comparison audio_convert.c @ 141:907e3776d2f4

Initial add.
author Ryan C. Gordon <icculus@icculus.org>
date Mon, 15 Oct 2001 20:24:28 +0000
parents
children fbbb1f25b944
comparison
equal deleted inserted replaced
140:c28566f219e2 141:907e3776d2f4
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
48 void Sound_ConvertEndian(Sound_AudioCVT *cvt, Uint16 *format)
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
74 void Sound_ConvertSign(Sound_AudioCVT *cvt, Uint16 *format)
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
111 void Sound_Convert8(Sound_AudioCVT *cvt, Uint16 *format)
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
139 void Sound_Convert16LSB(Sound_AudioCVT *cvt, Uint16 *format)
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
164 void Sound_Convert16MSB(Sound_AudioCVT *cvt, Uint16 *format)
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
189 void Sound_ConvertStereo(Sound_AudioCVT *cvt, Uint16 *format)
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
233 void Sound_ConvertMono(Sound_AudioCVT *cvt, Uint16 *format)
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
389 void Sound_RateMUL2(Sound_AudioCVT *cvt, Uint16 *format)
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
431 void Sound_RateDIV2(Sound_AudioCVT *cvt, Uint16 *format)
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
470 void Sound_RateSLOW(Sound_AudioCVT *cvt, Uint16 *format)
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 {
554 Sound_SetError("No buffer allocated for conversion");
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,
582 Uint16 dst_format, Uint8 dst_channels, Uint32 dst_rate)
583 {
584 /* Start off with no conversion necessary */
585 cvt->needed = 0;
586 cvt->filter_index = 0;
587 cvt->filters[0] = NULL;
588 cvt->len_mult = 1;
589 cvt->len_ratio = 1.0;
590
591 /* First filter: Endian conversion from src to dst */
592 if ((src_format & 0x1000) != (dst_format & 0x1000) &&
593 ((src_format & 0xff) != 8))
594 {
595 SNDDBG(("Adding filter: Sound_ConvertEndian\n"));
596 cvt->filters[cvt->filter_index++] = Sound_ConvertEndian;
597 } /* if */
598
599 /* Second filter: Sign conversion -- signed/unsigned */
600 if ((src_format & 0x8000) != (dst_format & 0x8000))
601 {
602 SNDDBG(("Adding filter: Sound_ConvertSign\n"));
603 cvt->filters[cvt->filter_index++] = Sound_ConvertSign;
604 } /* if */
605
606 /* Next filter: Convert 16 bit <--> 8 bit PCM. */
607 if ((src_format & 0xFF) != (dst_format & 0xFF))
608 {
609 switch (dst_format & 0x10FF)
610 {
611 case AUDIO_U8:
612 SNDDBG(("Adding filter: Sound_Convert8\n"));
613 cvt->filters[cvt->filter_index++] = Sound_Convert8;
614 cvt->len_ratio /= 2;
615 break;
616
617 case AUDIO_U16LSB:
618 SNDDBG(("Adding filter: Sound_Convert16LSB\n"));
619 cvt->filters[cvt->filter_index++] = Sound_Convert16LSB;
620 cvt->len_mult *= 2;
621 cvt->len_ratio *= 2;
622 break;
623
624 case AUDIO_U16MSB:
625 SNDDBG(("Adding filter: Sound_Convert16MSB\n"));
626 cvt->filters[cvt->filter_index++] = Sound_Convert16MSB;
627 cvt->len_mult *= 2;
628 cvt->len_ratio *= 2;
629 break;
630 } /* switch */
631 } /* if */
632
633 /* Next filter: Mono/Stereo conversion */
634 if (src_channels != dst_channels)
635 {
636 while ((src_channels * 2) <= dst_channels)
637 {
638 SNDDBG(("Adding filter: Sound_ConvertStereo\n"));
639 cvt->filters[cvt->filter_index++] = Sound_ConvertStereo;
640 cvt->len_mult *= 2;
641 src_channels *= 2;
642 cvt->len_ratio *= 2;
643 } /* while */
644
645 /* This assumes that 4 channel audio is in the format:
646 * Left {front/back} + Right {front/back}
647 * so converting to L/R stereo works properly.
648 */
649 while (((src_channels % 2) == 0) &&
650 ((src_channels / 2) >= dst_channels))
651 {
652 SNDDBG(("Adding filter: Sound_ConvertMono\n"));
653 cvt->filters[cvt->filter_index++] = Sound_ConvertMono;
654 src_channels /= 2;
655 cvt->len_ratio /= 2;
656 } /* while */
657
658 if ( src_channels != dst_channels ) {
659 /* Uh oh.. */;
660 } /* if */
661 } /* if */
662
663 /* Do rate conversion */
664 cvt->rate_incr = 0.0;
665 if ((src_rate / 100) != (dst_rate / 100))
666 {
667 Uint32 hi_rate, lo_rate;
668 int len_mult;
669 double len_ratio;
670 void (*rate_cvt)(Sound_AudioCVT *cvt, Uint16 *format);
671
672 if (src_rate > dst_rate)
673 {
674 hi_rate = src_rate;
675 lo_rate = dst_rate;
676 SNDDBG(("Adding filter: Sound_RateDIV2\n"));
677 rate_cvt = Sound_RateDIV2;
678 len_mult = 1;
679 len_ratio = 0.5;
680 } /* if */
681 else
682 {
683 hi_rate = dst_rate;
684 lo_rate = src_rate;
685 SNDDBG(("Adding filter: Sound_RateMUL2\n"));
686 rate_cvt = Sound_RateMUL2;
687 len_mult = 2;
688 len_ratio = 2.0;
689 } /* else */
690
691 /* If hi_rate = lo_rate*2^x then conversion is easy */
692 while (((lo_rate * 2) / 100) <= (hi_rate / 100))
693 {
694 cvt->filters[cvt->filter_index++] = rate_cvt;
695 cvt->len_mult *= len_mult;
696 lo_rate *= 2;
697 cvt->len_ratio *= len_ratio;
698 } /* while */
699
700 /* We may need a slow conversion here to finish up */
701 if ((lo_rate / 100) != (hi_rate / 100))
702 {
703 if (src_rate < dst_rate)
704 {
705 cvt->rate_incr = (double) lo_rate / hi_rate;
706 cvt->len_mult *= 2;
707 cvt->len_ratio /= cvt->rate_incr;
708 } /* if */
709 else
710 {
711 cvt->rate_incr = (double) hi_rate / lo_rate;
712 cvt->len_ratio *= cvt->rate_incr;
713 } /* else */
714 SNDDBG(("Adding filter: Sound_RateSLOW\n"));
715 cvt->filters[cvt->filter_index++] = Sound_RateSLOW;
716 } /* if */
717 } /* if */
718
719 /* Set up the filter information */
720 if (cvt->filter_index != 0)
721 {
722 cvt->needed = 1;
723 cvt->src_format = src_format;
724 cvt->dst_format = dst_format;
725 cvt->len = 0;
726 cvt->buf = NULL;
727 cvt->filters[cvt->filter_index] = NULL;
728 } /* if */
729
730 return(cvt->needed);
731 } /* Sound_BuildAudioCVT */