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