]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/mmedia/sndmsad.cpp
fix evaluation order bug (patch 1158099)
[wxWidgets.git] / contrib / src / mmedia / sndmsad.cpp
CommitLineData
e8482f24
GL
1// --------------------------------------------------------------------------
2// Name: sndulaw.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
GL
8// --------------------------------------------------------------------------
9#ifdef __GNUG__
c42b1de6 10#pragma implementation "sndmsad.cpp"
e8482f24
GL
11#endif
12
92a19c2e 13#include "wx/wxprec.h"
c42b1de6
GL
14
15#ifndef WX_PRECOMP
16 #include "wx/defs.h"
17 #include "wx/memory.h"
18 #include "wx/log.h"
19#endif
20
59917a74
JS
21#include "wx/mmedia/sndbase.h"
22#include "wx/mmedia/sndfile.h"
23#include "wx/mmedia/sndpcm.h"
24#include "wx/mmedia/sndmsad.h"
e8482f24
GL
25
26// --------------------------------------------------------------------------
27// wxSoundFormatMSAdpcm
28// --------------------------------------------------------------------------
29
30wxSoundFormatMSAdpcm::wxSoundFormatMSAdpcm()
31 : m_srate(22050)
32{
c42b1de6
GL
33 m_ncoefs = 0;
34 m_coefs_len = 0;
35 m_coefs = NULL;
e8482f24
GL
36}
37
38wxSoundFormatMSAdpcm::~wxSoundFormatMSAdpcm()
39{
c42b1de6
GL
40 if (m_ncoefs) {
41 wxUint16 i;
42
43 for (i=0;i<m_ncoefs;i++)
44 delete[] m_coefs[i];
45 delete[] m_coefs;
46 }
47
e8482f24
GL
48}
49
50void wxSoundFormatMSAdpcm::SetSampleRate(wxUint32 srate)
51{
52 m_srate = srate;
53}
54
55wxUint32 wxSoundFormatMSAdpcm::GetSampleRate() const
56{
57 return m_srate;
58}
59
c42b1de6
GL
60void wxSoundFormatMSAdpcm::SetChannels(wxUint16 nchannels)
61{
62 m_nchannels = nchannels;
63}
64
65wxUint16 wxSoundFormatMSAdpcm::GetChannels() const
66{
67 return m_nchannels;
68}
69
42c37dec 70void wxSoundFormatMSAdpcm::SetCoefs(wxInt16 **WXUNUSED(coefs), wxUint16 ncoefs,
c42b1de6
GL
71 wxUint16 coefs_len)
72{
73 wxUint16 i;
74
75 if (m_ncoefs) {
76 for (i=0;i<m_ncoefs;i++)
77 delete[] (m_coefs[i]);
78 delete[] m_coefs;
79 }
80 // TODO: Add some memory checking here
b97a1a73 81 m_coefs = new wxInt16 *[ncoefs];
c42b1de6
GL
82
83 for (i=0;i<ncoefs;i++)
84 m_coefs[i] = new wxInt16[coefs_len];
85
86 m_ncoefs = ncoefs;
87 m_coefs_len = coefs_len;
88}
89
90void wxSoundFormatMSAdpcm::GetCoefs(wxInt16 **& coefs, wxUint16& ncoefs,
91 wxUint16& coefs_len) const
92{
93 coefs = m_coefs;
94 ncoefs = m_ncoefs;
95 coefs_len = m_coefs_len;
96}
97
98void wxSoundFormatMSAdpcm::SetBlockSize(wxUint16 block_size)
99{
100 m_block_size = block_size;
101}
102
103wxUint16 wxSoundFormatMSAdpcm::GetBlockSize() const
104{
105 return m_block_size;
106}
107
e8482f24
GL
108wxSoundFormatBase *wxSoundFormatMSAdpcm::Clone() const
109{
110 wxSoundFormatMSAdpcm *adpcm = new wxSoundFormatMSAdpcm();
111
c42b1de6
GL
112 adpcm->m_srate = m_srate;
113 adpcm->SetCoefs(m_coefs, m_ncoefs, m_coefs_len);
114 adpcm->m_nchannels = m_nchannels;
115 adpcm->m_block_size = m_block_size;
e8482f24
GL
116 return adpcm;
117}
118
119wxUint32 wxSoundFormatMSAdpcm::GetTimeFromBytes(wxUint32 bytes) const
120{
c42b1de6 121 return 2 * bytes / (m_nchannels * m_srate);
e8482f24
GL
122}
123
124wxUint32 wxSoundFormatMSAdpcm::GetBytesFromTime(wxUint32 time) const
125{
c42b1de6 126 return time * m_nchannels * m_srate / 2;
e8482f24
GL
127}
128
129bool wxSoundFormatMSAdpcm::operator !=(const wxSoundFormatBase& frmt2) const
130{
c42b1de6 131 const wxSoundFormatMSAdpcm *adpcm = (const wxSoundFormatMSAdpcm *)&frmt2;
e8482f24
GL
132
133 if (frmt2.GetType() != wxSOUND_MSADPCM)
dea7e44a 134 return true;
e8482f24 135
c42b1de6 136 return (adpcm->m_srate != m_srate) && (adpcm->m_nchannels != m_nchannels);
e8482f24
GL
137}
138
139// --------------------------------------------------------------------------
140// wxSoundStreamMSAdpcm
141// --------------------------------------------------------------------------
142wxSoundStreamMSAdpcm::wxSoundStreamMSAdpcm(wxSoundStream& sndio)
143 : wxSoundStreamCodec(sndio)
144{
145 // PCM converter
146 m_router = new wxSoundRouterStream(sndio);
dea7e44a
WS
147 m_got_header = false;
148 m_stereo = false;
e8482f24
GL
149}
150
151wxSoundStreamMSAdpcm::~wxSoundStreamMSAdpcm()
152{
153 delete m_router;
154}
155
42c37dec 156wxSoundStream& wxSoundStreamMSAdpcm::Read(void *WXUNUSED(buffer), wxUint32 WXUNUSED(len))
e8482f24
GL
157{
158 m_snderror = wxSOUND_NOCODEC;
159 m_lastcount = 0;
160 return *this;
161}
162
163static wxInt16 gl_ADPCMcoeff_delta[] = {
c42b1de6
GL
164 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307,
165 230, 230, 230
e8482f24
GL
166};
167
c42b1de6
GL
168wxUint32 wxSoundStreamMSAdpcm::DecodeMonoADPCM(const void *in_buffer,
169 void *out_buffer,
170 wxUint32 in_len)
e8482f24 171{
c42b1de6
GL
172 wxUint8 *ADPCMdata;
173 wxInt16 *PCMdata;
174 AdpcmState *state;
175 wxUint32 out_len;
176
177 ADPCMdata = (wxUint8 *)in_buffer;
178 PCMdata = (wxInt16 *)out_buffer;
179 state = &m_state[0];
180
181#define GET_DATA_16(i) i = *ADPCMdata++, i |= ((wxUint32)(*ADPCMdata++) << 8)
182#define GET_DATA_8(i) i = (*ADPCMdata++)
183
184 out_len = 0;
185 while (in_len != 0) {
186 if (m_next_block == 0) {
187 GET_DATA_8(state->predictor);
188 GET_DATA_16(state->iDelta);
189
190 GET_DATA_16(state->samp1);
191 GET_DATA_16(state->samp2);
192
193 state->coeff[0] = state->coeff[1] = m_coefs[0][ state->predictor ];
194
195 *PCMdata++ = state->samp2;
196 *PCMdata++ = state->samp1;
197 in_len -= 7;
198 out_len += 4;
199 m_next_block = m_block_size;
200 continue;
201 }
202
203 while (in_len != 0 && m_next_block != 0) {
204 wxUint8 nib[2];
205
206 GET_DATA_8(nib[0]);
207 nib[1] = (nib[0] >> 4) & 0x0f;
208 nib[0] &= 0x0f;
209
210 Nibble(nib[0], state, &PCMdata);
211 Nibble(nib[1], state, &PCMdata);
212
213 in_len -= 4;
214 out_len += 4;
215 m_next_block -= 4;
216 }
e8482f24 217 }
c42b1de6
GL
218
219 return out_len;
220
221#undef GET_DATA_16
222#undef GET_DATA_8
223}
224
225wxUint32 wxSoundStreamMSAdpcm::DecodeStereoADPCM(const void *in_buffer,
226 void *out_buffer,
227 wxUint32 in_len)
228{
229 wxUint8 *ADPCMdata;
230 wxInt16 *PCMdata;
231 AdpcmState *state0, *state1;
232 wxUint32 out_len;
e8482f24 233
c42b1de6
GL
234 ADPCMdata = (wxUint8 *)in_buffer;
235 PCMdata = (wxInt16 *)out_buffer;
236
237 state0 = &m_state[0];
238 state1 = &m_state[1];
239
240#define GET_DATA_16(i) i = *ADPCMdata++, i |= ((wxUint32)(*ADPCMdata++) << 8)
241#define GET_DATA_8(i) i = (*ADPCMdata++)
242
243 out_len = 0;
244 while (in_len != 0) {
245 if (!m_next_block) {
246 GET_DATA_8(state0->predictor);
247 GET_DATA_8(state1->predictor);
248
249 GET_DATA_16(state0->iDelta);
250 GET_DATA_16(state1->iDelta);
e8482f24 251
c42b1de6
GL
252 GET_DATA_16(state0->samp1);
253 GET_DATA_16(state1->samp1);
254 GET_DATA_16(state0->samp2);
255 GET_DATA_16(state1->samp2);
e8482f24 256
c42b1de6
GL
257 *PCMdata++ = state0->samp2;
258 *PCMdata++ = state1->samp2;
259 *PCMdata++ = state0->samp1;
260 *PCMdata++ = state1->samp1;
261
262 in_len -= 14;
263 out_len += 8;
264 m_next_block = m_block_size;
265 continue;
266 }
267
268 while (in_len != 0 && m_next_block > 0) {
269 wxUint8 nib[2];
270
271 GET_DATA_8(nib[0]);
272 nib[1] = (nib[0] >> 4) & 0x0f;
273 nib[0] &= 0x0f;
274
275 Nibble(nib[0], state0, &PCMdata);
276 Nibble(nib[1], state1, &PCMdata);
277
278 in_len -= 4;
279 out_len += 4;
280 m_next_block -= 4;
281 }
282 }
283
284 return out_len;
285
286#undef GET_DATA_16
287#undef GET_DATA_8
288}
289
290void wxSoundStreamMSAdpcm::Nibble(wxInt8 nyb,
291 AdpcmState *state,
292 wxInt16 **out_buffer)
293{
294 wxUint32 new_delta;
295 wxInt32 new_sample;
296
297 // First: compute the next delta value
298 new_delta = (state->iDelta * gl_ADPCMcoeff_delta[nyb]) >> 8;
299 // If null, minor it by 16
300 if (!new_delta)
301 new_delta = 16;
302
303 // Barycentre
304 new_sample = (state->samp1 * state->coeff[0] +
305 state->samp2 * state->coeff[1]) / 256;
306
307 // Regenerate the sign
308 if (nyb & 0x08)
309 nyb -= 0x10;
310
311 new_sample += state->iDelta * nyb;
312
313 // Samples must be in [-32767, 32768]
314 if (new_sample < -32768)
315 new_sample = -32768;
316 else if (new_sample > 32767)
317 new_sample = 32767;
318
319 state->iDelta = new_delta;
320 state->samp2 = state->samp1;
321 state->samp1 = new_sample;
322
323 *(*out_buffer)++ = new_sample;
324}
325
326wxSoundStream& wxSoundStreamMSAdpcm::Write(const void *buffer, wxUint32 len)
327{
328 wxUint8 *out_buf;
329 wxUint32 new_len;
330
331 // TODO: prealloc the output buffer
332 out_buf = new wxUint8[len*2];
333
334 if (!m_stereo)
335 new_len = DecodeMonoADPCM(buffer, out_buf, len);
336 else
337 new_len = DecodeStereoADPCM(buffer, out_buf, len);
338
339 m_router->Write(out_buf, new_len);
340
341 m_lastcount = len;
342 m_snderror = wxSOUND_NOERROR;
343
344 delete[] out_buf;
345
e8482f24
GL
346 return *this;
347}
348
349wxUint32 wxSoundStreamMSAdpcm::GetBestSize() const
350{
351 return m_sndio->GetBestSize() / 2;
352}
353
354bool wxSoundStreamMSAdpcm::SetSoundFormat(const wxSoundFormatBase& format)
355{
c42b1de6 356 if (format.GetType() != wxSOUND_MSADPCM) {
e8482f24 357 m_snderror = wxSOUND_INVFRMT;
dea7e44a 358 return false;
e8482f24
GL
359 }
360
361 wxSoundFormatPcm pcm;
c42b1de6
GL
362 wxSoundFormatMSAdpcm *adpcm;
363 wxUint16 ncoefs, coefs_len;
e8482f24
GL
364
365 wxSoundStreamCodec::SetSoundFormat(format);
366
c42b1de6
GL
367 adpcm = (wxSoundFormatMSAdpcm *)m_sndformat;
368
369 adpcm->GetCoefs(m_coefs, ncoefs, coefs_len);
370
371 if (!ncoefs) {
f815011f 372 wxLogError(wxT("Number of ADPCM coefficients must be non null"));
dea7e44a 373 return false;
c42b1de6 374 }
e8482f24
GL
375
376 pcm.SetSampleRate(adpcm->GetSampleRate());
377 pcm.SetBPS(16);
378 pcm.SetChannels(adpcm->GetChannels());
dea7e44a 379 pcm.Signed(true);
e8482f24 380 pcm.SetOrder(wxBYTE_ORDER);
c42b1de6
GL
381
382 m_stereo = (adpcm->GetChannels() == 2);
383 m_block_size = adpcm->GetBlockSize();
384 m_next_block = 0;
e8482f24
GL
385
386 m_router->SetSoundFormat(pcm);
387
dea7e44a 388 return true;
e8482f24
GL
389}
390