comparison src/audio/SDL_audiocvt.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children e8157fcb3114
comparison
equal deleted inserted replaced
-1:000000000000 0:74212992fb08
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 #ifdef SAVE_RCSID
24 static char rcsid =
25 "@(#) $Id$";
26 #endif
27
28 /* Functions for audio drivers to perform runtime conversion of audio format */
29
30 #include <stdio.h>
31
32 #include "SDL_error.h"
33 #include "SDL_audio.h"
34
35
36 /* Effectively mix right and left channels into a single channel */
37 void SDL_ConvertMono(SDL_AudioCVT *cvt, Uint16 format)
38 {
39 int i;
40 Sint32 sample;
41
42 #ifdef DEBUG_CONVERT
43 fprintf(stderr, "Converting to mono\n");
44 #endif
45 switch (format&0x8018) {
46
47 case AUDIO_U8: {
48 Uint8 *src, *dst;
49
50 src = cvt->buf;
51 dst = cvt->buf;
52 for ( i=cvt->len_cvt/2; i; --i ) {
53 sample = src[0] + src[1];
54 if ( sample > 255 ) {
55 *dst = 255;
56 } else {
57 *dst = sample;
58 }
59 src += 2;
60 dst += 1;
61 }
62 }
63 break;
64
65 case AUDIO_S8: {
66 Sint8 *src, *dst;
67
68 src = (Sint8 *)cvt->buf;
69 dst = (Sint8 *)cvt->buf;
70 for ( i=cvt->len_cvt/2; i; --i ) {
71 sample = src[0] + src[1];
72 if ( sample > 127 ) {
73 *dst = 127;
74 } else
75 if ( sample < -128 ) {
76 *dst = -128;
77 } else {
78 *dst = sample;
79 }
80 src += 2;
81 dst += 1;
82 }
83 }
84 break;
85
86 case AUDIO_U16: {
87 Uint8 *src, *dst;
88
89 src = cvt->buf;
90 dst = cvt->buf;
91 if ( (format & 0x1000) == 0x1000 ) {
92 for ( i=cvt->len_cvt/4; i; --i ) {
93 sample = (Uint16)((src[0]<<8)|src[1])+
94 (Uint16)((src[2]<<8)|src[3]);
95 if ( sample > 65535 ) {
96 dst[0] = 0xFF;
97 dst[1] = 0xFF;
98 } else {
99 dst[1] = (sample&0xFF);
100 sample >>= 8;
101 dst[0] = (sample&0xFF);
102 }
103 src += 4;
104 dst += 2;
105 }
106 } else {
107 for ( i=cvt->len_cvt/4; i; --i ) {
108 sample = (Uint16)((src[1]<<8)|src[0])+
109 (Uint16)((src[3]<<8)|src[2]);
110 if ( sample > 65535 ) {
111 dst[0] = 0xFF;
112 dst[1] = 0xFF;
113 } else {
114 dst[0] = (sample&0xFF);
115 sample >>= 8;
116 dst[1] = (sample&0xFF);
117 }
118 src += 4;
119 dst += 2;
120 }
121 }
122 }
123 break;
124
125 case AUDIO_S16: {
126 Uint8 *src, *dst;
127
128 src = cvt->buf;
129 dst = cvt->buf;
130 if ( (format & 0x1000) == 0x1000 ) {
131 for ( i=cvt->len_cvt/4; i; --i ) {
132 sample = (Sint16)((src[0]<<8)|src[1])+
133 (Sint16)((src[2]<<8)|src[3]);
134 if ( sample > 32767 ) {
135 dst[0] = 0x7F;
136 dst[1] = 0xFF;
137 } else
138 if ( sample < -32768 ) {
139 dst[0] = 0x80;
140 dst[1] = 0x00;
141 } else {
142 dst[1] = (sample&0xFF);
143 sample >>= 8;
144 dst[0] = (sample&0xFF);
145 }
146 src += 4;
147 dst += 2;
148 }
149 } else {
150 for ( i=cvt->len_cvt/4; i; --i ) {
151 sample = (Sint16)((src[1]<<8)|src[0])+
152 (Sint16)((src[3]<<8)|src[2]);
153 if ( sample > 32767 ) {
154 dst[1] = 0x7F;
155 dst[0] = 0xFF;
156 } else
157 if ( sample < -32768 ) {
158 dst[1] = 0x80;
159 dst[0] = 0x00;
160 } else {
161 dst[0] = (sample&0xFF);
162 sample >>= 8;
163 dst[1] = (sample&0xFF);
164 }
165 src += 4;
166 dst += 2;
167 }
168 }
169 }
170 break;
171 }
172 cvt->len_cvt /= 2;
173 if ( cvt->filters[++cvt->filter_index] ) {
174 cvt->filters[cvt->filter_index](cvt, format);
175 }
176 }
177
178
179 /* Duplicate a mono channel to both stereo channels */
180 void SDL_ConvertStereo(SDL_AudioCVT *cvt, Uint16 format)
181 {
182 int i;
183
184 #ifdef DEBUG_CONVERT
185 fprintf(stderr, "Converting to stereo\n");
186 #endif
187 if ( (format & 0xFF) == 16 ) {
188 Uint16 *src, *dst;
189
190 src = (Uint16 *)(cvt->buf+cvt->len_cvt);
191 dst = (Uint16 *)(cvt->buf+cvt->len_cvt*2);
192 for ( i=cvt->len_cvt/2; i; --i ) {
193 dst -= 2;
194 src -= 1;
195 dst[0] = src[0];
196 dst[1] = src[0];
197 }
198 } else {
199 Uint8 *src, *dst;
200
201 src = cvt->buf+cvt->len_cvt;
202 dst = cvt->buf+cvt->len_cvt*2;
203 for ( i=cvt->len_cvt; i; --i ) {
204 dst -= 2;
205 src -= 1;
206 dst[0] = src[0];
207 dst[1] = src[0];
208 }
209 }
210 cvt->len_cvt *= 2;
211 if ( cvt->filters[++cvt->filter_index] ) {
212 cvt->filters[cvt->filter_index](cvt, format);
213 }
214 }
215
216 /* Convert 8-bit to 16-bit - LSB */
217 void SDL_Convert16LSB(SDL_AudioCVT *cvt, Uint16 format)
218 {
219 int i;
220 Uint8 *src, *dst;
221
222 #ifdef DEBUG_CONVERT
223 fprintf(stderr, "Converting to 16-bit LSB\n");
224 #endif
225 src = cvt->buf+cvt->len_cvt;
226 dst = cvt->buf+cvt->len_cvt*2;
227 for ( i=cvt->len_cvt; i; --i ) {
228 src -= 1;
229 dst -= 2;
230 dst[1] = *src;
231 dst[0] = 0;
232 }
233 format = ((format & ~0x0008) | AUDIO_U16LSB);
234 cvt->len_cvt *= 2;
235 if ( cvt->filters[++cvt->filter_index] ) {
236 cvt->filters[cvt->filter_index](cvt, format);
237 }
238 }
239 /* Convert 8-bit to 16-bit - MSB */
240 void SDL_Convert16MSB(SDL_AudioCVT *cvt, Uint16 format)
241 {
242 int i;
243 Uint8 *src, *dst;
244
245 #ifdef DEBUG_CONVERT
246 fprintf(stderr, "Converting to 16-bit MSB\n");
247 #endif
248 src = cvt->buf+cvt->len_cvt;
249 dst = cvt->buf+cvt->len_cvt*2;
250 for ( i=cvt->len_cvt; i; --i ) {
251 src -= 1;
252 dst -= 2;
253 dst[0] = *src;
254 dst[1] = 0;
255 }
256 format = ((format & ~0x0008) | AUDIO_U16MSB);
257 cvt->len_cvt *= 2;
258 if ( cvt->filters[++cvt->filter_index] ) {
259 cvt->filters[cvt->filter_index](cvt, format);
260 }
261 }
262
263 /* Convert 16-bit to 8-bit */
264 void SDL_Convert8(SDL_AudioCVT *cvt, Uint16 format)
265 {
266 int i;
267 Uint8 *src, *dst;
268
269 #ifdef DEBUG_CONVERT
270 fprintf(stderr, "Converting to 8-bit\n");
271 #endif
272 src = cvt->buf;
273 dst = cvt->buf;
274 if ( (format & 0x1000) != 0x1000 ) { /* Little endian */
275 ++src;
276 }
277 for ( i=cvt->len_cvt/2; i; --i ) {
278 *dst = *src;
279 src += 2;
280 dst += 1;
281 }
282 format = ((format & ~0x9010) | AUDIO_U8);
283 cvt->len_cvt /= 2;
284 if ( cvt->filters[++cvt->filter_index] ) {
285 cvt->filters[cvt->filter_index](cvt, format);
286 }
287 }
288
289 /* Toggle signed/unsigned */
290 void SDL_ConvertSign(SDL_AudioCVT *cvt, Uint16 format)
291 {
292 int i;
293 Uint8 *data;
294
295 #ifdef DEBUG_CONVERT
296 fprintf(stderr, "Converting audio signedness\n");
297 #endif
298 data = cvt->buf;
299 if ( (format & 0xFF) == 16 ) {
300 if ( (format & 0x1000) != 0x1000 ) { /* Little endian */
301 ++data;
302 }
303 for ( i=cvt->len_cvt/2; i; --i ) {
304 *data ^= 0x80;
305 data += 2;
306 }
307 } else {
308 for ( i=cvt->len_cvt; i; --i ) {
309 *data++ ^= 0x80;
310 }
311 }
312 format = (format ^ 0x8000);
313 if ( cvt->filters[++cvt->filter_index] ) {
314 cvt->filters[cvt->filter_index](cvt, format);
315 }
316 }
317
318 /* Toggle endianness */
319 void SDL_ConvertEndian(SDL_AudioCVT *cvt, Uint16 format)
320 {
321 int i;
322 Uint8 *data, tmp;
323
324 #ifdef DEBUG_CONVERT
325 fprintf(stderr, "Converting audio endianness\n");
326 #endif
327 data = cvt->buf;
328 for ( i=cvt->len_cvt/2; i; --i ) {
329 tmp = data[0];
330 data[0] = data[1];
331 data[1] = tmp;
332 data += 2;
333 }
334 format = (format ^ 0x1000);
335 if ( cvt->filters[++cvt->filter_index] ) {
336 cvt->filters[cvt->filter_index](cvt, format);
337 }
338 }
339
340 /* Convert rate up by multiple of 2 */
341 void SDL_RateMUL2(SDL_AudioCVT *cvt, Uint16 format)
342 {
343 int i;
344 Uint8 *src, *dst;
345
346 #ifdef DEBUG_CONVERT
347 fprintf(stderr, "Converting audio rate * 2\n");
348 #endif
349 src = cvt->buf+cvt->len_cvt;
350 dst = cvt->buf+cvt->len_cvt*2;
351 switch (format & 0xFF) {
352 case 8:
353 for ( i=cvt->len_cvt; i; --i ) {
354 src -= 1;
355 dst -= 2;
356 dst[0] = src[0];
357 dst[1] = src[0];
358 }
359 break;
360 case 16:
361 for ( i=cvt->len_cvt/2; i; --i ) {
362 src -= 2;
363 dst -= 4;
364 dst[0] = src[0];
365 dst[1] = src[1];
366 dst[2] = src[0];
367 dst[3] = src[1];
368 }
369 break;
370 }
371 cvt->len_cvt *= 2;
372 if ( cvt->filters[++cvt->filter_index] ) {
373 cvt->filters[cvt->filter_index](cvt, format);
374 }
375 }
376
377 /* Convert rate down by multiple of 2 */
378 void SDL_RateDIV2(SDL_AudioCVT *cvt, Uint16 format)
379 {
380 int i;
381 Uint8 *src, *dst;
382
383 #ifdef DEBUG_CONVERT
384 fprintf(stderr, "Converting audio rate / 2\n");
385 #endif
386 src = cvt->buf;
387 dst = cvt->buf;
388 switch (format & 0xFF) {
389 case 8:
390 for ( i=cvt->len_cvt/2; i; --i ) {
391 dst[0] = src[0];
392 src += 2;
393 dst += 1;
394 }
395 break;
396 case 16:
397 for ( i=cvt->len_cvt/4; i; --i ) {
398 dst[0] = src[0];
399 dst[1] = src[1];
400 src += 4;
401 dst += 2;
402 }
403 break;
404 }
405 cvt->len_cvt /= 2;
406 if ( cvt->filters[++cvt->filter_index] ) {
407 cvt->filters[cvt->filter_index](cvt, format);
408 }
409 }
410
411 /* Very slow rate conversion routine */
412 void SDL_RateSLOW(SDL_AudioCVT *cvt, Uint16 format)
413 {
414 double ipos;
415 int i, clen;
416
417 #ifdef DEBUG_CONVERT
418 fprintf(stderr, "Converting audio rate * %4.4f\n", 1.0/cvt->rate_incr);
419 #endif
420 clen = (int)((double)cvt->len_cvt / cvt->rate_incr);
421 if ( cvt->rate_incr > 1.0 ) {
422 switch (format & 0xFF) {
423 case 8: {
424 Uint8 *output;
425
426 output = cvt->buf;
427 ipos = 0.0;
428 for ( i=clen; i; --i ) {
429 *output = cvt->buf[(int)ipos];
430 ipos += cvt->rate_incr;
431 output += 1;
432 }
433 }
434 break;
435
436 case 16: {
437 Uint16 *output;
438
439 clen &= ~1;
440 output = (Uint16 *)cvt->buf;
441 ipos = 0.0;
442 for ( i=clen/2; i; --i ) {
443 *output=((Uint16 *)cvt->buf)[(int)ipos];
444 ipos += cvt->rate_incr;
445 output += 1;
446 }
447 }
448 break;
449 }
450 } else {
451 switch (format & 0xFF) {
452 case 8: {
453 Uint8 *output;
454
455 output = cvt->buf+clen;
456 ipos = (double)cvt->len_cvt;
457 for ( i=clen; i; --i ) {
458 ipos -= cvt->rate_incr;
459 output -= 1;
460 *output = cvt->buf[(int)ipos];
461 }
462 }
463 break;
464
465 case 16: {
466 Uint16 *output;
467
468 clen &= ~1;
469 output = (Uint16 *)(cvt->buf+clen);
470 ipos = (double)cvt->len_cvt/2;
471 for ( i=clen/2; i; --i ) {
472 ipos -= cvt->rate_incr;
473 output -= 1;
474 *output=((Uint16 *)cvt->buf)[(int)ipos];
475 }
476 }
477 break;
478 }
479 }
480 cvt->len_cvt = clen;
481 if ( cvt->filters[++cvt->filter_index] ) {
482 cvt->filters[cvt->filter_index](cvt, format);
483 }
484 }
485
486 int SDL_ConvertAudio(SDL_AudioCVT *cvt)
487 {
488 /* Make sure there's data to convert */
489 if ( cvt->buf == NULL ) {
490 SDL_SetError("No buffer allocated for conversion");
491 return(-1);
492 }
493 /* Return okay if no conversion is necessary */
494 cvt->len_cvt = cvt->len;
495 if ( cvt->filters[0] == NULL ) {
496 return(0);
497 }
498
499 /* Set up the conversion and go! */
500 cvt->filter_index = 0;
501 cvt->filters[0](cvt, cvt->src_format);
502 return(0);
503 }
504
505 /* Creates a set of audio filters to convert from one format to another.
506 Returns -1 if the format conversion is not supported, or 1 if the
507 audio filter is set up.
508 */
509
510 int SDL_BuildAudioCVT(SDL_AudioCVT *cvt,
511 Uint16 src_format, Uint8 src_channels, int src_rate,
512 Uint16 dst_format, Uint8 dst_channels, int dst_rate)
513 {
514 /* Start off with no conversion necessary */
515 cvt->needed = 0;
516 cvt->filter_index = 0;
517 cvt->filters[0] = NULL;
518 cvt->len_mult = 1;
519 cvt->len_ratio = 1.0;
520
521 /* First filter: Endian conversion from src to dst */
522 if ( (src_format & 0x1000) != (dst_format & 0x1000)
523 && ((src_format & 0xff) != 8) ) {
524 cvt->filters[cvt->filter_index++] = SDL_ConvertEndian;
525 }
526
527 /* Second filter: Sign conversion -- signed/unsigned */
528 if ( (src_format & 0x8000) != (dst_format & 0x8000) ) {
529 cvt->filters[cvt->filter_index++] = SDL_ConvertSign;
530 }
531
532 /* Next filter: Convert 16 bit <--> 8 bit PCM */
533 if ( (src_format & 0xFF) != (dst_format & 0xFF) ) {
534 switch (dst_format&0x10FF) {
535 case AUDIO_U8:
536 cvt->filters[cvt->filter_index++] =
537 SDL_Convert8;
538 cvt->len_ratio /= 2;
539 break;
540 case AUDIO_U16LSB:
541 cvt->filters[cvt->filter_index++] =
542 SDL_Convert16LSB;
543 cvt->len_mult *= 2;
544 cvt->len_ratio *= 2;
545 break;
546 case AUDIO_U16MSB:
547 cvt->filters[cvt->filter_index++] =
548 SDL_Convert16MSB;
549 cvt->len_mult *= 2;
550 cvt->len_ratio *= 2;
551 break;
552 }
553 }
554
555 /* Last filter: Mono/Stereo conversion */
556 if ( src_channels != dst_channels ) {
557 while ( (src_channels*2) <= dst_channels ) {
558 cvt->filters[cvt->filter_index++] =
559 SDL_ConvertStereo;
560 cvt->len_mult *= 2;
561 src_channels *= 2;
562 cvt->len_ratio *= 2;
563 }
564 /* This assumes that 4 channel audio is in the format:
565 Left {front/back} + Right {front/back}
566 so converting to L/R stereo works properly.
567 */
568 while ( ((src_channels%2) == 0) &&
569 ((src_channels/2) >= dst_channels) ) {
570 cvt->filters[cvt->filter_index++] =
571 SDL_ConvertMono;
572 src_channels /= 2;
573 cvt->len_ratio /= 2;
574 }
575 if ( src_channels != dst_channels ) {
576 /* Uh oh.. */;
577 }
578 }
579
580 /* Do rate conversion */
581 cvt->rate_incr = 0.0;
582 if ( (src_rate/100) != (dst_rate/100) ) {
583 Uint32 hi_rate, lo_rate;
584 int len_mult;
585 double len_ratio;
586 void (*rate_cvt)(SDL_AudioCVT *cvt, Uint16 format);
587
588 if ( src_rate > dst_rate ) {
589 hi_rate = src_rate;
590 lo_rate = dst_rate;
591 rate_cvt = SDL_RateDIV2;
592 len_mult = 1;
593 len_ratio = 0.5;
594 } else {
595 hi_rate = dst_rate;
596 lo_rate = src_rate;
597 rate_cvt = SDL_RateMUL2;
598 len_mult = 2;
599 len_ratio = 2.0;
600 }
601 /* If hi_rate = lo_rate*2^x then conversion is easy */
602 while ( ((lo_rate*2)/100) <= (hi_rate/100) ) {
603 cvt->filters[cvt->filter_index++] = rate_cvt;
604 cvt->len_mult *= len_mult;
605 lo_rate *= 2;
606 cvt->len_ratio *= len_ratio;
607 }
608 /* We may need a slow conversion here to finish up */
609 if ( (lo_rate/100) != (hi_rate/100) ) {
610 #if 1
611 /* The problem with this is that if the input buffer is
612 say 1K, and the conversion rate is say 1.1, then the
613 output buffer is 1.1K, which may not be an acceptable
614 buffer size for the audio driver (not a power of 2)
615 */
616 /* For now, punt and hope the rate distortion isn't great.
617 */
618 #else
619 if ( src_rate < dst_rate ) {
620 cvt->rate_incr = (double)lo_rate/hi_rate;
621 cvt->len_mult *= 2;
622 cvt->len_ratio /= cvt->rate_incr;
623 } else {
624 cvt->rate_incr = (double)hi_rate/lo_rate;
625 cvt->len_ratio *= cvt->rate_incr;
626 }
627 cvt->filters[cvt->filter_index++] = SDL_RateSLOW;
628 #endif
629 }
630 }
631
632 /* Set up the filter information */
633 if ( cvt->filter_index != 0 ) {
634 cvt->needed = 1;
635 cvt->src_format = src_format;
636 cvt->dst_format = dst_format;
637 cvt->len = 0;
638 cvt->buf = NULL;
639 cvt->filters[cvt->filter_index] = NULL;
640 }
641 return(cvt->needed);
642 }