2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
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.
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.
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
28 /* Functions for audio drivers to perform runtime conversion of audio format */
32 #include "SDL_error.h"
33 #include "SDL_audio.h"
36 /* Effectively mix right and left channels into a single channel */
37 void SDL_ConvertMono(SDL_AudioCVT
*cvt
, Uint16 format
)
43 fprintf(stderr
, "Converting to mono\n");
45 switch (format
&0x8018) {
52 for ( i
=cvt
->len_cvt
/2; i
; --i
) {
53 sample
= src
[0] + src
[1];
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];
75 if ( sample
< -128 ) {
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 ) {
99 dst
[1] = (sample
&0xFF);
101 dst
[0] = (sample
&0xFF);
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 ) {
114 dst
[0] = (sample
&0xFF);
116 dst
[1] = (sample
&0xFF);
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 ) {
138 if ( sample
< -32768 ) {
142 dst
[1] = (sample
&0xFF);
144 dst
[0] = (sample
&0xFF);
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 ) {
157 if ( sample
< -32768 ) {
161 dst
[0] = (sample
&0xFF);
163 dst
[1] = (sample
&0xFF);
173 if ( cvt
->filters
[++cvt
->filter_index
] ) {
174 cvt
->filters
[cvt
->filter_index
](cvt
, format
);
179 /* Duplicate a mono channel to both stereo channels */
180 void SDL_ConvertStereo(SDL_AudioCVT
*cvt
, Uint16 format
)
185 fprintf(stderr
, "Converting to stereo\n");
187 if ( (format
& 0xFF) == 16 ) {
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
) {
201 src
= cvt
->buf
+cvt
->len_cvt
;
202 dst
= cvt
->buf
+cvt
->len_cvt
*2;
203 for ( i
=cvt
->len_cvt
; i
; --i
) {
211 if ( cvt
->filters
[++cvt
->filter_index
] ) {
212 cvt
->filters
[cvt
->filter_index
](cvt
, format
);
216 /* Convert 8-bit to 16-bit - LSB */
217 void SDL_Convert16LSB(SDL_AudioCVT
*cvt
, Uint16 format
)
223 fprintf(stderr
, "Converting to 16-bit LSB\n");
225 src
= cvt
->buf
+cvt
->len_cvt
;
226 dst
= cvt
->buf
+cvt
->len_cvt
*2;
227 for ( i
=cvt
->len_cvt
; i
; --i
) {
233 format
= ((format
& ~0x0008) | AUDIO_U16LSB
);
235 if ( cvt
->filters
[++cvt
->filter_index
] ) {
236 cvt
->filters
[cvt
->filter_index
](cvt
, format
);
239 /* Convert 8-bit to 16-bit - MSB */
240 void SDL_Convert16MSB(SDL_AudioCVT
*cvt
, Uint16 format
)
246 fprintf(stderr
, "Converting to 16-bit MSB\n");
248 src
= cvt
->buf
+cvt
->len_cvt
;
249 dst
= cvt
->buf
+cvt
->len_cvt
*2;
250 for ( i
=cvt
->len_cvt
; i
; --i
) {
256 format
= ((format
& ~0x0008) | AUDIO_U16MSB
);
258 if ( cvt
->filters
[++cvt
->filter_index
] ) {
259 cvt
->filters
[cvt
->filter_index
](cvt
, format
);
263 /* Convert 16-bit to 8-bit */
264 void SDL_Convert8(SDL_AudioCVT
*cvt
, Uint16 format
)
270 fprintf(stderr
, "Converting to 8-bit\n");
274 if ( (format
& 0x1000) != 0x1000 ) { /* Little endian */
277 for ( i
=cvt
->len_cvt
/2; i
; --i
) {
282 format
= ((format
& ~0x9010) | AUDIO_U8
);
284 if ( cvt
->filters
[++cvt
->filter_index
] ) {
285 cvt
->filters
[cvt
->filter_index
](cvt
, format
);
289 /* Toggle signed/unsigned */
290 void SDL_ConvertSign(SDL_AudioCVT
*cvt
, Uint16 format
)
296 fprintf(stderr
, "Converting audio signedness\n");
299 if ( (format
& 0xFF) == 16 ) {
300 if ( (format
& 0x1000) != 0x1000 ) { /* Little endian */
303 for ( i
=cvt
->len_cvt
/2; i
; --i
) {
308 for ( i
=cvt
->len_cvt
; i
; --i
) {
312 format
= (format
^ 0x8000);
313 if ( cvt
->filters
[++cvt
->filter_index
] ) {
314 cvt
->filters
[cvt
->filter_index
](cvt
, format
);
318 /* Toggle endianness */
319 void SDL_ConvertEndian(SDL_AudioCVT
*cvt
, Uint16 format
)
325 fprintf(stderr
, "Converting audio endianness\n");
328 for ( i
=cvt
->len_cvt
/2; i
; --i
) {
334 format
= (format
^ 0x1000);
335 if ( cvt
->filters
[++cvt
->filter_index
] ) {
336 cvt
->filters
[cvt
->filter_index
](cvt
, format
);
340 /* Convert rate up by multiple of 2 */
341 void SDL_RateMUL2(SDL_AudioCVT
*cvt
, Uint16 format
)
347 fprintf(stderr
, "Converting audio rate * 2\n");
349 src
= cvt
->buf
+cvt
->len_cvt
;
350 dst
= cvt
->buf
+cvt
->len_cvt
*2;
351 switch (format
& 0xFF) {
353 for ( i
=cvt
->len_cvt
; i
; --i
) {
361 for ( i
=cvt
->len_cvt
/2; i
; --i
) {
372 if ( cvt
->filters
[++cvt
->filter_index
] ) {
373 cvt
->filters
[cvt
->filter_index
](cvt
, format
);
377 /* Convert rate down by multiple of 2 */
378 void SDL_RateDIV2(SDL_AudioCVT
*cvt
, Uint16 format
)
384 fprintf(stderr
, "Converting audio rate / 2\n");
388 switch (format
& 0xFF) {
390 for ( i
=cvt
->len_cvt
/2; i
; --i
) {
397 for ( i
=cvt
->len_cvt
/4; i
; --i
) {
406 if ( cvt
->filters
[++cvt
->filter_index
] ) {
407 cvt
->filters
[cvt
->filter_index
](cvt
, format
);
411 /* Very slow rate conversion routine */
412 void SDL_RateSLOW(SDL_AudioCVT
*cvt
, Uint16 format
)
418 fprintf(stderr
, "Converting audio rate * %4.4f\n", 1.0/cvt
->rate_incr
);
420 clen
= (int)((double)cvt
->len_cvt
/ cvt
->rate_incr
);
421 if ( cvt
->rate_incr
> 1.0 ) {
422 switch (format
& 0xFF) {
428 for ( i
=clen
; i
; --i
) {
429 *output
= cvt
->buf
[(int)ipos
];
430 ipos
+= cvt
->rate_incr
;
440 output
= (Uint16
*)cvt
->buf
;
442 for ( i
=clen
/2; i
; --i
) {
443 *output
=((Uint16
*)cvt
->buf
)[(int)ipos
];
444 ipos
+= cvt
->rate_incr
;
451 switch (format
& 0xFF) {
455 output
= cvt
->buf
+clen
;
456 ipos
= (double)cvt
->len_cvt
;
457 for ( i
=clen
; i
; --i
) {
458 ipos
-= cvt
->rate_incr
;
460 *output
= cvt
->buf
[(int)ipos
];
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
;
474 *output
=((Uint16
*)cvt
->buf
)[(int)ipos
];
481 if ( cvt
->filters
[++cvt
->filter_index
] ) {
482 cvt
->filters
[cvt
->filter_index
](cvt
, format
);
486 int SDL_ConvertAudio(SDL_AudioCVT
*cvt
)
488 /* Make sure there's data to convert */
489 if ( cvt
->buf
== NULL
) {
490 SDL_SetError("No buffer allocated for conversion");
493 /* Return okay if no conversion is necessary */
494 cvt
->len_cvt
= cvt
->len
;
495 if ( cvt
->filters
[0] == NULL
) {
499 /* Set up the conversion and go! */
500 cvt
->filter_index
= 0;
501 cvt
->filters
[0](cvt
, cvt
->src_format
);
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.
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
)
514 /* Start off with no conversion necessary */
516 cvt
->filter_index
= 0;
517 cvt
->filters
[0] = NULL
;
519 cvt
->len_ratio
= 1.0;
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
;
527 /* Second filter: Sign conversion -- signed/unsigned */
528 if ( (src_format
& 0x8000) != (dst_format
& 0x8000) ) {
529 cvt
->filters
[cvt
->filter_index
++] = SDL_ConvertSign
;
532 /* Next filter: Convert 16 bit <--> 8 bit PCM */
533 if ( (src_format
& 0xFF) != (dst_format
& 0xFF) ) {
534 switch (dst_format
&0x10FF) {
536 cvt
->filters
[cvt
->filter_index
++] =
541 cvt
->filters
[cvt
->filter_index
++] =
547 cvt
->filters
[cvt
->filter_index
++] =
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
++] =
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.
568 while ( ((src_channels
%2) == 0) &&
569 ((src_channels
/2) >= dst_channels
) ) {
570 cvt
->filters
[cvt
->filter_index
++] =
575 if ( src_channels
!= dst_channels
) {
580 /* Do rate conversion */
581 cvt
->rate_incr
= 0.0;
582 if ( (src_rate
/100) != (dst_rate
/100) ) {
583 Uint32 hi_rate
, lo_rate
;
586 void (*rate_cvt
)(SDL_AudioCVT
*cvt
, Uint16 format
);
588 if ( src_rate
> dst_rate
) {
591 rate_cvt
= SDL_RateDIV2
;
597 rate_cvt
= SDL_RateMUL2
;
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
;
606 cvt
->len_ratio
*= len_ratio
;
608 /* We may need a slow conversion here to finish up */
609 if ( (lo_rate
/100) != (hi_rate
/100) ) {
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)
616 /* For now, punt and hope the rate distortion isn't great.
619 if ( src_rate
< dst_rate
) {
620 cvt
->rate_incr
= (double)lo_rate
/hi_rate
;
622 cvt
->len_ratio
/= cvt
->rate_incr
;
624 cvt
->rate_incr
= (double)hi_rate
/lo_rate
;
625 cvt
->len_ratio
*= cvt
->rate_incr
;
627 cvt
->filters
[cvt
->filter_index
++] = SDL_RateSLOW
;
632 /* Set up the filter information */
633 if ( cvt
->filter_index
!= 0 ) {
635 cvt
->src_format
= src_format
;
636 cvt
->dst_format
= dst_format
;
639 cvt
->filters
[cvt
->filter_index
] = NULL
;