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