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