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