@@ -76,80 +76,84 @@ struct CombinedHeader
76
76
{
77
77
RIFFHeader riff;
78
78
WAVEHeader wave;
79
- DATAHeader data;
80
79
};
81
80
82
- static const int HeaderLength = sizeof (CombinedHeader);
83
81
84
82
85
83
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 )
88
87
{
89
-
90
88
}
91
89
92
90
bool WavFile::readHeader (QIODevice &device)
93
91
{
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 ;
135
119
}
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 ;
136
139
}
137
140
138
- return result ;
141
+ return true ;
139
142
}
140
143
141
144
bool WavFile::writeHeader (QIODevice &device)
142
145
{
143
146
CombinedHeader header;
147
+ DATAHeader dataHeader;
144
148
145
- memset (&header, 0 , HeaderLength );
149
+ memset (&header, 0 , sizeof (CombinedHeader) );
146
150
147
151
// RIFF header
148
152
if (m_format.byteOrder () == QAudioFormat::LittleEndian)
149
153
strncpy (&header.riff .descriptor .id [0 ], " RIFF" , 4 );
150
154
else
151
155
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) ),
153
157
reinterpret_cast <unsigned char *>(&header.riff .descriptor .size ));
154
158
strncpy (&header.riff .type [0 ], " WAVE" , 4 );
155
159
@@ -171,11 +175,12 @@ bool WavFile::writeHeader(QIODevice &device)
171
175
reinterpret_cast <unsigned char *>(&header.wave .bitsPerSample ));
172
176
173
177
// DATA header
174
- strncpy (&header. data . descriptor .id [ 0 ] , " data" , 4 );
178
+ strncpy (dataHeader. descriptor .id , " data" , 4 );
175
179
qToLittleEndian<quint32>(quint32 (m_dataLength),
176
- reinterpret_cast <unsigned char *>(&header. data .descriptor .size ));
180
+ reinterpret_cast <unsigned char *>(&dataHeader .descriptor .size ));
177
181
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);
179
184
}
180
185
181
186
const QAudioFormat& WavFile::format () const
@@ -190,7 +195,7 @@ qint64 WavFile::dataLength() const
190
195
191
196
qint64 WavFile::headerLength ()
192
197
{
193
- return HeaderLength ;
198
+ return sizeof (CombinedHeader) ;
194
199
}
195
200
196
201
bool WavFile::writeDataLength (QIODevice &device, qint64 dataLength)
@@ -205,42 +210,47 @@ bool WavFile::writeDataLength(QIODevice &device, qint64 dataLength)
205
210
return result;
206
211
}
207
212
208
- #include < QFile>
209
- #include < QTextStream>
210
-
211
213
qint64 WavFile::readData (QIODevice &device, QByteArray &buffer,
212
214
QAudioFormat outputFormat)
213
215
{
214
- if (QAudioFormat () == outputFormat)
216
+ // Sanity checks
217
+ if (!outputFormat.isValid ())
215
218
outputFormat = m_format;
216
219
220
+ if (!isPCMS16LE (outputFormat) || !isPCMS16LE (m_format))
221
+ return 0 ;
222
+
223
+ if (m_dataPosition == m_dataLength)
224
+ return 0 ;
225
+
226
+ // Process
217
227
qint64 result = 0 ;
218
228
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;
241
247
}
248
+ m_dataPosition += frameSize;
249
+ } else {
250
+ break ;
242
251
}
243
252
}
253
+
244
254
return result;
245
255
}
246
256
0 commit comments