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