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