Skip to content

Commit ca53010

Browse files
author
Justin McPherson
committed
Demo Spectrum wav data size is not calculated correctly
- Grab length of audio data from Data chunk size - Read from the device no greater than the audio Data chunk size Task-number: QTBUG-13779 Reviewed-by: Andrew den Exter
1 parent 8f11438 commit ca53010

File tree

2 files changed

+90
-79
lines changed

2 files changed

+90
-79
lines changed

demos/spectrum/app/wavfile.cpp

Lines changed: 89 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -76,80 +76,84 @@ struct CombinedHeader
7676
{
7777
RIFFHeader riff;
7878
WAVEHeader wave;
79-
DATAHeader data;
8079
};
8180

82-
static const int HeaderLength = sizeof(CombinedHeader);
8381

8482

8583
WavFile::WavFile(const QAudioFormat &format, qint64 dataLength)
86-
: m_format(format)
87-
, m_dataLength(dataLength)
84+
: m_format(format)
85+
, m_dataLength(dataLength)
86+
, m_dataPosition(0)
8887
{
89-
9088
}
9189

9290
bool WavFile::readHeader(QIODevice &device)
9391
{
94-
bool result = true;
95-
96-
if (!device.isSequential())
97-
result = device.seek(0);
98-
// else, assume that current position is the start of the header
99-
100-
if (result) {
101-
CombinedHeader header;
102-
result = (device.read(reinterpret_cast<char *>(&header), HeaderLength) == HeaderLength);
103-
if (result) {
104-
if ((memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0
105-
|| memcmp(&header.riff.descriptor.id, "RIFX", 4) == 0)
106-
&& memcmp(&header.riff.type, "WAVE", 4) == 0
107-
&& memcmp(&header.wave.descriptor.id, "fmt ", 4) == 0
108-
&& header.wave.audioFormat == 1 // PCM
109-
) {
110-
if (memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0)
111-
m_format.setByteOrder(QAudioFormat::LittleEndian);
112-
else
113-
m_format.setByteOrder(QAudioFormat::BigEndian);
114-
115-
m_format.setChannels(qFromLittleEndian<quint16>(header.wave.numChannels));
116-
m_format.setCodec("audio/pcm");
117-
m_format.setFrequency(qFromLittleEndian<quint32>(header.wave.sampleRate));
118-
m_format.setSampleSize(qFromLittleEndian<quint16>(header.wave.bitsPerSample));
119-
120-
switch(header.wave.bitsPerSample) {
121-
case 8:
122-
m_format.setSampleType(QAudioFormat::UnSignedInt);
123-
break;
124-
case 16:
125-
m_format.setSampleType(QAudioFormat::SignedInt);
126-
break;
127-
default:
128-
result = false;
129-
}
130-
131-
m_dataLength = device.size() - HeaderLength;
132-
} else {
133-
result = false;
134-
}
92+
if (!device.isSequential()) {
93+
if (!device.seek(0))
94+
return false;
95+
// XXX: else, assume that current position is the start of the header
96+
}
97+
98+
CombinedHeader header;
99+
if (device.read(reinterpret_cast<char *>(&header), sizeof(CombinedHeader)) != sizeof(CombinedHeader))
100+
return false;
101+
102+
if ((memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0
103+
|| memcmp(&header.riff.descriptor.id, "RIFX", 4) == 0)
104+
&& memcmp(&header.riff.type, "WAVE", 4) == 0
105+
&& memcmp(&header.wave.descriptor.id, "fmt ", 4) == 0
106+
&& (header.wave.audioFormat == 1 || header.wave.audioFormat == 0)) {
107+
108+
// Read off remaining header information
109+
DATAHeader dataHeader;
110+
111+
if (qFromLittleEndian<quint32>(header.wave.descriptor.size) > sizeof(WAVEHeader)) {
112+
// Extended data available
113+
quint16 extraFormatBytes;
114+
if (device.peek((char*)&extraFormatBytes, sizeof(quint16)) != sizeof(quint16))
115+
return false;
116+
const qint64 throwAwayBytes = sizeof(quint16) + qFromLittleEndian<quint16>(extraFormatBytes);
117+
if (device.read(throwAwayBytes).size() != throwAwayBytes)
118+
return false;
135119
}
120+
121+
if (device.read((char*)&dataHeader, sizeof(DATAHeader)) != sizeof(DATAHeader))
122+
return false;
123+
124+
// Establish format
125+
if (memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0)
126+
m_format.setByteOrder(QAudioFormat::LittleEndian);
127+
else
128+
m_format.setByteOrder(QAudioFormat::BigEndian);
129+
130+
int bps = qFromLittleEndian<quint16>(header.wave.bitsPerSample);
131+
m_format.setChannels(qFromLittleEndian<quint16>(header.wave.numChannels));
132+
m_format.setCodec("audio/pcm");
133+
m_format.setFrequency(qFromLittleEndian<quint32>(header.wave.sampleRate));
134+
m_format.setSampleSize(qFromLittleEndian<quint16>(header.wave.bitsPerSample));
135+
m_format.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
136+
137+
m_dataLength = qFromLittleEndian<quint32>(dataHeader.descriptor.size);
138+
m_dataPosition = 0;
136139
}
137140

138-
return result;
141+
return true;
139142
}
140143

141144
bool WavFile::writeHeader(QIODevice &device)
142145
{
143146
CombinedHeader header;
147+
DATAHeader dataHeader;
144148

145-
memset(&header, 0, HeaderLength);
149+
memset(&header, 0, sizeof(CombinedHeader));
146150

147151
// RIFF header
148152
if (m_format.byteOrder() == QAudioFormat::LittleEndian)
149153
strncpy(&header.riff.descriptor.id[0], "RIFF", 4);
150154
else
151155
strncpy(&header.riff.descriptor.id[0], "RIFX", 4);
152-
qToLittleEndian<quint32>(quint32(m_dataLength + HeaderLength - 8),
156+
qToLittleEndian<quint32>(quint32(m_dataLength + sizeof(CombinedHeader) + sizeof(DATAHeader) - sizeof(chunk)),
153157
reinterpret_cast<unsigned char*>(&header.riff.descriptor.size));
154158
strncpy(&header.riff.type[0], "WAVE", 4);
155159

@@ -171,11 +175,12 @@ bool WavFile::writeHeader(QIODevice &device)
171175
reinterpret_cast<unsigned char*>(&header.wave.bitsPerSample));
172176

173177
// DATA header
174-
strncpy(&header.data.descriptor.id[0], "data", 4);
178+
strncpy(dataHeader.descriptor.id, "data", 4);
175179
qToLittleEndian<quint32>(quint32(m_dataLength),
176-
reinterpret_cast<unsigned char*>(&header.data.descriptor.size));
180+
reinterpret_cast<unsigned char*>(&dataHeader.descriptor.size));
177181

178-
return (device.write(reinterpret_cast<const char *>(&header), HeaderLength) == HeaderLength);
182+
return device.write(reinterpret_cast<const char *>(&header), sizeof(CombinedHeader)) == sizeof(CombinedHeader)
183+
&& device.write(reinterpret_cast<const char*>(&dataHeader), sizeof(DATAHeader)) == sizeof(DATAHeader);
179184
}
180185

181186
const QAudioFormat& WavFile::format() const
@@ -190,7 +195,7 @@ qint64 WavFile::dataLength() const
190195

191196
qint64 WavFile::headerLength()
192197
{
193-
return HeaderLength;
198+
return sizeof(CombinedHeader);
194199
}
195200

196201
bool WavFile::writeDataLength(QIODevice &device, qint64 dataLength)
@@ -205,42 +210,47 @@ bool WavFile::writeDataLength(QIODevice &device, qint64 dataLength)
205210
return result;
206211
}
207212

208-
#include <QFile>
209-
#include <QTextStream>
210-
211213
qint64 WavFile::readData(QIODevice &device, QByteArray &buffer,
212214
QAudioFormat outputFormat)
213215
{
214-
if (QAudioFormat() == outputFormat)
216+
// Sanity checks
217+
if (!outputFormat.isValid())
215218
outputFormat = m_format;
216219

220+
if (!isPCMS16LE(outputFormat) || !isPCMS16LE(m_format))
221+
return 0;
222+
223+
if (m_dataPosition == m_dataLength)
224+
return 0;
225+
226+
// Process
217227
qint64 result = 0;
218228

219-
QFile file("wav.txt");
220-
file.open(QIODevice::WriteOnly | QIODevice::Text);
221-
QTextStream stream;
222-
stream.setDevice(&file);
223-
224-
if (isPCMS16LE(outputFormat) && isPCMS16LE(m_format)) {
225-
QVector<char> inputSample(2 * m_format.channels());
226-
227-
qint16 *output = reinterpret_cast<qint16*>(buffer.data());
228-
229-
while (result < buffer.size()) {
230-
if (device.read(inputSample.data(), inputSample.count())) {
231-
int inputIdx = 0;
232-
for (int outputIdx = 0; outputIdx < outputFormat.channels(); ++outputIdx) {
233-
const qint16* input = reinterpret_cast<const qint16*>(inputSample.data() + 2 * inputIdx);
234-
*output++ = qFromLittleEndian<qint16>(*input);
235-
result += 2;
236-
if (inputIdx < m_format.channels())
237-
++inputIdx;
238-
}
239-
} else {
240-
break;
229+
const int frameSize = 2 * m_format.channels(); // 16 bit samples
230+
QVector<char> inputSample(frameSize);
231+
232+
qint16 *output = reinterpret_cast<qint16*>(buffer.data());
233+
234+
while (result < buffer.size()) {
235+
if (m_dataPosition == m_dataLength)
236+
break;
237+
238+
// XXX only working with particular alignments
239+
if (device.read(inputSample.data(), inputSample.count())) {
240+
int inputIdx = 0;
241+
for (int outputIdx = 0; outputIdx < outputFormat.channels(); ++outputIdx) {
242+
const qint16* input = reinterpret_cast<const qint16*>(inputSample.data() + 2 * inputIdx);
243+
*output++ = qFromLittleEndian<qint16>(*input);
244+
result += 2;
245+
if (inputIdx < m_format.channels())
246+
++inputIdx;
241247
}
248+
m_dataPosition += frameSize;
249+
} else {
250+
break;
242251
}
243252
}
253+
244254
return result;
245255
}
246256

demos/spectrum/app/wavfile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class WavFile
7777
private:
7878
QAudioFormat m_format;
7979
qint64 m_dataLength;
80+
qint64 m_dataPosition;
8081
};
8182

8283
#endif

0 commit comments

Comments
 (0)