]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/mmedia/sndmsad.cpp
overseeing the obvious, there is already a perfect scroll call for HIView...
[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 // --------------------------------------------------------------------------
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
29 wxSoundFormatMSAdpcm::wxSoundFormatMSAdpcm()
30 : m_srate(22050)
31 {
32 m_ncoefs = 0;
33 m_coefs_len = 0;
34 m_coefs = NULL;
35 }
36
37 wxSoundFormatMSAdpcm::~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
49 void wxSoundFormatMSAdpcm::SetSampleRate(wxUint32 srate)
50 {
51 m_srate = srate;
52 }
53
54 wxUint32 wxSoundFormatMSAdpcm::GetSampleRate() const
55 {
56 return m_srate;
57 }
58
59 void wxSoundFormatMSAdpcm::SetChannels(wxUint16 nchannels)
60 {
61 m_nchannels = nchannels;
62 }
63
64 wxUint16 wxSoundFormatMSAdpcm::GetChannels() const
65 {
66 return m_nchannels;
67 }
68
69 void wxSoundFormatMSAdpcm::SetCoefs(wxInt16 **WXUNUSED(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
89 void 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
97 void wxSoundFormatMSAdpcm::SetBlockSize(wxUint16 block_size)
98 {
99 m_block_size = block_size;
100 }
101
102 wxUint16 wxSoundFormatMSAdpcm::GetBlockSize() const
103 {
104 return m_block_size;
105 }
106
107 wxSoundFormatBase *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
118 wxUint32 wxSoundFormatMSAdpcm::GetTimeFromBytes(wxUint32 bytes) const
119 {
120 return 2 * bytes / (m_nchannels * m_srate);
121 }
122
123 wxUint32 wxSoundFormatMSAdpcm::GetBytesFromTime(wxUint32 time) const
124 {
125 return time * m_nchannels * m_srate / 2;
126 }
127
128 bool 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 // --------------------------------------------------------------------------
141 wxSoundStreamMSAdpcm::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
150 wxSoundStreamMSAdpcm::~wxSoundStreamMSAdpcm()
151 {
152 delete m_router;
153 }
154
155 wxSoundStream& wxSoundStreamMSAdpcm::Read(void *WXUNUSED(buffer), wxUint32 WXUNUSED(len))
156 {
157 m_snderror = wxSOUND_NOCODEC;
158 m_lastcount = 0;
159 return *this;
160 }
161
162 static wxInt16 gl_ADPCMcoeff_delta[] = {
163 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307,
164 230, 230, 230
165 };
166
167 wxUint32 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
224 wxUint32 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
289 void 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
325 wxSoundStream& 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
348 wxUint32 wxSoundStreamMSAdpcm::GetBestSize() const
349 {
350 return m_sndio->GetBestSize() / 2;
351 }
352
353 bool 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(wxT("Number of ADPCM coefficients must be non null"));
372 return FALSE;
373 }
374
375 pcm.SetSampleRate(adpcm->GetSampleRate());
376 pcm.SetBPS(16);
377 pcm.SetChannels(adpcm->GetChannels());
378 pcm.Signed(TRUE);
379 pcm.SetOrder(wxBYTE_ORDER);
380
381 m_stereo = (adpcm->GetChannels() == 2);
382 m_block_size = adpcm->GetBlockSize();
383 m_next_block = 0;
384
385 m_router->SetSoundFormat(pcm);
386
387 return TRUE;
388 }
389