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