]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/mmedia/sndcpcm.cpp
Applied [ 1283696 ] wxDC::GetPartialTextExtents crashes on empty strings
[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 #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
29 wxSoundStreamPcm::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
39 wxSoundStreamPcm::~wxSoundStreamPcm()
40 {
41 if (m_prebuffer)
42 delete[] m_prebuffer;
43 }
44
45 wxUint32 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) \
55 static void Convert_##name(const void *buf_in, void *buf_out, wxUint32 len) \
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
70 DEFINE_CONV(8_8_sign, wxUint8, wxUint8, (src ^ 0x80))
71
72 DEFINE_CONV(8_16, wxUint8, wxUint16, (((wxUint16)src) << 8))
73 DEFINE_CONV(8_16_swap, wxUint8, wxUint16, (src))
74 DEFINE_CONV(8_16_sign, wxUint8, wxUint16, (((wxUint16)(src ^ 0x80)) << 8))
75 DEFINE_CONV(8_16_sign_swap, wxUint8, wxUint16, (src ^ 0x80))
76
77 DEFINE_CONV(16_8, wxUint16, wxUint8, (wxUint8)(src >> 8))
78 DEFINE_CONV(16_8_sign, wxUint16, wxUint8, (wxUint8)((src >> 8) ^ 0x80))
79 DEFINE_CONV(16_swap_8, wxUint16, wxUint8, (wxUint8)(src & 0xff))
80 DEFINE_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
87 DEFINE_CONV(16_sign, wxUint16, wxUint16, (src ^ 0x8000))
88 DEFINE_CONV(16_swap, wxUint16, wxUint16, (((src & 0xff) << 8) | ((src >> 8) & 0xff)))
89 // Problem.
90 DEFINE_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))
92 DEFINE_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
116 static 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.
177 static 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
184 wxSoundStream& 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
231 wxSoundStream& 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
275 bool 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;
283 return true;
284 }
285 if (format.GetType() != wxSOUND_PCM) {
286 m_snderror = wxSOUND_INVFRMT;
287 return false;
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();
304 m_needResampling = true;
305 if (src_rate < dst_rate)
306 m_expandSamples = true;
307 else
308 m_expandSamples = false;
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, ...
331 return false;
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, ...
342 return false;
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 for 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) {
383 m_prebuffer_size = (wxUint32)(m_sndio->GetBestSize() *
384 m_multiplier_out);
385 m_best_size = (wxUint32)(m_sndio->GetBestSize() *
386 m_multiplier_in);
387 } else {
388 m_prebuffer_size = (wxUint32)(m_sndio->GetBestSize() *
389 m_multiplier_in);
390 m_best_size = (wxUint32)(m_sndio->GetBestSize() *
391 m_multiplier_out);
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 );
400 wxUnusedVar( SetSoundFormatReturn );
401
402 m_sndformat = new_format;
403 return true;
404 }
405
406 wxUint32 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
413 wxUint32 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
427 void 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