]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/mmedia/sndcpcm.cpp
fix evaluation order bug (patch 1158099)
[wxWidgets.git] / contrib / src / mmedia / sndcpcm.cpp
CommitLineData
e8482f24
GL
1// --------------------------------------------------------------------------
2// Name: sndcpcm.cpp
3// Purpose:
4// Date: 08/11/1999
5// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000
6// CVSID: $Id$
58b9c9ba 7// wxWindows licence
e8482f24
GL
8// --------------------------------------------------------------------------
9#ifdef __GNUG__
10#pragma implementation "sndcpcm.cpp"
11#endif
12
13#include "wx/wxprec.h"
14
15#ifndef WX_PRECOMP
16 #include "wx/defs.h"
17 #include "wx/debug.h"
18 #include "wx/log.h"
19#endif
20
21#ifdef __BORLANDC__
22 #pragma hdrstop
23#endif
24
25#include "wx/mmedia/sndbase.h"
26#include "wx/mmedia/sndpcm.h"
27#include "wx/mmedia/sndcpcm.h"
28
29wxSoundStreamPcm::wxSoundStreamPcm(wxSoundStream& sndio)
30 : wxSoundStreamCodec(sndio)
31{
32 m_function_in = NULL;
33 m_function_out = NULL;
34 m_prebuffer = NULL;
35 m_prebuffer_size = 0;
36 m_best_size = 0;
37}
38
39wxSoundStreamPcm::~wxSoundStreamPcm()
40{
41 if (m_prebuffer)
42 delete[] m_prebuffer;
43}
44
45wxUint32 wxSoundStreamPcm::GetBestSize() const
46{
47 return m_best_size;
48}
49
50// -----------------------------------------------------------------------
51// "Converters" definitions/implementations
52// -----------------------------------------------------------------------
53
54#define DEFINE_CONV(name, input_type, output_type, convert) \
15e8daec 55static void Convert_##name(const void *buf_in, void *buf_out, wxUint32 len) \
e8482f24
GL
56{\
57 register input_type src; \
58 register const input_type *t_buf_in = (input_type *)buf_in; \
59 register output_type *t_buf_out = (output_type *)buf_out; \
60\
61 while (len > 0) { \
62 src = *t_buf_in++; \
63 *t_buf_out++ = convert; \
64 len -= sizeof(input_type); \
65 } \
66}
67
68// TODO: define converters for all other formats (32, 24)
69
70DEFINE_CONV(8_8_sign, wxUint8, wxUint8, (src ^ 0x80))
71
72DEFINE_CONV(8_16, wxUint8, wxUint16, (((wxUint16)src) << 8))
73DEFINE_CONV(8_16_swap, wxUint8, wxUint16, (src))
74DEFINE_CONV(8_16_sign, wxUint8, wxUint16, (((wxUint16)(src ^ 0x80)) << 8))
75DEFINE_CONV(8_16_sign_swap, wxUint8, wxUint16, (src ^ 0x80))
76
77DEFINE_CONV(16_8, wxUint16, wxUint8, (wxUint8)(src >> 8))
78DEFINE_CONV(16_8_sign, wxUint16, wxUint8, (wxUint8)((src >> 8) ^ 0x80))
79DEFINE_CONV(16_swap_8, wxUint16, wxUint8, (wxUint8)(src & 0xff))
80DEFINE_CONV(16_swap_8_sign, wxUint16, wxUint8, (wxUint8)((src & 0xff) ^ 0x80))
81
82//DEFINE_CONV(24_8, wxUint32, wxUint8, (wxUint8)(src >> 16))
83//DEFINE_CONV(24_8_sig, wxUint32, wxUint8, (wxUint8)((src >> 16) ^ 0x80))
84
85//DEFINE_CONV(32_8, wxUint32, wxUint8, (wxUint8)(src >> 24))
86
87DEFINE_CONV(16_sign, wxUint16, wxUint16, (src ^ 0x8000))
88DEFINE_CONV(16_swap, wxUint16, wxUint16, (((src & 0xff) << 8) | ((src >> 8) & 0xff)))
89// Problem.
90DEFINE_CONV(16_swap_16_sign, wxUint16, wxUint16, ((((src & 0xff) << 8) | ((src >> 8) & 0xff)) ^ 0x80))
91// DEFINE_CONV(16_sign_16_swap, wxUint16, wxUint16, ((((src & 0xff) << 8) | ((src >> 8) & 0xff)) ^ 0x8000))
92DEFINE_CONV(16_swap_16_sign_swap, wxUint16, wxUint16, (src ^ 0x80))
93
94// -----------------------------------------------------------------------
95// Main PCM stream converter table
96// -----------------------------------------------------------------------
97// Definition
98// XX -> YY
99// XX -> YY sign
100//
101// XX swapped -> YY
102// XX swapped -> YY sign
103//
104// XX swapped -> YY swapped
105// XX swapped -> YY swapped sign
106//
107// XX stereo -> YY mono
108// XX stereo -> YY mono sign
109//
110// XX swapped stereo -> YY swapped mono
111// XX swapped stereo -> YY swapped mono sign
112//
113// XX swapped stereo -> YY swapped mono
114// XX swapped stereo -> YY swapped mono sign
115
116static wxSoundStreamPcm::ConverterType s_converters[4][3][2] = {
117 {
118 {
119 NULL,
120 Convert_8_8_sign /* 8 -> 8 sign */
121 },
122 {
123 NULL,
124 NULL
125 },
126 {
127 NULL,
128 NULL
129 }
130 },
131 {
132 {
133 Convert_8_16, /* 8 -> 16 */
134 Convert_8_16_sign /* 8 -> 16 sign */
135 },
136 {
137 Convert_8_16_swap, /* 8 -> 16 swapped */
138 Convert_8_16_sign_swap /* 8 -> 16 sign swapped */
139 },
140 {
141 NULL,
142 NULL
143 }
144 },
145 {
146 {
147 Convert_16_8, /* 16 -> 8 */
148 Convert_16_8_sign /* 16 -> 8 sign */
149 },
150 {
151 Convert_16_swap_8, /* 16 swapped -> 8 */
152 Convert_16_swap_8_sign /* 16 swapped -> 8 sign */
153 },
154 {
155 NULL,
156 NULL
157 },
158 },
159
160 {
161 {
162 NULL, /* 16 -> 16 */
163 Convert_16_sign /* 16 -> 16 sign */
164 },
165 {
166 Convert_16_swap, /* 16 swapped -> 16 */
167 Convert_16_swap_16_sign /* 16 swapped -> 16 sign */
168 },
169 {
170 NULL,
171 Convert_16_swap_16_sign_swap /* 16 swapped -> 16 sign swapped */
172 }
173 }
174};
175
176// This is the buffer size multiplier. It gives the needed size of the output size.
177static float s_converters_multip[] = {1, 2, 0.5, 1};
178
179//
180// TODO: Read() and Write() aren't really safe. If you give it a buffer which
181// is not aligned on 2, you may crash (See converter.def).
182//
183
184wxSoundStream& wxSoundStreamPcm::Read(void *buffer, wxUint32 len)
185{
186 wxUint32 in_bufsize;
187
188 // We must have a multiple of 2
189 len &= 0x01;
190
191 if (!m_function_in) {
192 m_sndio->Read(buffer, len);
193 m_lastcount = m_sndio->GetLastAccess();
194 m_snderror = m_sndio->GetError();
195 return *this;
196 }
197
198 in_bufsize = GetReadSize(len);
199
200 if (len <= m_best_size) {
201 m_sndio->Read(m_prebuffer, in_bufsize);
202 m_snderror = m_sndio->GetError();
203 if (m_snderror != wxSOUND_NOERROR) {
204 m_lastcount = 0;
205 return *this;
206 }
207
208 m_function_in(m_prebuffer, buffer, m_sndio->GetLastAccess());
209 } else {
210 char *temp_buffer;
211
212 temp_buffer = new char[in_bufsize];
213 m_sndio->Read(temp_buffer, in_bufsize);
214
215 m_snderror = m_sndio->GetError();
216 if (m_snderror != wxSOUND_NOERROR) {
217 m_lastcount = 0;
218 return *this;
219 }
220
221 m_function_in(temp_buffer, buffer, m_sndio->GetLastAccess());
222
223 delete[] temp_buffer;
224 }
225
226 m_lastcount = (wxUint32)(m_sndio->GetLastAccess() * m_multiplier_in);
227
228 return *this;
229}
230
231wxSoundStream& wxSoundStreamPcm::Write(const void *buffer, wxUint32 len)
232{
233 wxUint32 out_bufsize;
234
235 if (!m_function_out) {
236 m_sndio->Write(buffer, len);
237 m_lastcount = m_sndio->GetLastAccess();
238 m_snderror = m_sndio->GetError();
239 return *this;
240 }
241
242 out_bufsize = GetWriteSize(len);
243
244 if (len <= m_best_size) {
245 out_bufsize = GetWriteSize(len);
246
247 m_function_out(buffer, m_prebuffer, len);
248 m_sndio->Write(m_prebuffer, out_bufsize);
249 m_snderror = m_sndio->GetError();
250 if (m_snderror != wxSOUND_NOERROR) {
251 m_lastcount = 0;
252 return *this;
253 }
254 } else {
255 char *temp_buffer;
256
257 temp_buffer = new char[out_bufsize];
258 m_function_out(buffer, temp_buffer, len);
259
260 m_sndio->Write(temp_buffer, out_bufsize);
261 m_snderror = m_sndio->GetError();
262 if (m_snderror != wxSOUND_NOERROR) {
263 m_lastcount = 0;
264 return *this;
265 }
266
267 delete[] temp_buffer;
268 }
269
270 m_lastcount = (wxUint32)(m_sndio->GetLastAccess() / m_multiplier_out);
271
272 return *this;
273}
274
275bool wxSoundStreamPcm::SetSoundFormat(const wxSoundFormatBase& format)
276{
277 wxSoundFormatBase *new_format;
278 wxSoundFormatPcm *pcm_format, *pcm_format2;
279
280 if (m_sndio->SetSoundFormat(format)) {
281 m_function_out = NULL;
282 m_function_in = NULL;
dea7e44a 283 return true;
e8482f24
GL
284 }
285 if (format.GetType() != wxSOUND_PCM) {
286 m_snderror = wxSOUND_INVFRMT;
dea7e44a 287 return false;
e8482f24
GL
288 }
289 if (m_sndformat)
290 delete m_sndformat;
291
292 new_format = m_sndio->GetSoundFormat().Clone();
293 pcm_format = (wxSoundFormatPcm *)&format;
294 pcm_format2 = (wxSoundFormatPcm *)new_format;
295
296#if 0
297 // ----------------------------------------------------
298 // Test whether we need to resample
299 if (pcm_format->GetSampleRate() != pcm_format2->GetSampleRate()) {
300 wxUint32 src_rate, dst_rate;
301
302 src_rate = pcm_format->GetSampleRate();
303 dst_rate = pcm_format2->GetSampleRate();
dea7e44a 304 m_needResampling = true;
e8482f24 305 if (src_rate < dst_rate)
dea7e44a 306 m_expandSamples = true;
e8482f24 307 else
dea7e44a 308 m_expandSamples = false;
e8482f24
GL
309 m_pitch = (src_rate << FLOATBITS) / dst_rate;
310 }
311#endif
312 // ----------------------------------------------------
313 // Select table to use:
314 // * 8 bits -> 8 bits
315 // * 16 bits -> 8 bits
316 // * 8 bits -> 16 bits
317 // * 16 bits -> 16 bits
318
319 int table_no, table_no2;
320 int i_sign, i_swap;
321
322 switch (pcm_format->GetBPS()) {
323 case 8:
324 table_no = 0;
325 break;
326 case 16:
327 table_no = 1;
328 break;
329 default:
330 // TODO: Add something here: error, log, ...
dea7e44a 331 return false;
e8482f24
GL
332 }
333 switch (pcm_format2->GetBPS()) {
334 case 8:
335 table_no2 = 0;
336 break;
337 case 16:
338 table_no2 = 1;
339 break;
340 default:
341 // TODO: Add something here: error, log, ...
dea7e44a 342 return false;
e8482f24
GL
343 }
344
345 if (pcm_format2->Signed() != pcm_format->Signed())
346 i_sign = 1;
347 else
348 i_sign = 0;
349
350#define MY_ORDER wxBYTE_ORDER
351#if wxBYTE_ORDER == wxLITTLE_ENDIAN
352#define OTHER_ORDER wxBIG_ENDIAN
353#else
354#define OTHER_ORDER wxLITTLE_ENDIAN
355#endif
356
357 // --------------------------------------------------------
358 // Find the good converter !
359
360 if (pcm_format->GetOrder() == OTHER_ORDER) {
361 if (pcm_format->GetOrder() == pcm_format2->GetOrder())
362 i_swap = 2;
363 else
364 i_swap = 1;
365 } else {
366 if (pcm_format->GetOrder() == pcm_format2->GetOrder())
367 i_swap = 0;
368 else
369 i_swap = 1;
370 }
371
372 m_function_out = s_converters[table_no*2+table_no2][i_swap][i_sign];
373 m_function_in = s_converters[table_no2*2+table_no][i_swap][i_sign];
374 m_multiplier_out = s_converters_multip[table_no*2+table_no2];
375 m_multiplier_in = s_converters_multip[table_no2*2+table_no2];
376
377 if (m_prebuffer)
378 delete[] m_prebuffer;
379
380 // We try to minimize the need of dynamic memory allocation by preallocating a buffer. But
381 // to be sure it will be efficient we minimize the best size.
382 if (m_multiplier_in < m_multiplier_out) {
c42b1de6
GL
383 m_prebuffer_size = (wxUint32)(m_sndio->GetBestSize() *
384 m_multiplier_out);
385 m_best_size = (wxUint32)(m_sndio->GetBestSize() *
386 m_multiplier_in);
e8482f24 387 } else {
c42b1de6
GL
388 m_prebuffer_size = (wxUint32)(m_sndio->GetBestSize() *
389 m_multiplier_in);
390 m_best_size = (wxUint32)(m_sndio->GetBestSize() *
391 m_multiplier_out);
e8482f24
GL
392 }
393
394 m_prebuffer = new char[m_prebuffer_size];
395
396 bool SetSoundFormatReturn;
397
398 SetSoundFormatReturn = m_sndio->SetSoundFormat(*new_format);
399 wxASSERT( SetSoundFormatReturn );
2b3644c7 400 wxUnusedVar( SetSoundFormatReturn );
e8482f24
GL
401
402 m_sndformat = new_format;
dea7e44a 403 return true;
e8482f24
GL
404}
405
406wxUint32 wxSoundStreamPcm::GetWriteSize(wxUint32 len) const
407{
408 // For the moment, it is simple but next time it will become more complicated
409 // (Resampling)
410 return (wxUint32)(len * m_multiplier_out);
411}
412
413wxUint32 wxSoundStreamPcm::GetReadSize(wxUint32 len) const
414{
415 return (wxUint32)(len / m_multiplier_in);
416}
417
418// Resampling engine. NOT FINISHED and NOT INCLUDED but this is a first DRAFT.
419
420#if 0
421
422#define FLOATBITS 16
423#define INTBITS 16
424#define FLOATMASK 0xffff
425#define INTMASK 0xffff0000
426
427void ResamplingShrink_##DEPTH##(const void *source, void *destination, wxUint32 len)
428{
429 wxUint##DEPTH## *source_data, *dest_data;
430 wxUint32 pos;
431
432 source_data = (wxUint##DEPTH## *)source;
433 dest_data = (wxUint##DEPTH## *)destination;
434
435 pos = m_saved_pos;
436 while (len > 0) {
437 // Increment the position in the input buffer
438 pos += m_pitch;
439 if (pos & INTMASK) {
440 pos &= FLOATMASK;
441
442 *dest_data ++ = *source_data;
443 }
444 len--;
445 source_data++;
446 }
447 m_saved_pos = pos;
448}
449#endif