]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/mmedia/sndmsad.cpp
GetBestFittingSize --> GetEffectiveMinSize
[wxWidgets.git] / contrib / src / mmedia / sndmsad.cpp
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 // wxWindows licence
8 // --------------------------------------------------------------------------
9
10 #include "wx/wxprec.h"
11
12 #ifndef WX_PRECOMP
13 #include "wx/defs.h"
14 #include "wx/memory.h"
15 #include "wx/log.h"
16 #endif
17
18 #include "wx/mmedia/sndbase.h"
19 #include "wx/mmedia/sndfile.h"
20 #include "wx/mmedia/sndpcm.h"
21 #include "wx/mmedia/sndmsad.h"
22
23 // --------------------------------------------------------------------------
24 // wxSoundFormatMSAdpcm
25 // --------------------------------------------------------------------------
26
27 wxSoundFormatMSAdpcm::wxSoundFormatMSAdpcm()
28 : m_srate(22050)
29 {
30 m_ncoefs = 0;
31 m_coefs_len = 0;
32 m_coefs = NULL;
33 }
34
35 wxSoundFormatMSAdpcm::~wxSoundFormatMSAdpcm()
36 {
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
45 }
46
47 void wxSoundFormatMSAdpcm::SetSampleRate(wxUint32 srate)
48 {
49 m_srate = srate;
50 }
51
52 wxUint32 wxSoundFormatMSAdpcm::GetSampleRate() const
53 {
54 return m_srate;
55 }
56
57 void wxSoundFormatMSAdpcm::SetChannels(wxUint16 nchannels)
58 {
59 m_nchannels = nchannels;
60 }
61
62 wxUint16 wxSoundFormatMSAdpcm::GetChannels() const
63 {
64 return m_nchannels;
65 }
66
67 void wxSoundFormatMSAdpcm::SetCoefs(wxInt16 **WXUNUSED(coefs), wxUint16 ncoefs,
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
78 m_coefs = new wxInt16 *[ncoefs];
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
87 void 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
95 void wxSoundFormatMSAdpcm::SetBlockSize(wxUint16 block_size)
96 {
97 m_block_size = block_size;
98 }
99
100 wxUint16 wxSoundFormatMSAdpcm::GetBlockSize() const
101 {
102 return m_block_size;
103 }
104
105 wxSoundFormatBase *wxSoundFormatMSAdpcm::Clone() const
106 {
107 wxSoundFormatMSAdpcm *adpcm = new wxSoundFormatMSAdpcm();
108
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;
113 return adpcm;
114 }
115
116 wxUint32 wxSoundFormatMSAdpcm::GetTimeFromBytes(wxUint32 bytes) const
117 {
118 return 2 * bytes / (m_nchannels * m_srate);
119 }
120
121 wxUint32 wxSoundFormatMSAdpcm::GetBytesFromTime(wxUint32 time) const
122 {
123 return time * m_nchannels * m_srate / 2;
124 }
125
126 bool wxSoundFormatMSAdpcm::operator !=(const wxSoundFormatBase& frmt2) const
127 {
128 const wxSoundFormatMSAdpcm *adpcm = (const wxSoundFormatMSAdpcm *)&frmt2;
129
130 if (frmt2.GetType() != wxSOUND_MSADPCM)
131 return true;
132
133 return (adpcm->m_srate != m_srate) && (adpcm->m_nchannels != m_nchannels);
134 }
135
136 // --------------------------------------------------------------------------
137 // wxSoundStreamMSAdpcm
138 // --------------------------------------------------------------------------
139 wxSoundStreamMSAdpcm::wxSoundStreamMSAdpcm(wxSoundStream& sndio)
140 : wxSoundStreamCodec(sndio)
141 {
142 // PCM converter
143 m_router = new wxSoundRouterStream(sndio);
144 m_got_header = false;
145 m_stereo = false;
146 }
147
148 wxSoundStreamMSAdpcm::~wxSoundStreamMSAdpcm()
149 {
150 delete m_router;
151 }
152
153 wxSoundStream& wxSoundStreamMSAdpcm::Read(void *WXUNUSED(buffer), wxUint32 WXUNUSED(len))
154 {
155 m_snderror = wxSOUND_NOCODEC;
156 m_lastcount = 0;
157 return *this;
158 }
159
160 static wxInt16 gl_ADPCMcoeff_delta[] = {
161 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307,
162 230, 230, 230
163 };
164
165 wxUint32 wxSoundStreamMSAdpcm::DecodeMonoADPCM(const void *in_buffer,
166 void *out_buffer,
167 wxUint32 in_len)
168 {
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 }
214 }
215
216 return out_len;
217
218 #undef GET_DATA_16
219 #undef GET_DATA_8
220 }
221
222 wxUint32 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;
230
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);
248
249 GET_DATA_16(state0->samp1);
250 GET_DATA_16(state1->samp1);
251 GET_DATA_16(state0->samp2);
252 GET_DATA_16(state1->samp2);
253
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
287 void 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
323 wxSoundStream& 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
343 return *this;
344 }
345
346 wxUint32 wxSoundStreamMSAdpcm::GetBestSize() const
347 {
348 return m_sndio->GetBestSize() / 2;
349 }
350
351 bool wxSoundStreamMSAdpcm::SetSoundFormat(const wxSoundFormatBase& format)
352 {
353 if (format.GetType() != wxSOUND_MSADPCM) {
354 m_snderror = wxSOUND_INVFRMT;
355 return false;
356 }
357
358 wxSoundFormatPcm pcm;
359 wxSoundFormatMSAdpcm *adpcm;
360 wxUint16 ncoefs, coefs_len;
361
362 wxSoundStreamCodec::SetSoundFormat(format);
363
364 adpcm = (wxSoundFormatMSAdpcm *)m_sndformat;
365
366 adpcm->GetCoefs(m_coefs, ncoefs, coefs_len);
367
368 if (!ncoefs) {
369 wxLogError(wxT("Number of ADPCM coefficients must be non null"));
370 return false;
371 }
372
373 pcm.SetSampleRate(adpcm->GetSampleRate());
374 pcm.SetBPS(16);
375 pcm.SetChannels(adpcm->GetChannels());
376 pcm.Signed(true);
377 pcm.SetOrder(wxBYTE_ORDER);
378
379 m_stereo = (adpcm->GetChannels() == 2);
380 m_block_size = adpcm->GetBlockSize();
381 m_next_block = 0;
382
383 m_router->SetSoundFormat(pcm);
384
385 return true;
386 }
387