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