]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/mmedia/sndwav.cpp
corrected version number extraction
[wxWidgets.git] / contrib / src / mmedia / sndwav.cpp
CommitLineData
e8482f24
GL
1// --------------------------------------------------------------------------
2// Name: sndwav.cpp
3// Purpose:
4// Date: 08/11/1999
5// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
6// CVSID: $Id$
58b9c9ba 7// wxWindows licence
e8482f24
GL
8// --------------------------------------------------------------------------
9#ifdef __GNUG__
10#pragma implementation "sndwav.cpp"
11#endif
12
92a19c2e 13#include "wx/wxprec.h"
e8482f24
GL
14
15#ifndef WX_PRECOMP
16 #include "wx/defs.h"
17#endif
18
19#ifdef __BORLANDC__
20 #pragma hdrstop
21#endif
22
23#include "wx/stream.h"
24#include "wx/datstrm.h"
25#include "wx/filefn.h"
26#include "wx/mstream.h"
27
28#include "wx/mmedia/sndbase.h"
29#include "wx/mmedia/sndcodec.h"
30#include "wx/mmedia/sndfile.h"
31#include "wx/mmedia/sndpcm.h"
32#include "wx/mmedia/sndg72x.h"
c42b1de6 33#include "wx/mmedia/sndmsad.h"
e8482f24
GL
34#include "wx/mmedia/sndwav.h"
35
36#define BUILD_SIGNATURE(a,b,c,d) (((wxUint32)a) | (((wxUint32)b) << 8) | (((wxUint32)c) << 16) | (((wxUint32)d) << 24))
37
38#define RIFF_SIGNATURE BUILD_SIGNATURE('R','I','F','F')
39#define WAVE_SIGNATURE BUILD_SIGNATURE('W','A','V','E')
40#define FMT_SIGNATURE BUILD_SIGNATURE('f','m','t',' ')
41#define DATA_SIGNATURE BUILD_SIGNATURE('d','a','t','a')
42
43#define HEADER_SIZE 4+4 + 4+4+16 + 4+4
44// 4+4 => NAME + LEN
45// 16 => fmt size
46
47wxSoundWave::wxSoundWave(wxInputStream& stream, wxSoundStream& io_sound)
48 : wxSoundFileStream(stream, io_sound)
49{
50 m_base_offset = wxInvalidOffset;
51}
52
53wxSoundWave::wxSoundWave(wxOutputStream& stream, wxSoundStream& io_sound)
54 : wxSoundFileStream(stream, io_sound)
55{
56 m_base_offset = wxInvalidOffset;
57}
58
59wxSoundWave::~wxSoundWave()
60{
61}
62
63wxString wxSoundWave::GetCodecName() const
64{
65 return wxString(wxT("wxSoundWave codec"));
66}
67
dea7e44a 68#define FAIL_WITH(condition, err) if (condition) { m_snderror = err; return false; }
e8482f24
GL
69
70bool wxSoundWave::CanRead()
71{
72 wxUint32 len, signature1, signature2;
73 m_snderror = wxSOUND_NOERROR;
74
75 // Test the main signatures:
76 // "RIFF"
77 FAIL_WITH(m_input->Read(&signature1, 4).LastRead() != 4, wxSOUND_INVSTRM);
78
79 if (wxUINT32_SWAP_ON_BE(signature1) != RIFF_SIGNATURE) {
80 m_input->Ungetch(&signature1, 4);
dea7e44a 81 return false;
e8482f24
GL
82 }
83
84 // Pass the global length
85 m_input->Read(&len, 4);
86 FAIL_WITH(m_input->LastRead() != 4, wxSOUND_INVSTRM);
87
88 // Get the second signature
89 FAIL_WITH(m_input->Read(&signature2, 4).LastRead() != 4, wxSOUND_INVSTRM);
90 // Ungetch all
91 m_input->Ungetch(&signature2, 4);
92 m_input->Ungetch(&len, 4);
93 m_input->Ungetch(&signature1, 4);
94
95 // Test the second signature
96 if (wxUINT32_SWAP_ON_BE(signature2) != WAVE_SIGNATURE)
dea7e44a 97 return false;
e8482f24 98
dea7e44a 99 return true;
e8482f24
GL
100}
101
42c37dec 102bool wxSoundWave::HandleOutputPCM(wxDataInputStream& WXUNUSED(data), wxUint32 len,
c42b1de6 103 wxUint16 channels,
42c37dec
VS
104 wxUint32 sample_fq, wxUint32 WXUNUSED(byte_p_sec),
105 wxUint16 WXUNUSED(byte_p_spl), wxUint16 bits_p_spl)
e8482f24
GL
106{
107 wxSoundFormatPcm sndformat;
108
109 sndformat.SetSampleRate(sample_fq);
110 sndformat.SetBPS(bits_p_spl);
111 sndformat.SetChannels(channels);
dea7e44a 112 sndformat.Signed(true);
e8482f24
GL
113 sndformat.SetOrder(wxLITTLE_ENDIAN);
114
115 if (!SetSoundFormat(sndformat))
dea7e44a 116 return false;
e8482f24 117
c42b1de6
GL
118 m_input->SeekI(len, wxFromCurrent);
119
dea7e44a 120 return true;
e8482f24
GL
121}
122
c42b1de6
GL
123bool wxSoundWave::HandleOutputMSADPCM(wxDataInputStream& data, wxUint32 len,
124 wxUint16 channels,
42c37dec
VS
125 wxUint32 sample_fq, wxUint32 WXUNUSED(byte_p_sec),
126 wxUint16 WXUNUSED(byte_p_spl), wxUint16 WXUNUSED(bits_p_spl))
c42b1de6
GL
127{
128 wxSoundFormatMSAdpcm sndformat;
129 wxInt16 *coefs[2];
130 wxUint16 coefs_len, i;
131 wxUint16 block_size;
132
133 sndformat.SetSampleRate(sample_fq);
134 sndformat.SetChannels(channels);
135
136 block_size = data.Read16();
137 coefs_len = data.Read16();
138
139 coefs[0] = new wxInt16[coefs_len];
140 coefs[1] = new wxInt16[coefs_len];
141
142 for (i=0;i<coefs_len;i++) {
143 coefs[0][i] = data.Read16();
144 coefs[1][i] = data.Read16();
145 }
146
147 sndformat.SetCoefs(coefs, 2, coefs_len);
148 sndformat.SetBlockSize(block_size);
149
150 delete[] coefs[0];
151 delete[] coefs[1];
152
153 if (!SetSoundFormat(sndformat))
dea7e44a 154 return false;
c42b1de6
GL
155
156 len -= coefs_len*4 + 4;
157
158 m_input->SeekI(len, wxFromCurrent);
159
dea7e44a 160 return true;
c42b1de6
GL
161}
162
42c37dec
VS
163bool wxSoundWave::HandleOutputG721(wxDataInputStream& WXUNUSED(data), wxUint32 len,
164 wxUint16 WXUNUSED(channels),
165 wxUint32 sample_fq, wxUint32 WXUNUSED(byte_p_sec),
166 wxUint16 WXUNUSED(byte_p_spl), wxUint16 WXUNUSED(bits_p_spl))
e8482f24
GL
167{
168 wxSoundFormatG72X sndformat;
169
170 sndformat.SetSampleRate(sample_fq);
171 sndformat.SetG72XType(wxSOUND_G721);
172
173 if (!SetSoundFormat(sndformat))
dea7e44a 174 return false;
e8482f24 175
c42b1de6
GL
176 m_input->SeekI(len, wxFromCurrent);
177
dea7e44a 178 return true;
e8482f24
GL
179}
180
181bool wxSoundWave::PrepareToPlay()
182{
183 wxUint32 signature, len;
184 bool end_headers;
185
186 if (!m_input) {
187 m_snderror = wxSOUND_INVSTRM;
dea7e44a 188 return false;
e8482f24
GL
189 }
190
191 wxDataInputStream data(*m_input);
dea7e44a 192 data.BigEndianOrdered(false);
e8482f24
GL
193
194 // Get the first signature
195 FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM);
196 FAIL_WITH(wxUINT32_SWAP_ON_BE(signature) != RIFF_SIGNATURE, wxSOUND_INVSTRM);
197 // "RIFF"
198
199 len = data.Read32();
2b3644c7 200 wxUnusedVar(len);
e8482f24
GL
201 FAIL_WITH(m_input->LastRead() != 4, wxSOUND_INVSTRM);
202 // dummy len
203
204 // Get the second signature
205 FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM);
206 FAIL_WITH(wxUINT32_SWAP_ON_BE(signature) != WAVE_SIGNATURE, wxSOUND_INVSTRM);
207 // "WAVE"
208
dea7e44a 209 end_headers = false;
e8482f24
GL
210 // Chunk loop
211 while (!end_headers) {
212 FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM);
213
214 len = data.Read32();
215 FAIL_WITH(m_input->LastRead() != 4, wxSOUND_INVSTRM);
216
217 switch (wxUINT32_SWAP_ON_BE(signature)) {
218 case FMT_SIGNATURE: { // "fmt "
219 wxUint16 format, channels, byte_p_spl, bits_p_spl;
220 wxUint32 sample_fq, byte_p_sec;
221
222 // Get the common parameters
223 data >> format >> channels >> sample_fq
224 >> byte_p_sec >> byte_p_spl >> bits_p_spl;
c42b1de6 225 len -= 16;
e8482f24
GL
226
227 switch (format) {
228 case 0x01: // PCM
c42b1de6
GL
229 if (!HandleOutputPCM(data, len, channels, sample_fq,
230 byte_p_sec, byte_p_spl,
231 bits_p_spl))
dea7e44a 232 return false;
c42b1de6
GL
233 break;
234 case 0x02: // MS ADPCM
235 if (!HandleOutputMSADPCM(data, len,
236 channels, sample_fq,
237 byte_p_sec, byte_p_spl,
238 bits_p_spl))
dea7e44a 239 return false;
e8482f24
GL
240 break;
241 case 0x40: // G721
c42b1de6
GL
242 if (!HandleOutputG721(data, len,
243 channels, sample_fq,
244 byte_p_sec, byte_p_spl,
245 bits_p_spl))
dea7e44a 246 return false;
e8482f24
GL
247 break;
248 default:
249 m_snderror = wxSOUND_NOCODEC;
dea7e44a 250 return false;
e8482f24
GL
251 }
252 break;
253 }
254 case DATA_SIGNATURE: // "data"
255 m_base_offset = m_input->TellI();
dea7e44a 256 end_headers = true;
e8482f24
GL
257 FinishPreparation(len);
258 break;
259 default:
260 // We pass the chunk
261 m_input->SeekI(len, wxFromCurrent);
262 break;
263 }
264 }
dea7e44a 265 return true;
e8482f24
GL
266}
267
268wxSoundFormatBase *wxSoundWave::HandleInputPCM(wxDataOutputStream& data)
269{
270 wxUint16 format, channels, byte_p_spl, bits_p_spl;
271 wxUint32 sample_fq, byte_p_sec;
272 wxSoundFormatPcm *pcm;
273
274 pcm = (wxSoundFormatPcm *)(m_sndformat->Clone());
275
276 // Write block length
277 data.Write32(16);
278
279 sample_fq = pcm->GetSampleRate();
280 bits_p_spl = pcm->GetBPS();
281 channels = pcm->GetChannels();
282 byte_p_spl = pcm->GetBPS() / 8;
283 byte_p_sec = pcm->GetBytesFromTime(1);
284 format = 0x01;
285
dea7e44a 286 pcm->Signed(true);
e8482f24
GL
287 pcm->SetOrder(wxLITTLE_ENDIAN);
288
289 data << format << channels << sample_fq
290 << byte_p_sec << byte_p_spl << bits_p_spl;
291
292 return pcm;
293}
294
295wxSoundFormatBase *wxSoundWave::HandleInputG72X(wxDataOutputStream& data)
296{
297 wxUint16 format, channels, byte_p_spl, bits_p_spl;
298 wxUint32 sample_fq, byte_p_sec;
299 wxSoundFormatG72X *g72x;
300
301 // Write block length
302 data.Write32(16);
303
304 g72x = (wxSoundFormatG72X *)(m_sndformat->Clone());
305 if (g72x->GetG72XType() != wxSOUND_G721) {
306 delete g72x;
307 return NULL;
308 }
309
310 sample_fq = g72x->GetSampleRate();
311 bits_p_spl = 4;
312 channels = 1;
313 byte_p_spl = 0;
314 byte_p_sec = g72x->GetBytesFromTime(1);
315 format = 0x40;
316 data << format << channels << sample_fq
317 << byte_p_sec << byte_p_spl << bits_p_spl;
318
319 return g72x;
320}
321
322bool wxSoundWave::PrepareToRecord(wxUint32 time)
323{
324#define WRITE_SIGNATURE(s,sig) \
325signature = sig; \
326signature = wxUINT32_SWAP_ON_BE(signature); \
327FAIL_WITH(s->Write(&signature, 4).LastWrite() != 4, wxSOUND_INVSTRM);
328
329 wxUint32 signature;
330 wxMemoryOutputStream fmt_data;
331
332 if (!m_output) {
333 m_snderror = wxSOUND_INVSTRM;
dea7e44a 334 return false;
e8482f24
GL
335 }
336
337 wxDataOutputStream data(*m_output);
338 wxDataOutputStream fmt_d_data(fmt_data);
339
dea7e44a
WS
340 data.BigEndianOrdered(false);
341 fmt_d_data.BigEndianOrdered(false);
e8482f24
GL
342
343 WRITE_SIGNATURE(m_output, RIFF_SIGNATURE);
344
345 FAIL_WITH(m_output->LastWrite() != 4, wxSOUND_INVSTRM);
346
347 WRITE_SIGNATURE((&fmt_data), WAVE_SIGNATURE);
348
349 {
350 wxSoundFormatBase *frmt;
351
352 WRITE_SIGNATURE((&fmt_data), FMT_SIGNATURE);
353
354 switch (m_sndformat->GetType()) {
355 case wxSOUND_PCM:
356 frmt = HandleInputPCM(fmt_d_data);
357 break;
358 case wxSOUND_G72X:
359 frmt = HandleInputG72X(fmt_d_data);
360 break;
361 default:
362 m_snderror = wxSOUND_NOCODEC;
dea7e44a 363 return false;
e8482f24
GL
364 }
365
366 FAIL_WITH(!frmt, wxSOUND_NOCODEC);
367
368 if (!SetSoundFormat(*frmt)) {
369 delete frmt;
dea7e44a 370 return false;
e8482f24
GL
371 }
372
373 delete frmt;
374 }
375
60c474a0 376 data << (wxUint32)(fmt_data.GetSize() + m_sndformat->GetBytesFromTime(time));
e8482f24
GL
377
378 // We, finally, copy the header block to the output stream
379 {
380 char *out_buf;
381 out_buf = new char[fmt_data.GetSize()];
382
383 fmt_data.CopyTo(out_buf, fmt_data.GetSize());
384 m_output->Write(out_buf, fmt_data.GetSize());
385
386 delete[] out_buf;
387 }
388
389 WRITE_SIGNATURE(m_output, DATA_SIGNATURE);
390 data.Write32(m_sndformat->GetBytesFromTime(time));
dea7e44a 391 return true;
e8482f24
GL
392}
393
394bool wxSoundWave::FinishRecording()
395{
396 if (m_output->SeekO(0, wxFromStart) == wxInvalidOffset)
397 // We can't but there is no error.
dea7e44a 398 return true;
e8482f24
GL
399
400 if (m_bytes_left == 0)
dea7e44a 401 return true;
e8482f24
GL
402
403 // TODO: Update headers when we stop before the specified time (if possible)
dea7e44a 404 return true;
e8482f24
GL
405}
406
42c37dec 407bool wxSoundWave::RepositionStream(wxUint32 WXUNUSED(position))
e8482f24
GL
408{
409 if (m_base_offset == wxInvalidOffset)
dea7e44a 410 return false;
e8482f24 411 m_input->SeekI(m_base_offset, wxFromStart);
dea7e44a 412 return true;
e8482f24
GL
413}
414
415wxUint32 wxSoundWave::GetData(void *buffer, wxUint32 len)
416{
417 return m_input->Read(buffer, len).LastRead();
418}
419
420wxUint32 wxSoundWave::PutData(const void *buffer, wxUint32 len)
421{
422 return m_output->Write(buffer, len).LastWrite();
423}