]> git.saurik.com Git - wxWidgets.git/blame_incremental - contrib/src/mmedia/sndmsad.cpp
added new files (after library split)
[wxWidgets.git] / contrib / src / mmedia / sndmsad.cpp
... / ...
CommitLineData
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__
9#pragma implementation "sndmsad.cpp"
10#endif
11
12#include "wx/wxprec.h"
13
14#ifndef WX_PRECOMP
15 #include "wx/defs.h"
16 #include "wx/memory.h"
17 #include "wx/log.h"
18#endif
19
20#include "wx/mmedia/sndbase.h"
21#include "wx/mmedia/sndfile.h"
22#include "wx/mmedia/sndpcm.h"
23#include "wx/mmedia/sndmsad.h"
24
25// --------------------------------------------------------------------------
26// wxSoundFormatMSAdpcm
27// --------------------------------------------------------------------------
28
29wxSoundFormatMSAdpcm::wxSoundFormatMSAdpcm()
30 : m_srate(22050)
31{
32 m_ncoefs = 0;
33 m_coefs_len = 0;
34 m_coefs = NULL;
35}
36
37wxSoundFormatMSAdpcm::~wxSoundFormatMSAdpcm()
38{
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
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
59void wxSoundFormatMSAdpcm::SetChannels(wxUint16 nchannels)
60{
61 m_nchannels = nchannels;
62}
63
64wxUint16 wxSoundFormatMSAdpcm::GetChannels() const
65{
66 return m_nchannels;
67}
68
69void wxSoundFormatMSAdpcm::SetCoefs(wxInt16 **coefs, wxUint16 ncoefs,
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
80 m_coefs = new wxInt16 *[ncoefs];
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
107wxSoundFormatBase *wxSoundFormatMSAdpcm::Clone() const
108{
109 wxSoundFormatMSAdpcm *adpcm = new wxSoundFormatMSAdpcm();
110
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;
115 return adpcm;
116}
117
118wxUint32 wxSoundFormatMSAdpcm::GetTimeFromBytes(wxUint32 bytes) const
119{
120 return 2 * bytes / (m_nchannels * m_srate);
121}
122
123wxUint32 wxSoundFormatMSAdpcm::GetBytesFromTime(wxUint32 time) const
124{
125 return time * m_nchannels * m_srate / 2;
126}
127
128bool wxSoundFormatMSAdpcm::operator !=(const wxSoundFormatBase& frmt2) const
129{
130 const wxSoundFormatMSAdpcm *adpcm = (const wxSoundFormatMSAdpcm *)&frmt2;
131
132 if (frmt2.GetType() != wxSOUND_MSADPCM)
133 return TRUE;
134
135 return (adpcm->m_srate != m_srate) && (adpcm->m_nchannels != m_nchannels);
136}
137
138// --------------------------------------------------------------------------
139// wxSoundStreamMSAdpcm
140// --------------------------------------------------------------------------
141wxSoundStreamMSAdpcm::wxSoundStreamMSAdpcm(wxSoundStream& sndio)
142 : wxSoundStreamCodec(sndio)
143{
144 // PCM converter
145 m_router = new wxSoundRouterStream(sndio);
146 m_got_header = FALSE;
147 m_stereo = FALSE;
148}
149
150wxSoundStreamMSAdpcm::~wxSoundStreamMSAdpcm()
151{
152 delete m_router;
153}
154
155wxSoundStream& wxSoundStreamMSAdpcm::Read(void *buffer, wxUint32 len)
156{
157 m_snderror = wxSOUND_NOCODEC;
158 m_lastcount = 0;
159 return *this;
160}
161
162static wxInt16 gl_ADPCMcoeff_delta[] = {
163 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307,
164 230, 230, 230
165};
166
167wxUint32 wxSoundStreamMSAdpcm::DecodeMonoADPCM(const void *in_buffer,
168 void *out_buffer,
169 wxUint32 in_len)
170{
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 }
216 }
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;
232
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);
250
251 GET_DATA_16(state0->samp1);
252 GET_DATA_16(state1->samp1);
253 GET_DATA_16(state0->samp2);
254 GET_DATA_16(state1->samp2);
255
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
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{
355 if (format.GetType() != wxSOUND_MSADPCM) {
356 m_snderror = wxSOUND_INVFRMT;
357 return FALSE;
358 }
359
360 wxSoundFormatPcm pcm;
361 wxSoundFormatMSAdpcm *adpcm;
362 wxUint16 ncoefs, coefs_len;
363
364 wxSoundStreamCodec::SetSoundFormat(format);
365
366 adpcm = (wxSoundFormatMSAdpcm *)m_sndformat;
367
368 adpcm->GetCoefs(m_coefs, ncoefs, coefs_len);
369
370 if (!ncoefs) {
371 wxLogError(__FILE__ ":%d: Number of ADPCM coefficients"
372 " must be non null", __LINE__);
373 return FALSE;
374 }
375
376 pcm.SetSampleRate(adpcm->GetSampleRate());
377 pcm.SetBPS(16);
378 pcm.SetChannels(adpcm->GetChannels());
379 pcm.Signed(TRUE);
380 pcm.SetOrder(wxBYTE_ORDER);
381
382 m_stereo = (adpcm->GetChannels() == 2);
383 m_block_size = adpcm->GetBlockSize();
384 m_next_block = 0;
385
386 m_router->SetSoundFormat(pcm);
387
388 return TRUE;
389}
390