Mercurial > SDL_sound_CoreAudio
annotate audio_convert.c @ 461:3112fac4abfe
Updated.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 10 Oct 2003 08:02:54 +0000 |
parents | fb519e6028e3 |
children | 636796aed4e2 |
rev | line source |
---|---|
141 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga | |
4 | |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Library General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2 of the License, or (at your option) any later version. | |
9 | |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Library General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Library General Public | |
16 License along with this library; if not, write to the Free | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | |
19 Sam Lantinga | |
20 slouken@devolution.com | |
21 */ | |
22 | |
23 /* | |
24 * This file was derived from SDL's SDL_audiocvt.c and is an attempt to | |
25 * address the shortcomings of it. | |
26 * | |
27 * Perhaps we can adapt some good filters from SoX? | |
28 */ | |
29 | |
30 #if HAVE_CONFIG_H | |
31 # include <config.h> | |
32 #endif | |
33 | |
34 #include "SDL.h" | |
35 #include "SDL_sound.h" | |
36 | |
37 #define __SDL_SOUND_INTERNAL__ | |
38 #include "SDL_sound_internal.h" | |
39 | |
40 /* Functions for audio drivers to perform runtime conversion of audio format */ | |
41 | |
42 | |
43 /* | |
44 * Toggle endianness. This filter is, of course, only applied to 16-bit | |
45 * audio data. | |
46 */ | |
47 | |
342 | 48 static void Sound_ConvertEndian(Sound_AudioCVT *cvt, Uint16 *format) |
141 | 49 { |
50 int i; | |
51 Uint8 *data, tmp; | |
52 | |
53 /* SNDDBG(("Converting audio endianness\n")); */ | |
54 | |
55 data = cvt->buf; | |
56 | |
57 for (i = cvt->len_cvt / 2; i; --i) | |
58 { | |
59 tmp = data[0]; | |
60 data[0] = data[1]; | |
61 data[1] = tmp; | |
62 data += 2; | |
63 } /* for */ | |
64 | |
65 *format = (*format ^ 0x1000); | |
66 } /* Sound_ConvertEndian */ | |
67 | |
68 | |
69 /* | |
70 * Toggle signed/unsigned. Apparently this is done by toggling the most | |
71 * significant bit of each sample. | |
72 */ | |
73 | |
342 | 74 static void Sound_ConvertSign(Sound_AudioCVT *cvt, Uint16 *format) |
141 | 75 { |
76 int i; | |
77 Uint8 *data; | |
78 | |
79 /* SNDDBG(("Converting audio signedness\n")); */ | |
80 | |
81 data = cvt->buf; | |
82 | |
83 /* 16-bit sound? */ | |
84 if ((*format & 0xFF) == 16) | |
85 { | |
86 /* Little-endian? */ | |
87 if ((*format & 0x1000) != 0x1000) | |
88 ++data; | |
89 | |
90 for (i = cvt->len_cvt / 2; i; --i) | |
91 { | |
92 *data ^= 0x80; | |
93 data += 2; | |
94 } /* for */ | |
95 } /* if */ | |
96 else | |
97 { | |
98 for (i = cvt->len_cvt; i; --i) | |
99 *data++ ^= 0x80; | |
100 } /* else */ | |
101 | |
102 *format = (*format ^ 0x8000); | |
103 } /* Sound_ConvertSign */ | |
104 | |
105 | |
106 /* | |
107 * Convert 16-bit to 8-bit. This is done by taking the most significant byte | |
108 * of each 16-bit sample. | |
109 */ | |
110 | |
342 | 111 static void Sound_Convert8(Sound_AudioCVT *cvt, Uint16 *format) |
141 | 112 { |
113 int i; | |
114 Uint8 *src, *dst; | |
115 | |
116 /* SNDDBG(("Converting to 8-bit\n")); */ | |
117 | |
118 src = cvt->buf; | |
119 dst = cvt->buf; | |
120 | |
121 /* Little-endian? */ | |
122 if ((*format & 0x1000) != 0x1000) | |
123 ++src; | |
124 | |
125 for (i = cvt->len_cvt / 2; i; --i) | |
126 { | |
127 *dst = *src; | |
128 src += 2; | |
129 dst += 1; | |
130 } /* for */ | |
131 | |
132 *format = ((*format & ~0x9010) | AUDIO_U8); | |
133 cvt->len_cvt /= 2; | |
134 } /* Sound_Convert8 */ | |
135 | |
136 | |
137 /* Convert 8-bit to 16-bit - LSB */ | |
138 | |
342 | 139 static void Sound_Convert16LSB(Sound_AudioCVT *cvt, Uint16 *format) |
141 | 140 { |
141 int i; | |
142 Uint8 *src, *dst; | |
143 | |
144 /* SNDDBG(("Converting to 16-bit LSB\n")); */ | |
145 | |
146 src = cvt->buf + cvt->len_cvt; | |
147 dst = cvt->buf + cvt->len_cvt * 2; | |
148 | |
149 for (i = cvt->len_cvt; i; --i) | |
150 { | |
151 src -= 1; | |
152 dst -= 2; | |
153 dst[1] = *src; | |
154 dst[0] = 0; | |
155 } /* for */ | |
156 | |
157 *format = ((*format & ~0x0008) | AUDIO_U16LSB); | |
158 cvt->len_cvt *= 2; | |
159 } /* Sound_Convert16LSB */ | |
160 | |
161 | |
162 /* Convert 8-bit to 16-bit - MSB */ | |
163 | |
342 | 164 static void Sound_Convert16MSB(Sound_AudioCVT *cvt, Uint16 *format) |
141 | 165 { |
166 int i; | |
167 Uint8 *src, *dst; | |
168 | |
169 /* SNDDBG(("Converting to 16-bit MSB\n")); */ | |
170 | |
171 src = cvt->buf + cvt->len_cvt; | |
172 dst = cvt->buf + cvt->len_cvt * 2; | |
173 | |
174 for (i = cvt->len_cvt; i; --i) | |
175 { | |
176 src -= 1; | |
177 dst -= 2; | |
178 dst[0] = *src; | |
179 dst[1] = 0; | |
180 } /* for */ | |
181 | |
182 *format = ((*format & ~0x0008) | AUDIO_U16MSB); | |
183 cvt->len_cvt *= 2; | |
184 } /* Sound_Convert16MSB */ | |
185 | |
186 | |
187 /* Duplicate a mono channel to both stereo channels */ | |
188 | |
342 | 189 static void Sound_ConvertStereo(Sound_AudioCVT *cvt, Uint16 *format) |
141 | 190 { |
191 int i; | |
192 | |
193 /* SNDDBG(("Converting to stereo\n")); */ | |
194 | |
195 /* 16-bit sound? */ | |
196 if ((*format & 0xFF) == 16) | |
197 { | |
198 Uint16 *src, *dst; | |
199 | |
200 src = (Uint16 *) (cvt->buf + cvt->len_cvt); | |
201 dst = (Uint16 *) (cvt->buf + cvt->len_cvt * 2); | |
202 | |
203 for (i = cvt->len_cvt/2; i; --i) | |
204 { | |
205 dst -= 2; | |
206 src -= 1; | |
207 dst[0] = src[0]; | |
208 dst[1] = src[0]; | |
209 } /* for */ | |
210 } /* if */ | |
211 else | |
212 { | |
213 Uint8 *src, *dst; | |
214 | |
215 src = cvt->buf + cvt->len_cvt; | |
216 dst = cvt->buf + cvt->len_cvt * 2; | |
217 | |
218 for (i = cvt->len_cvt; i; --i) | |
219 { | |
220 dst -= 2; | |
221 src -= 1; | |
222 dst[0] = src[0]; | |
223 dst[1] = src[0]; | |
224 } /* for */ | |
225 } /* else */ | |
226 | |
227 cvt->len_cvt *= 2; | |
228 } /* Sound_ConvertStereo */ | |
229 | |
230 | |
231 /* Effectively mix right and left channels into a single channel */ | |
232 | |
342 | 233 static void Sound_ConvertMono(Sound_AudioCVT *cvt, Uint16 *format) |
141 | 234 { |
235 int i; | |
236 Sint32 sample; | |
237 Uint8 *u_src, *u_dst; | |
238 Sint8 *s_src, *s_dst; | |
239 | |
240 /* SNDDBG(("Converting to mono\n")); */ | |
241 | |
242 switch (*format) | |
243 { | |
244 case AUDIO_U8: | |
245 u_src = cvt->buf; | |
246 u_dst = cvt->buf; | |
247 | |
248 for (i = cvt->len_cvt / 2; i; --i) | |
249 { | |
250 sample = u_src[0] + u_src[1]; | |
251 *u_dst = (sample > 255) ? 255 : sample; | |
252 u_src += 2; | |
253 u_dst += 1; | |
254 } /* for */ | |
255 break; | |
256 | |
257 case AUDIO_S8: | |
258 s_src = (Sint8 *) cvt->buf; | |
259 s_dst = (Sint8 *) cvt->buf; | |
260 | |
261 for (i = cvt->len_cvt / 2; i; --i) | |
262 { | |
263 sample = s_src[0] + s_src[1]; | |
264 if (sample > 127) | |
265 *s_dst = 127; | |
266 else if (sample < -128) | |
267 *s_dst = -128; | |
268 else | |
269 *s_dst = sample; | |
270 | |
271 s_src += 2; | |
272 s_dst += 1; | |
273 } /* for */ | |
274 break; | |
275 | |
276 case AUDIO_U16MSB: | |
277 u_src = cvt->buf; | |
278 u_dst = cvt->buf; | |
279 | |
280 for (i = cvt->len_cvt / 4; i; --i) | |
281 { | |
282 sample = (Uint16) ((u_src[0] << 8) | u_src[1]) | |
283 + (Uint16) ((u_src[2] << 8) | u_src[3]); | |
284 if (sample > 65535) | |
285 { | |
286 u_dst[0] = 0xFF; | |
287 u_dst[1] = 0xFF; | |
288 } /* if */ | |
289 else | |
290 { | |
291 u_dst[1] = (sample & 0xFF); | |
292 sample >>= 8; | |
293 u_dst[0] = (sample & 0xFF); | |
294 } /* else */ | |
295 u_src += 4; | |
296 u_dst += 2; | |
297 } /* for */ | |
298 break; | |
299 | |
300 case AUDIO_U16LSB: | |
301 u_src = cvt->buf; | |
302 u_dst = cvt->buf; | |
303 | |
304 for (i = cvt->len_cvt / 4; i; --i) | |
305 { | |
306 sample = (Uint16) ((u_src[1] << 8) | u_src[0]) | |
307 + (Uint16) ((u_src[3] << 8) | u_src[2]); | |
308 if (sample > 65535) | |
309 { | |
310 u_dst[0] = 0xFF; | |
311 u_dst[1] = 0xFF; | |
312 } /* if */ | |
313 else | |
314 { | |
315 u_dst[0] = (sample & 0xFF); | |
316 sample >>= 8; | |
317 u_dst[1] = (sample & 0xFF); | |
318 } /* else */ | |
319 u_src += 4; | |
320 u_dst += 2; | |
321 } /* for */ | |
322 break; | |
323 | |
324 case AUDIO_S16MSB: | |
325 u_src = cvt->buf; | |
326 u_dst = cvt->buf; | |
327 | |
328 for (i = cvt->len_cvt / 4; i; --i) | |
329 { | |
330 sample = (Sint16) ((u_src[0] << 8) | u_src[1]) | |
331 + (Sint16) ((u_src[2] << 8) | u_src[3]); | |
332 if (sample > 32767) | |
333 { | |
334 u_dst[0] = 0x7F; | |
335 u_dst[1] = 0xFF; | |
336 } /* if */ | |
337 else if (sample < -32768) | |
338 { | |
339 u_dst[0] = 0x80; | |
340 u_dst[1] = 0x00; | |
341 } /* else if */ | |
342 else | |
343 { | |
344 u_dst[1] = (sample & 0xFF); | |
345 sample >>= 8; | |
346 u_dst[0] = (sample & 0xFF); | |
347 } /* else */ | |
348 u_src += 4; | |
349 u_dst += 2; | |
350 } /* for */ | |
351 break; | |
352 | |
353 case AUDIO_S16LSB: | |
354 u_src = cvt->buf; | |
355 u_dst = cvt->buf; | |
356 | |
357 for (i = cvt->len_cvt / 4; i; --i) | |
358 { | |
359 sample = (Sint16) ((u_src[1] << 8) | u_src[0]) | |
360 + (Sint16) ((u_src[3] << 8) | u_src[2]); | |
361 if (sample > 32767) | |
362 { | |
363 u_dst[1] = 0x7F; | |
364 u_dst[0] = 0xFF; | |
365 } /* if */ | |
366 else if (sample < -32768) | |
367 { | |
368 u_dst[1] = 0x80; | |
369 u_dst[0] = 0x00; | |
370 } /* else if */ | |
371 else | |
372 { | |
373 u_dst[0] = (sample & 0xFF); | |
374 sample >>= 8; | |
375 u_dst[1] = (sample & 0xFF); | |
376 } /* else */ | |
377 u_src += 4; | |
378 u_dst += 2; | |
379 } /* for */ | |
380 break; | |
381 } /* switch */ | |
382 | |
383 cvt->len_cvt /= 2; | |
384 } /* Sound_ConvertMono */ | |
385 | |
386 | |
387 /* Convert rate up by multiple of 2 */ | |
388 | |
342 | 389 static void Sound_RateMUL2(Sound_AudioCVT *cvt, Uint16 *format) |
141 | 390 { |
391 int i; | |
392 Uint8 *src, *dst; | |
393 | |
394 /* SNDDBG(("Converting audio rate * 2\n")); */ | |
395 | |
396 src = cvt->buf + cvt->len_cvt; | |
397 dst = cvt->buf + cvt->len_cvt*2; | |
398 | |
399 /* 8- or 16-bit sound? */ | |
400 switch (*format & 0xFF) | |
401 { | |
402 case 8: | |
403 for (i = cvt->len_cvt; i; --i) | |
404 { | |
405 src -= 1; | |
406 dst -= 2; | |
407 dst[0] = src[0]; | |
408 dst[1] = src[0]; | |
409 } /* for */ | |
410 break; | |
411 | |
412 case 16: | |
413 for (i = cvt->len_cvt / 2; i; --i) | |
414 { | |
415 src -= 2; | |
416 dst -= 4; | |
417 dst[0] = src[0]; | |
418 dst[1] = src[1]; | |
419 dst[2] = src[0]; | |
420 dst[3] = src[1]; | |
421 } /* for */ | |
422 break; | |
423 } /* switch */ | |
424 | |
425 cvt->len_cvt *= 2; | |
426 } /* Sound_RateMUL2 */ | |
427 | |
428 | |
429 /* Convert rate down by multiple of 2 */ | |
430 | |
342 | 431 static void Sound_RateDIV2(Sound_AudioCVT *cvt, Uint16 *format) |
141 | 432 { |
433 int i; | |
434 Uint8 *src, *dst; | |
435 | |
436 /* SNDDBG(("Converting audio rate / 2\n")); */ | |
437 | |
438 src = cvt->buf; | |
439 dst = cvt->buf; | |
440 | |
441 /* 8- or 16-bit sound? */ | |
442 switch (*format & 0xFF) | |
443 { | |
444 case 8: | |
445 for (i = cvt->len_cvt / 2; i; --i) | |
446 { | |
447 dst[0] = src[0]; | |
448 src += 2; | |
449 dst += 1; | |
450 } /* for */ | |
451 break; | |
452 | |
453 case 16: | |
454 for (i = cvt->len_cvt / 4; i; --i) | |
455 { | |
456 dst[0] = src[0]; | |
457 dst[1] = src[1]; | |
458 src += 4; | |
459 dst += 2; | |
460 } | |
461 break; | |
462 } /* switch */ | |
463 | |
464 cvt->len_cvt /= 2; | |
465 } /* Sound_RateDIV2 */ | |
466 | |
467 | |
468 /* Very slow rate conversion routine */ | |
469 | |
342 | 470 static void Sound_RateSLOW(Sound_AudioCVT *cvt, Uint16 *format) |
141 | 471 { |
472 double ipos; | |
473 int i, clen; | |
474 Uint8 *output8; | |
475 Uint16 *output16; | |
476 | |
477 /* SNDDBG(("Converting audio rate * %4.4f\n", 1.0/cvt->rate_incr)); */ | |
478 | |
479 clen = (int) ((double) cvt->len_cvt / cvt->rate_incr); | |
480 | |
481 if (cvt->rate_incr > 1.0) | |
482 { | |
483 /* 8- or 16-bit sound? */ | |
484 switch (*format & 0xFF) | |
485 { | |
486 case 8: | |
487 output8 = cvt->buf; | |
488 | |
489 ipos = 0.0; | |
490 for (i = clen; i; --i) | |
491 { | |
492 *output8 = cvt->buf[(int) ipos]; | |
493 ipos += cvt->rate_incr; | |
494 output8 += 1; | |
495 } /* for */ | |
496 break; | |
497 | |
498 case 16: | |
499 output16 = (Uint16 *) cvt->buf; | |
500 | |
501 clen &= ~1; | |
502 ipos = 0.0; | |
503 for (i = clen / 2; i; --i) | |
504 { | |
505 *output16 = ((Uint16 *) cvt->buf)[(int) ipos]; | |
506 ipos += cvt->rate_incr; | |
507 output16 += 1; | |
508 } /* for */ | |
509 break; | |
510 } /* switch */ | |
511 } /* if */ | |
512 else | |
513 { | |
514 /* 8- or 16-bit sound */ | |
515 switch (*format & 0xFF) | |
516 { | |
517 case 8: | |
518 output8 = cvt->buf + clen; | |
519 | |
520 ipos = (double) cvt->len_cvt; | |
521 for (i = clen; i; --i) | |
522 { | |
523 ipos -= cvt->rate_incr; | |
524 output8 -= 1; | |
525 *output8 = cvt->buf[(int) ipos]; | |
526 } /* for */ | |
527 break; | |
528 | |
529 case 16: | |
530 clen &= ~1; | |
531 output16 = (Uint16 *) (cvt->buf + clen); | |
532 ipos = (double) cvt->len_cvt / 2; | |
533 for (i = clen / 2; i; --i) | |
534 { | |
535 ipos -= cvt->rate_incr; | |
536 output16 -= 1; | |
537 *output16 = ((Uint16 *) cvt->buf)[(int) ipos]; | |
538 } /* for */ | |
539 break; | |
540 } /* switch */ | |
541 } /* else */ | |
542 | |
543 cvt->len_cvt = clen; | |
544 } /* Sound_RateSLOW */ | |
545 | |
546 | |
547 int Sound_ConvertAudio(Sound_AudioCVT *cvt) | |
548 { | |
549 Uint16 format; | |
550 | |
551 /* Make sure there's data to convert */ | |
552 if (cvt->buf == NULL) | |
553 { | |
387
fb519e6028e3
Changed all the Sound_SetError() calls to __Sound_SetError (or BAIL*_MACRO)
Ryan C. Gordon <icculus@icculus.org>
parents:
382
diff
changeset
|
554 __Sound_SetError("No buffer allocated for conversion"); |
141 | 555 return(-1); |
556 } /* if */ | |
557 | |
558 /* Return okay if no conversion is necessary */ | |
559 cvt->len_cvt = cvt->len; | |
560 if (cvt->filters[0] == NULL) | |
561 return(0); | |
562 | |
563 /* Set up the conversion and go! */ | |
564 format = cvt->src_format; | |
565 for (cvt->filter_index = 0; cvt->filters[cvt->filter_index]; | |
566 cvt->filter_index++) | |
567 { | |
568 cvt->filters[cvt->filter_index](cvt, &format); | |
569 } | |
570 return(0); | |
571 } /* Sound_ConvertAudio */ | |
572 | |
573 | |
574 /* | |
575 * Creates a set of audio filters to convert from one format to another. | |
576 * Returns -1 if the format conversion is not supported, or 1 if the | |
577 * audio filter is set up. | |
578 */ | |
579 | |
580 int Sound_BuildAudioCVT(Sound_AudioCVT *cvt, | |
581 Uint16 src_format, Uint8 src_channels, Uint32 src_rate, | |
382
ce998ee6194f
Sync'd with latest altcvt.
Ryan C. Gordon <icculus@icculus.org>
parents:
342
diff
changeset
|
582 Uint16 dst_format, Uint8 dst_channels, Uint32 dst_rate, |
ce998ee6194f
Sync'd with latest altcvt.
Ryan C. Gordon <icculus@icculus.org>
parents:
342
diff
changeset
|
583 Uint32 dst_size) |
141 | 584 { |
585 /* Start off with no conversion necessary */ | |
586 cvt->needed = 0; | |
587 cvt->filter_index = 0; | |
588 cvt->filters[0] = NULL; | |
589 cvt->len_mult = 1; | |
590 cvt->len_ratio = 1.0; | |
591 | |
592 /* First filter: Endian conversion from src to dst */ | |
593 if ((src_format & 0x1000) != (dst_format & 0x1000) && | |
594 ((src_format & 0xff) != 8)) | |
595 { | |
596 SNDDBG(("Adding filter: Sound_ConvertEndian\n")); | |
597 cvt->filters[cvt->filter_index++] = Sound_ConvertEndian; | |
598 } /* if */ | |
599 | |
600 /* Second filter: Sign conversion -- signed/unsigned */ | |
601 if ((src_format & 0x8000) != (dst_format & 0x8000)) | |
602 { | |
603 SNDDBG(("Adding filter: Sound_ConvertSign\n")); | |
604 cvt->filters[cvt->filter_index++] = Sound_ConvertSign; | |
605 } /* if */ | |
606 | |
607 /* Next filter: Convert 16 bit <--> 8 bit PCM. */ | |
608 if ((src_format & 0xFF) != (dst_format & 0xFF)) | |
609 { | |
610 switch (dst_format & 0x10FF) | |
611 { | |
612 case AUDIO_U8: | |
613 SNDDBG(("Adding filter: Sound_Convert8\n")); | |
614 cvt->filters[cvt->filter_index++] = Sound_Convert8; | |
615 cvt->len_ratio /= 2; | |
616 break; | |
617 | |
618 case AUDIO_U16LSB: | |
619 SNDDBG(("Adding filter: Sound_Convert16LSB\n")); | |
620 cvt->filters[cvt->filter_index++] = Sound_Convert16LSB; | |
621 cvt->len_mult *= 2; | |
622 cvt->len_ratio *= 2; | |
623 break; | |
624 | |
625 case AUDIO_U16MSB: | |
626 SNDDBG(("Adding filter: Sound_Convert16MSB\n")); | |
627 cvt->filters[cvt->filter_index++] = Sound_Convert16MSB; | |
628 cvt->len_mult *= 2; | |
629 cvt->len_ratio *= 2; | |
630 break; | |
631 } /* switch */ | |
632 } /* if */ | |
633 | |
634 /* Next filter: Mono/Stereo conversion */ | |
635 if (src_channels != dst_channels) | |
636 { | |
637 while ((src_channels * 2) <= dst_channels) | |
638 { | |
639 SNDDBG(("Adding filter: Sound_ConvertStereo\n")); | |
640 cvt->filters[cvt->filter_index++] = Sound_ConvertStereo; | |
641 cvt->len_mult *= 2; | |
642 src_channels *= 2; | |
643 cvt->len_ratio *= 2; | |
644 } /* while */ | |
645 | |
646 /* This assumes that 4 channel audio is in the format: | |
647 * Left {front/back} + Right {front/back} | |
648 * so converting to L/R stereo works properly. | |
649 */ | |
650 while (((src_channels % 2) == 0) && | |
651 ((src_channels / 2) >= dst_channels)) | |
652 { | |
653 SNDDBG(("Adding filter: Sound_ConvertMono\n")); | |
654 cvt->filters[cvt->filter_index++] = Sound_ConvertMono; | |
655 src_channels /= 2; | |
656 cvt->len_ratio /= 2; | |
657 } /* while */ | |
658 | |
659 if ( src_channels != dst_channels ) { | |
660 /* Uh oh.. */; | |
661 } /* if */ | |
662 } /* if */ | |
663 | |
664 /* Do rate conversion */ | |
665 cvt->rate_incr = 0.0; | |
666 if ((src_rate / 100) != (dst_rate / 100)) | |
667 { | |
668 Uint32 hi_rate, lo_rate; | |
669 int len_mult; | |
670 double len_ratio; | |
671 void (*rate_cvt)(Sound_AudioCVT *cvt, Uint16 *format); | |
672 | |
673 if (src_rate > dst_rate) | |
674 { | |
675 hi_rate = src_rate; | |
676 lo_rate = dst_rate; | |
677 SNDDBG(("Adding filter: Sound_RateDIV2\n")); | |
678 rate_cvt = Sound_RateDIV2; | |
679 len_mult = 1; | |
680 len_ratio = 0.5; | |
681 } /* if */ | |
682 else | |
683 { | |
684 hi_rate = dst_rate; | |
685 lo_rate = src_rate; | |
686 SNDDBG(("Adding filter: Sound_RateMUL2\n")); | |
687 rate_cvt = Sound_RateMUL2; | |
688 len_mult = 2; | |
689 len_ratio = 2.0; | |
690 } /* else */ | |
691 | |
692 /* If hi_rate = lo_rate*2^x then conversion is easy */ | |
693 while (((lo_rate * 2) / 100) <= (hi_rate / 100)) | |
694 { | |
695 cvt->filters[cvt->filter_index++] = rate_cvt; | |
696 cvt->len_mult *= len_mult; | |
697 lo_rate *= 2; | |
698 cvt->len_ratio *= len_ratio; | |
699 } /* while */ | |
700 | |
701 /* We may need a slow conversion here to finish up */ | |
702 if ((lo_rate / 100) != (hi_rate / 100)) | |
703 { | |
704 if (src_rate < dst_rate) | |
705 { | |
706 cvt->rate_incr = (double) lo_rate / hi_rate; | |
707 cvt->len_mult *= 2; | |
708 cvt->len_ratio /= cvt->rate_incr; | |
709 } /* if */ | |
710 else | |
711 { | |
712 cvt->rate_incr = (double) hi_rate / lo_rate; | |
713 cvt->len_ratio *= cvt->rate_incr; | |
714 } /* else */ | |
715 SNDDBG(("Adding filter: Sound_RateSLOW\n")); | |
716 cvt->filters[cvt->filter_index++] = Sound_RateSLOW; | |
717 } /* if */ | |
718 } /* if */ | |
719 | |
720 /* Set up the filter information */ | |
721 if (cvt->filter_index != 0) | |
722 { | |
723 cvt->needed = 1; | |
724 cvt->src_format = src_format; | |
725 cvt->dst_format = dst_format; | |
726 cvt->len = 0; | |
727 cvt->buf = NULL; | |
728 cvt->filters[cvt->filter_index] = NULL; | |
729 } /* if */ | |
730 | |
731 return(cvt->needed); | |
732 } /* Sound_BuildAudioCVT */ |