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