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