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