comparison src/audio/SDL_audiocvt.c @ 942:41a59de7f2ed

Here are patches for SDL12 and SDL_mixer for 4 or 6 channel surround sound on Linux using the Alsa driver. To use them, naturally you need a sound card that will do 4 or 6 channels and probably also a recent version of the Alsa drivers and library. Since the only SDL output driver that knows about surround sound is the Alsa driver, you���ll want to choose it, using: export SDL_AUDIODRIVER=alsa There are no syntactic changes to the programming API. No new library calls, no differences in arguments. There are two semantic changes: (1) For library calls with number of channels as an argument, formerly you could use only 1 or 2 for the number of channels. Now you can also use 4 or 6. (2) The two "left" and "right" arguments to Mix_SetPanning, for the case of 4 or 6 channels, no longer simply control the volumes of the left and right channels. Now the "left" argument is converted to an angle and Mix_SetPosition is called, and the "right" argu- ment is ignored. With two exceptions, so far as I know, the modified SDL12 and SDL_mixer work the same way as the original versions, when opened for 1 or 2 channel output. The two exceptions are bugs which I fixed. Well, the first, anyway, is a bug for sure. When rate conversions up or down by a factor of two are applied (in src/audio/SDL_audiocvt.c), streams with different numbers of channels (that is, mono and stereo) are treated the same way: either each sample is copied or every other sample is omitted. This is ok for mono, but for stereo, it is frames that should be copied or omitted, where by "frame" I mean a portion of the stream containing one sample for each channel. (In the SDL source, confusingly, sometimes frames are called "samples".) So for these rate conversions, stereo streams have to be treated differently, and they are, in my modified version. The other problem that might be characterized as a bug arises when SDL_mixer is passed a multichannel chunk which does not have an integral number of frames. Due to the way the effect_position code loops over frames, when the chunk ends with a partial frame, memory outside the chunk buffer will be accessed. In the case of stereo, it���s possible that because malloc may give more memory than requested, this potential problem never actually causes a segment fault. I don���t know. For 6 channel chunks, I do know, and it does cause segment faults. If SDL_mixer is passed defective chunks and this causes a segment fault, arguably, that���s not a bug in SDL_mixer. Still, whether or not it counts as a bug, it���s easy to protect against, so why not? I added code in mixer.c to discard any partial frame at the end of a chunk. Then what about when SDL or SDL_mixer is opened for 4 or 6 chan- nel output? What happens with the parts of the current library designed for stereo? I don���t know whether I���ve covered all the bases, but I���ve tried: (1) For playing 2 channel waves, or other cases where SDL knows it has to match up a 2 channel source with a 4 or 6 channel output, I���ve added code in SDL_audiocvt.c to make the necessary conversions. (2) For playing midis using timidity, I���ve converted timidity to do 4 or 6 channel output, upon request. (3) For playing mods using mikmod, I put ad hoc code in music.c to convert the stereo output that mikmod produces to 4 or 6 chan- nels. Obviously it would be better to change the mikmod code to mix down into 4 or 6 channels, but I have a hard time following the code in mikmod, so I didn���t do that. (4) For playing mp3s, I put ad hoc code in smpeg to copy channels in the case when 4 or 6 channel output is needed. (5) There seems to be no problem with .ogg files - stereo .oggs can be up converted as .wavs are. (6) The effect_position code in SDL_mixer is now generalized to in- clude the cases of 4 and 6 channel streams. I���ve done a very limited amount of compatibility testing for some of the games using SDL I happen to have. For details, see the file TESTS. I���ve put into a separate archive, Surround-SDL-testfiles.tgz, a couple of 6 channel wave files for testing and a 6 channel ogg file. If you have the right hardware and version of Alsa, you should be able to play the wave files with the Alsa utility aplay (and hear all channels, except maybe lfe, for chan-id.wav, since it���s rather faint). Don���t expect aplay to give good sound, though. There���s something wrong with the current version of aplay. The canyon.ogg file is to test loading of 6 channel oggs. After patching and compiling, you can play it with playmus. (My version of ogg123 will not play it, and I had to patch mplayer to get it to play 6 channel oggs.) Greg Lee <greg@ling.lll.hawaii.edu> Thus, July 1, 2004
author Sam Lantinga <slouken@libsdl.org>
date Sat, 21 Aug 2004 12:27:02 +0000
parents b8d311d90021
children 4095d9ca23f2
comparison
equal deleted inserted replaced
941:5095c4a264aa 942:41a59de7f2ed
173 if ( cvt->filters[++cvt->filter_index] ) { 173 if ( cvt->filters[++cvt->filter_index] ) {
174 cvt->filters[cvt->filter_index](cvt, format); 174 cvt->filters[cvt->filter_index](cvt, format);
175 } 175 }
176 } 176 }
177 177
178 /* Discard top 4 channels */
179 void SDL_ConvertStrip(SDL_AudioCVT *cvt, Uint16 format)
180 {
181 int i;
182 Sint32 lsample, rsample;
183
184 #ifdef DEBUG_CONVERT
185 fprintf(stderr, "Converting down to stereo\n");
186 #endif
187 switch (format&0x8018) {
188
189 case AUDIO_U8: {
190 Uint8 *src, *dst;
191
192 src = cvt->buf;
193 dst = cvt->buf;
194 for ( i=cvt->len_cvt/6; i; --i ) {
195 lsample = src[0];
196 rsample = src[1];
197 dst[0] = lsample;
198 dst[1] = rsample;
199 src += 6;
200 dst += 2;
201 }
202 }
203 break;
204
205 case AUDIO_S8: {
206 Sint8 *src, *dst;
207
208 src = (Sint8 *)cvt->buf;
209 dst = (Sint8 *)cvt->buf;
210 for ( i=cvt->len_cvt/6; i; --i ) {
211 lsample = src[0];
212 rsample = src[1];
213 dst[0] = lsample;
214 dst[1] = rsample;
215 src += 6;
216 dst += 2;
217 }
218 }
219 break;
220
221 case AUDIO_U16: {
222 Uint8 *src, *dst;
223
224 src = cvt->buf;
225 dst = cvt->buf;
226 if ( (format & 0x1000) == 0x1000 ) {
227 for ( i=cvt->len_cvt/12; i; --i ) {
228 lsample = (Uint16)((src[0]<<8)|src[1]);
229 rsample = (Uint16)((src[2]<<8)|src[3]);
230 dst[1] = (lsample&0xFF);
231 lsample >>= 8;
232 dst[0] = (lsample&0xFF);
233 dst[3] = (rsample&0xFF);
234 rsample >>= 8;
235 dst[2] = (rsample&0xFF);
236 src += 12;
237 dst += 4;
238 }
239 } else {
240 for ( i=cvt->len_cvt/12; i; --i ) {
241 lsample = (Uint16)((src[1]<<8)|src[0]);
242 rsample = (Uint16)((src[3]<<8)|src[2]);
243 dst[0] = (lsample&0xFF);
244 lsample >>= 8;
245 dst[1] = (lsample&0xFF);
246 dst[2] = (rsample&0xFF);
247 rsample >>= 8;
248 dst[3] = (rsample&0xFF);
249 src += 12;
250 dst += 4;
251 }
252 }
253 }
254 break;
255
256 case AUDIO_S16: {
257 Uint8 *src, *dst;
258
259 src = cvt->buf;
260 dst = cvt->buf;
261 if ( (format & 0x1000) == 0x1000 ) {
262 for ( i=cvt->len_cvt/12; i; --i ) {
263 lsample = (Sint16)((src[0]<<8)|src[1]);
264 rsample = (Sint16)((src[2]<<8)|src[3]);
265 dst[1] = (lsample&0xFF);
266 lsample >>= 8;
267 dst[0] = (lsample&0xFF);
268 dst[3] = (rsample&0xFF);
269 rsample >>= 8;
270 dst[2] = (rsample&0xFF);
271 src += 12;
272 dst += 4;
273 }
274 } else {
275 for ( i=cvt->len_cvt/12; i; --i ) {
276 lsample = (Sint16)((src[1]<<8)|src[0]);
277 rsample = (Sint16)((src[3]<<8)|src[2]);
278 dst[0] = (lsample&0xFF);
279 lsample >>= 8;
280 dst[1] = (lsample&0xFF);
281 dst[2] = (rsample&0xFF);
282 rsample >>= 8;
283 dst[3] = (rsample&0xFF);
284 src += 12;
285 dst += 4;
286 }
287 }
288 }
289 break;
290 }
291 cvt->len_cvt /= 3;
292 if ( cvt->filters[++cvt->filter_index] ) {
293 cvt->filters[cvt->filter_index](cvt, format);
294 }
295 }
296
297
298 /* Discard top 2 channels of 6 */
299 void SDL_ConvertStrip_2(SDL_AudioCVT *cvt, Uint16 format)
300 {
301 int i;
302 Sint32 lsample, rsample;
303
304 #ifdef DEBUG_CONVERT
305 fprintf(stderr, "Converting 6 down to quad\n");
306 #endif
307 switch (format&0x8018) {
308
309 case AUDIO_U8: {
310 Uint8 *src, *dst;
311
312 src = cvt->buf;
313 dst = cvt->buf;
314 for ( i=cvt->len_cvt/4; i; --i ) {
315 lsample = src[0];
316 rsample = src[1];
317 dst[0] = lsample;
318 dst[1] = rsample;
319 src += 4;
320 dst += 2;
321 }
322 }
323 break;
324
325 case AUDIO_S8: {
326 Sint8 *src, *dst;
327
328 src = (Sint8 *)cvt->buf;
329 dst = (Sint8 *)cvt->buf;
330 for ( i=cvt->len_cvt/4; i; --i ) {
331 lsample = src[0];
332 rsample = src[1];
333 dst[0] = lsample;
334 dst[1] = rsample;
335 src += 4;
336 dst += 2;
337 }
338 }
339 break;
340
341 case AUDIO_U16: {
342 Uint8 *src, *dst;
343
344 src = cvt->buf;
345 dst = cvt->buf;
346 if ( (format & 0x1000) == 0x1000 ) {
347 for ( i=cvt->len_cvt/8; i; --i ) {
348 lsample = (Uint16)((src[0]<<8)|src[1]);
349 rsample = (Uint16)((src[2]<<8)|src[3]);
350 dst[1] = (lsample&0xFF);
351 lsample >>= 8;
352 dst[0] = (lsample&0xFF);
353 dst[3] = (rsample&0xFF);
354 rsample >>= 8;
355 dst[2] = (rsample&0xFF);
356 src += 8;
357 dst += 4;
358 }
359 } else {
360 for ( i=cvt->len_cvt/8; i; --i ) {
361 lsample = (Uint16)((src[1]<<8)|src[0]);
362 rsample = (Uint16)((src[3]<<8)|src[2]);
363 dst[0] = (lsample&0xFF);
364 lsample >>= 8;
365 dst[1] = (lsample&0xFF);
366 dst[2] = (rsample&0xFF);
367 rsample >>= 8;
368 dst[3] = (rsample&0xFF);
369 src += 8;
370 dst += 4;
371 }
372 }
373 }
374 break;
375
376 case AUDIO_S16: {
377 Uint8 *src, *dst;
378
379 src = cvt->buf;
380 dst = cvt->buf;
381 if ( (format & 0x1000) == 0x1000 ) {
382 for ( i=cvt->len_cvt/8; i; --i ) {
383 lsample = (Sint16)((src[0]<<8)|src[1]);
384 rsample = (Sint16)((src[2]<<8)|src[3]);
385 dst[1] = (lsample&0xFF);
386 lsample >>= 8;
387 dst[0] = (lsample&0xFF);
388 dst[3] = (rsample&0xFF);
389 rsample >>= 8;
390 dst[2] = (rsample&0xFF);
391 src += 8;
392 dst += 4;
393 }
394 } else {
395 for ( i=cvt->len_cvt/8; i; --i ) {
396 lsample = (Sint16)((src[1]<<8)|src[0]);
397 rsample = (Sint16)((src[3]<<8)|src[2]);
398 dst[0] = (lsample&0xFF);
399 lsample >>= 8;
400 dst[1] = (lsample&0xFF);
401 dst[2] = (rsample&0xFF);
402 rsample >>= 8;
403 dst[3] = (rsample&0xFF);
404 src += 8;
405 dst += 4;
406 }
407 }
408 }
409 break;
410 }
411 cvt->len_cvt /= 2;
412 if ( cvt->filters[++cvt->filter_index] ) {
413 cvt->filters[cvt->filter_index](cvt, format);
414 }
415 }
178 416
179 /* Duplicate a mono channel to both stereo channels */ 417 /* Duplicate a mono channel to both stereo channels */
180 void SDL_ConvertStereo(SDL_AudioCVT *cvt, Uint16 format) 418 void SDL_ConvertStereo(SDL_AudioCVT *cvt, Uint16 format)
181 { 419 {
182 int i; 420 int i;
210 cvt->len_cvt *= 2; 448 cvt->len_cvt *= 2;
211 if ( cvt->filters[++cvt->filter_index] ) { 449 if ( cvt->filters[++cvt->filter_index] ) {
212 cvt->filters[cvt->filter_index](cvt, format); 450 cvt->filters[cvt->filter_index](cvt, format);
213 } 451 }
214 } 452 }
453
454
455 /* Duplicate a stereo channel to a pseudo-5.1 stream */
456 void SDL_ConvertSurround(SDL_AudioCVT *cvt, Uint16 format)
457 {
458 int i;
459
460 #ifdef DEBUG_CONVERT
461 fprintf(stderr, "Converting stereo to surround\n");
462 #endif
463 switch (format&0x8018) {
464
465 case AUDIO_U8: {
466 Uint8 *src, *dst, lf, rf, ce;
467
468 src = (Uint8 *)(cvt->buf+cvt->len_cvt);
469 dst = (Uint8 *)(cvt->buf+cvt->len_cvt*3);
470 for ( i=cvt->len_cvt; i; --i ) {
471 dst -= 6;
472 src -= 2;
473 lf = src[0];
474 rf = src[1];
475 ce = (lf/2) + (rf/2);
476 dst[0] = lf;
477 dst[1] = rf;
478 dst[2] = lf - ce;
479 dst[3] = rf - ce;
480 dst[4] = ce;
481 dst[5] = ce;
482 }
483 }
484 break;
485
486 case AUDIO_S8: {
487 Sint8 *src, *dst, lf, rf, ce;
488
489 src = cvt->buf+cvt->len_cvt;
490 dst = cvt->buf+cvt->len_cvt*3;
491 for ( i=cvt->len_cvt; i; --i ) {
492 dst -= 6;
493 src -= 2;
494 lf = src[0];
495 rf = src[1];
496 ce = (lf/2) + (rf/2);
497 dst[0] = lf;
498 dst[1] = rf;
499 dst[2] = lf - ce;
500 dst[3] = rf - ce;
501 dst[4] = ce;
502 dst[5] = ce;
503 }
504 }
505 break;
506
507 case AUDIO_U16: {
508 Uint8 *src, *dst;
509 Uint16 lf, rf, ce, lr, rr;
510
511 src = cvt->buf+cvt->len_cvt;
512 dst = cvt->buf+cvt->len_cvt*3;
513
514 if ( (format & 0x1000) == 0x1000 ) {
515 for ( i=cvt->len_cvt/4; i; --i ) {
516 dst -= 12;
517 src -= 4;
518 lf = (Uint16)((src[0]<<8)|src[1]);
519 rf = (Uint16)((src[2]<<8)|src[3]);
520 ce = (lf/2) + (rf/2);
521 rr = lf - ce;
522 lr = rf - ce;
523 dst[1] = (lf&0xFF);
524 dst[0] = ((lf>>8)&0xFF);
525 dst[3] = (rf&0xFF);
526 dst[2] = ((rf>>8)&0xFF);
527
528 dst[1+4] = (lr&0xFF);
529 dst[0+4] = ((lr>>8)&0xFF);
530 dst[3+4] = (rr&0xFF);
531 dst[2+4] = ((rr>>8)&0xFF);
532
533 dst[1+8] = (ce&0xFF);
534 dst[0+8] = ((ce>>8)&0xFF);
535 dst[3+8] = (ce&0xFF);
536 dst[2+8] = ((ce>>8)&0xFF);
537 }
538 } else {
539 for ( i=cvt->len_cvt/4; i; --i ) {
540 dst -= 12;
541 src -= 4;
542 lf = (Uint16)((src[1]<<8)|src[0]);
543 rf = (Uint16)((src[3]<<8)|src[2]);
544 ce = (lf/2) + (rf/2);
545 rr = lf - ce;
546 lr = rf - ce;
547 dst[0] = (lf&0xFF);
548 dst[1] = ((lf>>8)&0xFF);
549 dst[2] = (rf&0xFF);
550 dst[3] = ((rf>>8)&0xFF);
551
552 dst[0+4] = (lr&0xFF);
553 dst[1+4] = ((lr>>8)&0xFF);
554 dst[2+4] = (rr&0xFF);
555 dst[3+4] = ((rr>>8)&0xFF);
556
557 dst[0+8] = (ce&0xFF);
558 dst[1+8] = ((ce>>8)&0xFF);
559 dst[2+8] = (ce&0xFF);
560 dst[3+8] = ((ce>>8)&0xFF);
561 }
562 }
563 }
564 break;
565
566 case AUDIO_S16: {
567 Uint8 *src, *dst;
568 Sint16 lf, rf, ce, lr, rr;
569
570 src = cvt->buf+cvt->len_cvt;
571 dst = cvt->buf+cvt->len_cvt*3;
572
573 if ( (format & 0x1000) == 0x1000 ) {
574 for ( i=cvt->len_cvt/4; i; --i ) {
575 dst -= 12;
576 src -= 4;
577 lf = (Sint16)((src[0]<<8)|src[1]);
578 rf = (Sint16)((src[2]<<8)|src[3]);
579 ce = (lf/2) + (rf/2);
580 rr = lf - ce;
581 lr = rf - ce;
582 dst[1] = (lf&0xFF);
583 dst[0] = ((lf>>8)&0xFF);
584 dst[3] = (rf&0xFF);
585 dst[2] = ((rf>>8)&0xFF);
586
587 dst[1+4] = (lr&0xFF);
588 dst[0+4] = ((lr>>8)&0xFF);
589 dst[3+4] = (rr&0xFF);
590 dst[2+4] = ((rr>>8)&0xFF);
591
592 dst[1+8] = (ce&0xFF);
593 dst[0+8] = ((ce>>8)&0xFF);
594 dst[3+8] = (ce&0xFF);
595 dst[2+8] = ((ce>>8)&0xFF);
596 }
597 } else {
598 for ( i=cvt->len_cvt/4; i; --i ) {
599 dst -= 12;
600 src -= 4;
601 lf = (Sint16)((src[1]<<8)|src[0]);
602 rf = (Sint16)((src[3]<<8)|src[2]);
603 ce = (lf/2) + (rf/2);
604 rr = lf - ce;
605 lr = rf - ce;
606 dst[0] = (lf&0xFF);
607 dst[1] = ((lf>>8)&0xFF);
608 dst[2] = (rf&0xFF);
609 dst[3] = ((rf>>8)&0xFF);
610
611 dst[0+4] = (lr&0xFF);
612 dst[1+4] = ((lr>>8)&0xFF);
613 dst[2+4] = (rr&0xFF);
614 dst[3+4] = ((rr>>8)&0xFF);
615
616 dst[0+8] = (ce&0xFF);
617 dst[1+8] = ((ce>>8)&0xFF);
618 dst[2+8] = (ce&0xFF);
619 dst[3+8] = ((ce>>8)&0xFF);
620 }
621 }
622 }
623 break;
624 }
625 cvt->len_cvt *= 3;
626 if ( cvt->filters[++cvt->filter_index] ) {
627 cvt->filters[cvt->filter_index](cvt, format);
628 }
629 }
630
631
632 /* Duplicate a stereo channel to a pseudo-4.0 stream */
633 void SDL_ConvertSurround_4(SDL_AudioCVT *cvt, Uint16 format)
634 {
635 int i;
636
637 #ifdef DEBUG_CONVERT
638 fprintf(stderr, "Converting stereo to quad\n");
639 #endif
640 switch (format&0x8018) {
641
642 case AUDIO_U8: {
643 Uint8 *src, *dst, lf, rf, ce;
644
645 src = (Uint8 *)(cvt->buf+cvt->len_cvt);
646 dst = (Uint8 *)(cvt->buf+cvt->len_cvt*2);
647 for ( i=cvt->len_cvt; i; --i ) {
648 dst -= 4;
649 src -= 2;
650 lf = src[0];
651 rf = src[1];
652 ce = (lf/2) + (rf/2);
653 dst[0] = lf;
654 dst[1] = rf;
655 dst[2] = lf - ce;
656 dst[3] = rf - ce;
657 }
658 }
659 break;
660
661 case AUDIO_S8: {
662 Sint8 *src, *dst, lf, rf, ce;
663
664 src = cvt->buf+cvt->len_cvt;
665 dst = cvt->buf+cvt->len_cvt*2;
666 for ( i=cvt->len_cvt; i; --i ) {
667 dst -= 4;
668 src -= 2;
669 lf = src[0];
670 rf = src[1];
671 ce = (lf/2) + (rf/2);
672 dst[0] = lf;
673 dst[1] = rf;
674 dst[2] = lf - ce;
675 dst[3] = rf - ce;
676 }
677 }
678 break;
679
680 case AUDIO_U16: {
681 Uint8 *src, *dst;
682 Uint16 lf, rf, ce, lr, rr;
683
684 src = cvt->buf+cvt->len_cvt;
685 dst = cvt->buf+cvt->len_cvt*2;
686
687 if ( (format & 0x1000) == 0x1000 ) {
688 for ( i=cvt->len_cvt/4; i; --i ) {
689 dst -= 8;
690 src -= 4;
691 lf = (Uint16)((src[0]<<8)|src[1]);
692 rf = (Uint16)((src[2]<<8)|src[3]);
693 ce = (lf/2) + (rf/2);
694 rr = lf - ce;
695 lr = rf - ce;
696 dst[1] = (lf&0xFF);
697 dst[0] = ((lf>>8)&0xFF);
698 dst[3] = (rf&0xFF);
699 dst[2] = ((rf>>8)&0xFF);
700
701 dst[1+4] = (lr&0xFF);
702 dst[0+4] = ((lr>>8)&0xFF);
703 dst[3+4] = (rr&0xFF);
704 dst[2+4] = ((rr>>8)&0xFF);
705 }
706 } else {
707 for ( i=cvt->len_cvt/4; i; --i ) {
708 dst -= 8;
709 src -= 4;
710 lf = (Uint16)((src[1]<<8)|src[0]);
711 rf = (Uint16)((src[3]<<8)|src[2]);
712 ce = (lf/2) + (rf/2);
713 rr = lf - ce;
714 lr = rf - ce;
715 dst[0] = (lf&0xFF);
716 dst[1] = ((lf>>8)&0xFF);
717 dst[2] = (rf&0xFF);
718 dst[3] = ((rf>>8)&0xFF);
719
720 dst[0+4] = (lr&0xFF);
721 dst[1+4] = ((lr>>8)&0xFF);
722 dst[2+4] = (rr&0xFF);
723 dst[3+4] = ((rr>>8)&0xFF);
724 }
725 }
726 }
727 break;
728
729 case AUDIO_S16: {
730 Uint8 *src, *dst;
731 Sint16 lf, rf, ce, lr, rr;
732
733 src = cvt->buf+cvt->len_cvt;
734 dst = cvt->buf+cvt->len_cvt*2;
735
736 if ( (format & 0x1000) == 0x1000 ) {
737 for ( i=cvt->len_cvt/4; i; --i ) {
738 dst -= 8;
739 src -= 4;
740 lf = (Sint16)((src[0]<<8)|src[1]);
741 rf = (Sint16)((src[2]<<8)|src[3]);
742 ce = (lf/2) + (rf/2);
743 rr = lf - ce;
744 lr = rf - ce;
745 dst[1] = (lf&0xFF);
746 dst[0] = ((lf>>8)&0xFF);
747 dst[3] = (rf&0xFF);
748 dst[2] = ((rf>>8)&0xFF);
749
750 dst[1+4] = (lr&0xFF);
751 dst[0+4] = ((lr>>8)&0xFF);
752 dst[3+4] = (rr&0xFF);
753 dst[2+4] = ((rr>>8)&0xFF);
754 }
755 } else {
756 for ( i=cvt->len_cvt/4; i; --i ) {
757 dst -= 8;
758 src -= 4;
759 lf = (Sint16)((src[1]<<8)|src[0]);
760 rf = (Sint16)((src[3]<<8)|src[2]);
761 ce = (lf/2) + (rf/2);
762 rr = lf - ce;
763 lr = rf - ce;
764 dst[0] = (lf&0xFF);
765 dst[1] = ((lf>>8)&0xFF);
766 dst[2] = (rf&0xFF);
767 dst[3] = ((rf>>8)&0xFF);
768
769 dst[0+4] = (lr&0xFF);
770 dst[1+4] = ((lr>>8)&0xFF);
771 dst[2+4] = (rr&0xFF);
772 dst[3+4] = ((rr>>8)&0xFF);
773 }
774 }
775 }
776 break;
777 }
778 cvt->len_cvt *= 2;
779 if ( cvt->filters[++cvt->filter_index] ) {
780 cvt->filters[cvt->filter_index](cvt, format);
781 }
782 }
783
215 784
216 /* Convert 8-bit to 16-bit - LSB */ 785 /* Convert 8-bit to 16-bit - LSB */
217 void SDL_Convert16LSB(SDL_AudioCVT *cvt, Uint16 format) 786 void SDL_Convert16LSB(SDL_AudioCVT *cvt, Uint16 format)
218 { 787 {
219 int i; 788 int i;
372 if ( cvt->filters[++cvt->filter_index] ) { 941 if ( cvt->filters[++cvt->filter_index] ) {
373 cvt->filters[cvt->filter_index](cvt, format); 942 cvt->filters[cvt->filter_index](cvt, format);
374 } 943 }
375 } 944 }
376 945
946
947 /* Convert rate up by multiple of 2, for stereo */
948 void SDL_RateMUL2_c2(SDL_AudioCVT *cvt, Uint16 format)
949 {
950 int i;
951 Uint8 *src, *dst;
952
953 #ifdef DEBUG_CONVERT
954 fprintf(stderr, "Converting audio rate * 2\n");
955 #endif
956 src = cvt->buf+cvt->len_cvt;
957 dst = cvt->buf+cvt->len_cvt*2;
958 switch (format & 0xFF) {
959 case 8:
960 for ( i=cvt->len_cvt/2; i; --i ) {
961 src -= 2;
962 dst -= 4;
963 dst[0] = src[0];
964 dst[1] = src[1];
965 dst[2] = src[0];
966 dst[3] = src[1];
967 }
968 break;
969 case 16:
970 for ( i=cvt->len_cvt/4; i; --i ) {
971 src -= 4;
972 dst -= 8;
973 dst[0] = src[0];
974 dst[1] = src[1];
975 dst[2] = src[2];
976 dst[3] = src[3];
977 dst[4] = src[0];
978 dst[5] = src[1];
979 dst[6] = src[2];
980 dst[7] = src[3];
981 }
982 break;
983 }
984 cvt->len_cvt *= 2;
985 if ( cvt->filters[++cvt->filter_index] ) {
986 cvt->filters[cvt->filter_index](cvt, format);
987 }
988 }
989
990 /* Convert rate up by multiple of 2, for quad */
991 void SDL_RateMUL2_c4(SDL_AudioCVT *cvt, Uint16 format)
992 {
993 int i;
994 Uint8 *src, *dst;
995
996 #ifdef DEBUG_CONVERT
997 fprintf(stderr, "Converting audio rate * 2\n");
998 #endif
999 src = cvt->buf+cvt->len_cvt;
1000 dst = cvt->buf+cvt->len_cvt*2;
1001 switch (format & 0xFF) {
1002 case 8:
1003 for ( i=cvt->len_cvt/4; i; --i ) {
1004 src -= 4;
1005 dst -= 8;
1006 dst[0] = src[0];
1007 dst[1] = src[1];
1008 dst[2] = src[2];
1009 dst[3] = src[3];
1010 dst[4] = src[0];
1011 dst[5] = src[1];
1012 dst[6] = src[2];
1013 dst[7] = src[3];
1014 }
1015 break;
1016 case 16:
1017 for ( i=cvt->len_cvt/8; i; --i ) {
1018 src -= 8;
1019 dst -= 16;
1020 dst[0] = src[0];
1021 dst[1] = src[1];
1022 dst[2] = src[2];
1023 dst[3] = src[3];
1024 dst[4] = src[4];
1025 dst[5] = src[5];
1026 dst[6] = src[6];
1027 dst[7] = src[7];
1028 dst[8] = src[0];
1029 dst[9] = src[1];
1030 dst[10] = src[2];
1031 dst[11] = src[3];
1032 dst[12] = src[4];
1033 dst[13] = src[5];
1034 dst[14] = src[6];
1035 dst[15] = src[7];
1036 }
1037 break;
1038 }
1039 cvt->len_cvt *= 2;
1040 if ( cvt->filters[++cvt->filter_index] ) {
1041 cvt->filters[cvt->filter_index](cvt, format);
1042 }
1043 }
1044
1045
1046 /* Convert rate up by multiple of 2, for 5.1 */
1047 void SDL_RateMUL2_c6(SDL_AudioCVT *cvt, Uint16 format)
1048 {
1049 int i;
1050 Uint8 *src, *dst;
1051
1052 #ifdef DEBUG_CONVERT
1053 fprintf(stderr, "Converting audio rate * 2\n");
1054 #endif
1055 src = cvt->buf+cvt->len_cvt;
1056 dst = cvt->buf+cvt->len_cvt*2;
1057 switch (format & 0xFF) {
1058 case 8:
1059 for ( i=cvt->len_cvt/6; i; --i ) {
1060 src -= 6;
1061 dst -= 12;
1062 dst[0] = src[0];
1063 dst[1] = src[1];
1064 dst[2] = src[2];
1065 dst[3] = src[3];
1066 dst[4] = src[4];
1067 dst[5] = src[5];
1068 dst[6] = src[0];
1069 dst[7] = src[1];
1070 dst[8] = src[2];
1071 dst[9] = src[3];
1072 dst[10] = src[4];
1073 dst[11] = src[5];
1074 }
1075 break;
1076 case 16:
1077 for ( i=cvt->len_cvt/12; i; --i ) {
1078 src -= 12;
1079 dst -= 24;
1080 dst[0] = src[0];
1081 dst[1] = src[1];
1082 dst[2] = src[2];
1083 dst[3] = src[3];
1084 dst[4] = src[4];
1085 dst[5] = src[5];
1086 dst[6] = src[6];
1087 dst[7] = src[7];
1088 dst[8] = src[8];
1089 dst[9] = src[9];
1090 dst[10] = src[10];
1091 dst[11] = src[11];
1092 dst[12] = src[0];
1093 dst[13] = src[1];
1094 dst[14] = src[2];
1095 dst[15] = src[3];
1096 dst[16] = src[4];
1097 dst[17] = src[5];
1098 dst[18] = src[6];
1099 dst[19] = src[7];
1100 dst[20] = src[8];
1101 dst[21] = src[9];
1102 dst[22] = src[10];
1103 dst[23] = src[11];
1104 }
1105 break;
1106 }
1107 cvt->len_cvt *= 2;
1108 if ( cvt->filters[++cvt->filter_index] ) {
1109 cvt->filters[cvt->filter_index](cvt, format);
1110 }
1111 }
1112
377 /* Convert rate down by multiple of 2 */ 1113 /* Convert rate down by multiple of 2 */
378 void SDL_RateDIV2(SDL_AudioCVT *cvt, Uint16 format) 1114 void SDL_RateDIV2(SDL_AudioCVT *cvt, Uint16 format)
379 { 1115 {
380 int i; 1116 int i;
381 Uint8 *src, *dst; 1117 Uint8 *src, *dst;
406 if ( cvt->filters[++cvt->filter_index] ) { 1142 if ( cvt->filters[++cvt->filter_index] ) {
407 cvt->filters[cvt->filter_index](cvt, format); 1143 cvt->filters[cvt->filter_index](cvt, format);
408 } 1144 }
409 } 1145 }
410 1146
1147
1148 /* Convert rate down by multiple of 2, for stereo */
1149 void SDL_RateDIV2_c2(SDL_AudioCVT *cvt, Uint16 format)
1150 {
1151 int i;
1152 Uint8 *src, *dst;
1153
1154 #ifdef DEBUG_CONVERT
1155 fprintf(stderr, "Converting audio rate / 2\n");
1156 #endif
1157 src = cvt->buf;
1158 dst = cvt->buf;
1159 switch (format & 0xFF) {
1160 case 8:
1161 for ( i=cvt->len_cvt/4; i; --i ) {
1162 dst[0] = src[0];
1163 dst[1] = src[1];
1164 src += 4;
1165 dst += 2;
1166 }
1167 break;
1168 case 16:
1169 for ( i=cvt->len_cvt/8; i; --i ) {
1170 dst[0] = src[0];
1171 dst[1] = src[1];
1172 dst[2] = src[2];
1173 dst[3] = src[3];
1174 src += 8;
1175 dst += 4;
1176 }
1177 break;
1178 }
1179 cvt->len_cvt /= 2;
1180 if ( cvt->filters[++cvt->filter_index] ) {
1181 cvt->filters[cvt->filter_index](cvt, format);
1182 }
1183 }
1184
1185
1186 /* Convert rate down by multiple of 2, for quad */
1187 void SDL_RateDIV2_c4(SDL_AudioCVT *cvt, Uint16 format)
1188 {
1189 int i;
1190 Uint8 *src, *dst;
1191
1192 #ifdef DEBUG_CONVERT
1193 fprintf(stderr, "Converting audio rate / 2\n");
1194 #endif
1195 src = cvt->buf;
1196 dst = cvt->buf;
1197 switch (format & 0xFF) {
1198 case 8:
1199 for ( i=cvt->len_cvt/8; i; --i ) {
1200 dst[0] = src[0];
1201 dst[1] = src[1];
1202 dst[2] = src[2];
1203 dst[3] = src[3];
1204 src += 8;
1205 dst += 4;
1206 }
1207 break;
1208 case 16:
1209 for ( i=cvt->len_cvt/16; i; --i ) {
1210 dst[0] = src[0];
1211 dst[1] = src[1];
1212 dst[2] = src[2];
1213 dst[3] = src[3];
1214 dst[4] = src[4];
1215 dst[5] = src[5];
1216 dst[6] = src[6];
1217 dst[7] = src[7];
1218 src += 16;
1219 dst += 8;
1220 }
1221 break;
1222 }
1223 cvt->len_cvt /= 2;
1224 if ( cvt->filters[++cvt->filter_index] ) {
1225 cvt->filters[cvt->filter_index](cvt, format);
1226 }
1227 }
1228
1229 /* Convert rate down by multiple of 2, for 5.1 */
1230 void SDL_RateDIV2_c6(SDL_AudioCVT *cvt, Uint16 format)
1231 {
1232 int i;
1233 Uint8 *src, *dst;
1234
1235 #ifdef DEBUG_CONVERT
1236 fprintf(stderr, "Converting audio rate / 2\n");
1237 #endif
1238 src = cvt->buf;
1239 dst = cvt->buf;
1240 switch (format & 0xFF) {
1241 case 8:
1242 for ( i=cvt->len_cvt/12; i; --i ) {
1243 dst[0] = src[0];
1244 dst[1] = src[1];
1245 dst[2] = src[2];
1246 dst[3] = src[3];
1247 dst[4] = src[4];
1248 dst[5] = src[5];
1249 src += 12;
1250 dst += 6;
1251 }
1252 break;
1253 case 16:
1254 for ( i=cvt->len_cvt/24; i; --i ) {
1255 dst[0] = src[0];
1256 dst[1] = src[1];
1257 dst[2] = src[2];
1258 dst[3] = src[3];
1259 dst[4] = src[4];
1260 dst[5] = src[5];
1261 dst[6] = src[6];
1262 dst[7] = src[7];
1263 dst[8] = src[8];
1264 dst[9] = src[9];
1265 dst[10] = src[10];
1266 dst[11] = src[11];
1267 src += 24;
1268 dst += 12;
1269 }
1270 break;
1271 }
1272 cvt->len_cvt /= 2;
1273 if ( cvt->filters[++cvt->filter_index] ) {
1274 cvt->filters[cvt->filter_index](cvt, format);
1275 }
1276 }
1277
411 /* Very slow rate conversion routine */ 1278 /* Very slow rate conversion routine */
412 void SDL_RateSLOW(SDL_AudioCVT *cvt, Uint16 format) 1279 void SDL_RateSLOW(SDL_AudioCVT *cvt, Uint16 format)
413 { 1280 {
414 double ipos; 1281 double ipos;
415 int i, clen; 1282 int i, clen;
509 1376
510 int SDL_BuildAudioCVT(SDL_AudioCVT *cvt, 1377 int SDL_BuildAudioCVT(SDL_AudioCVT *cvt,
511 Uint16 src_format, Uint8 src_channels, int src_rate, 1378 Uint16 src_format, Uint8 src_channels, int src_rate,
512 Uint16 dst_format, Uint8 dst_channels, int dst_rate) 1379 Uint16 dst_format, Uint8 dst_channels, int dst_rate)
513 { 1380 {
1381 /*printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
1382 src_format, dst_format, src_channels, dst_channels, src_rate, dst_rate);*/
514 /* Start off with no conversion necessary */ 1383 /* Start off with no conversion necessary */
515 cvt->needed = 0; 1384 cvt->needed = 0;
516 cvt->filter_index = 0; 1385 cvt->filter_index = 0;
517 cvt->filters[0] = NULL; 1386 cvt->filters[0] = NULL;
518 cvt->len_mult = 1; 1387 cvt->len_mult = 1;
552 } 1421 }
553 } 1422 }
554 1423
555 /* Last filter: Mono/Stereo conversion */ 1424 /* Last filter: Mono/Stereo conversion */
556 if ( src_channels != dst_channels ) { 1425 if ( src_channels != dst_channels ) {
1426 if ( (src_channels == 1) && (dst_channels > 1) ) {
1427 cvt->filters[cvt->filter_index++] =
1428 SDL_ConvertStereo;
1429 cvt->len_mult *= 2;
1430 src_channels = 2;
1431 cvt->len_ratio *= 2;
1432 }
1433 if ( (src_channels == 2) &&
1434 (dst_channels == 6) ) {
1435 cvt->filters[cvt->filter_index++] =
1436 SDL_ConvertSurround;
1437 src_channels = 6;
1438 cvt->len_mult *= 3;
1439 cvt->len_ratio *= 3;
1440 }
1441 if ( (src_channels == 2) &&
1442 (dst_channels == 4) ) {
1443 cvt->filters[cvt->filter_index++] =
1444 SDL_ConvertSurround_4;
1445 src_channels = 4;
1446 cvt->len_mult *= 2;
1447 cvt->len_ratio *= 2;
1448 }
557 while ( (src_channels*2) <= dst_channels ) { 1449 while ( (src_channels*2) <= dst_channels ) {
558 cvt->filters[cvt->filter_index++] = 1450 cvt->filters[cvt->filter_index++] =
559 SDL_ConvertStereo; 1451 SDL_ConvertStereo;
560 cvt->len_mult *= 2; 1452 cvt->len_mult *= 2;
561 src_channels *= 2; 1453 src_channels *= 2;
562 cvt->len_ratio *= 2; 1454 cvt->len_ratio *= 2;
1455 }
1456 if ( (src_channels == 6) &&
1457 (dst_channels <= 2) ) {
1458 cvt->filters[cvt->filter_index++] =
1459 SDL_ConvertStrip;
1460 src_channels = 2;
1461 cvt->len_ratio /= 3;
1462 }
1463 if ( (src_channels == 6) &&
1464 (dst_channels == 4) ) {
1465 cvt->filters[cvt->filter_index++] =
1466 SDL_ConvertStrip_2;
1467 src_channels = 4;
1468 cvt->len_ratio /= 2;
563 } 1469 }
564 /* This assumes that 4 channel audio is in the format: 1470 /* This assumes that 4 channel audio is in the format:
565 Left {front/back} + Right {front/back} 1471 Left {front/back} + Right {front/back}
566 so converting to L/R stereo works properly. 1472 so converting to L/R stereo works properly.
567 */ 1473 */
586 void (*rate_cvt)(SDL_AudioCVT *cvt, Uint16 format); 1492 void (*rate_cvt)(SDL_AudioCVT *cvt, Uint16 format);
587 1493
588 if ( src_rate > dst_rate ) { 1494 if ( src_rate > dst_rate ) {
589 hi_rate = src_rate; 1495 hi_rate = src_rate;
590 lo_rate = dst_rate; 1496 lo_rate = dst_rate;
591 rate_cvt = SDL_RateDIV2; 1497 switch (src_channels) {
1498 case 1: rate_cvt = SDL_RateDIV2; break;
1499 case 2: rate_cvt = SDL_RateDIV2_c2; break;
1500 case 4: rate_cvt = SDL_RateDIV2_c4; break;
1501 case 6: rate_cvt = SDL_RateDIV2_c6; break;
1502 default: return -1;
1503 }
592 len_mult = 1; 1504 len_mult = 1;
593 len_ratio = 0.5; 1505 len_ratio = 0.5;
594 } else { 1506 } else {
595 hi_rate = dst_rate; 1507 hi_rate = dst_rate;
596 lo_rate = src_rate; 1508 lo_rate = src_rate;
597 rate_cvt = SDL_RateMUL2; 1509 switch (src_channels) {
1510 case 1: rate_cvt = SDL_RateMUL2; break;
1511 case 2: rate_cvt = SDL_RateMUL2_c2; break;
1512 case 4: rate_cvt = SDL_RateMUL2_c4; break;
1513 case 6: rate_cvt = SDL_RateMUL2_c6; break;
1514 default: return -1;
1515 }
598 len_mult = 2; 1516 len_mult = 2;
599 len_ratio = 2.0; 1517 len_ratio = 2.0;
600 } 1518 }
601 /* If hi_rate = lo_rate*2^x then conversion is easy */ 1519 /* If hi_rate = lo_rate*2^x then conversion is easy */
602 while ( ((lo_rate*2)/100) <= (hi_rate/100) ) { 1520 while ( ((lo_rate*2)/100) <= (hi_rate/100) ) {