Mercurial > sdl-ios-xcode
comparison src/audio/sdlgenaudiocvt.pl @ 3008:786a48f8309c
First shot at autogenerated audio resamplers.
Don't check in a new SDL_audiotypecvt.c yet, though.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 09 Jan 2009 15:41:45 +0000 |
parents | 1210d5a28e16 |
children | dfd23eb79be9 |
comparison
equal
deleted
inserted
replaced
3007:b30409e106f2 | 3008:786a48f8309c |
---|---|
14 S32MSB | 14 S32MSB |
15 F32LSB | 15 F32LSB |
16 F32MSB | 16 F32MSB |
17 ); | 17 ); |
18 | 18 |
19 my @channels = ( 1, 2, 4, 6, 8 ); | |
19 my %funcs; | 20 my %funcs; |
20 | |
21 my $custom_converters = 0; | 21 my $custom_converters = 0; |
22 | |
23 | |
24 sub getTypeConvertHashId { | |
25 my ($from, $to) = @_; | |
26 return "TYPECONVERTER $from/$to"; | |
27 } | |
28 | |
29 | |
30 sub getResamplerHashId { | |
31 my ($from, $channels, $upsample, $multiple) = @_; | |
32 return "RESAMPLER $from/$channels/$upsample/$multiple"; | |
33 } | |
22 | 34 |
23 | 35 |
24 sub outputHeader { | 36 sub outputHeader { |
25 print <<EOF; | 37 print <<EOF; |
26 /* DO NOT EDIT! This file is generated by sdlgenaudiocvt.pl */ | 38 /* DO NOT EDIT! This file is generated by sdlgenaudiocvt.pl */ |
64 print("\n"); | 76 print("\n"); |
65 } | 77 } |
66 | 78 |
67 sub outputFooter { | 79 sub outputFooter { |
68 print <<EOF; | 80 print <<EOF; |
81 /* $custom_converters converters generated. */ | |
82 | |
69 /* *INDENT-ON* */ | 83 /* *INDENT-ON* */ |
70 | 84 |
71 /* vi: set ts=4 sw=4 expandtab: */ | 85 /* vi: set ts=4 sw=4 expandtab: */ |
72 EOF | 86 EOF |
73 } | 87 } |
160 $diffs++ if ($ffloat != $tfloat); | 174 $diffs++ if ($ffloat != $tfloat); |
161 $diffs++ if ($fendian ne $tendian); | 175 $diffs++ if ($fendian ne $tendian); |
162 | 176 |
163 return if ($diffs == 0); | 177 return if ($diffs == 0); |
164 | 178 |
165 my $hashid = "$from/$to"; | 179 my $hashid = getTypeConvertHashId($from, $to); |
166 if (1) { # !!! FIXME: if ($diffs > 1) { | 180 if (1) { # !!! FIXME: if ($diffs > 1) { |
167 my $sym = "SDL_Convert_${from}_to_${to}"; | 181 my $sym = "SDL_Convert_${from}_to_${to}"; |
168 $funcs{$hashid} = $sym; | 182 $funcs{$hashid} = $sym; |
169 $custom_converters++; | 183 $custom_converters++; |
170 | 184 |
272 die("error in script.\n"); | 286 die("error in script.\n"); |
273 } | 287 } |
274 } | 288 } |
275 } | 289 } |
276 | 290 |
291 | |
292 sub buildTypeConverters { | |
293 foreach (@audiotypes) { | |
294 my $from = $_; | |
295 foreach (@audiotypes) { | |
296 my $to = $_; | |
297 buildCvtFunc($from, $to); | |
298 } | |
299 } | |
300 | |
301 print "const SDL_AudioTypeFilters sdl_audio_type_filters[] =\n{\n"; | |
302 foreach (@audiotypes) { | |
303 my $from = $_; | |
304 foreach (@audiotypes) { | |
305 my $to = $_; | |
306 if ($from ne $to) { | |
307 my $hashid = getTypeConvertHashId($from, $to); | |
308 my $sym = $funcs{$hashid}; | |
309 print(" { AUDIO_$from, AUDIO_$to, $sym },\n"); | |
310 } | |
311 } | |
312 } | |
313 | |
314 print "};\n\n\n"; | |
315 } | |
316 | |
317 sub getBiggerCtype { | |
318 my ($isfloat, $size) = @_; | |
319 | |
320 if ($isfloat) { | |
321 if ($size == 32) { | |
322 return 'double'; | |
323 } | |
324 die("bug in script.\n"); | |
325 } | |
326 | |
327 if ($size == 8) { | |
328 return 'Sint16'; | |
329 } elsif ($size == 16) { | |
330 return 'Sint32' | |
331 } elsif ($size == 32) { | |
332 return 'Sint64' | |
333 } | |
334 | |
335 die("bug in script.\n"); | |
336 } | |
337 | |
338 | |
339 # These handle arbitrary resamples...44100Hz to 48000Hz, for example. | |
340 # Man, this code is skanky. | |
341 sub buildArbitraryResampleFunc { | |
342 # !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc(). | |
343 my ($from, $channels, $upsample) = @_; | |
344 my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from); | |
345 | |
346 my $bigger = getBiggerCtype($ffloat, $fsize); | |
347 my $interp = ($ffloat) ? '* 0.5' : '>> 1'; | |
348 | |
349 my $resample = ($upsample) ? 'Upsample' : 'Downsample'; | |
350 my $hashid = getResamplerHashId($from, $channels, $upsample, 0); | |
351 my $sym = "SDL_${resample}_${from}_${channels}c"; | |
352 $funcs{$hashid} = $sym; | |
353 $custom_converters++; | |
354 | |
355 my $fudge = $fsize * $channels * 2; # !!! FIXME | |
356 my $eps_adjust = ($upsample) ? 'dstsize' : 'srcsize'; | |
357 my $incr = ''; | |
358 my $incr2 = ''; | |
359 | |
360 | |
361 # !!! FIXME: DEBUG_CONVERT should report frequencies. | |
362 print <<EOF; | |
363 static void SDLCALL | |
364 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format) | |
365 { | |
366 #ifdef DEBUG_CONVERT | |
367 fprintf(stderr, "$resample arbitrary (x%f) AUDIO_${from}, ${channels} channels.\\n", cvt->rate_incr); | |
368 #endif | |
369 | |
370 const int srcsize = cvt->len_cvt - $fudge; | |
371 const int dstsize = (int) (((double)cvt->len_cvt) * cvt->rate_incr); | |
372 register int eps = 0; | |
373 EOF | |
374 | |
375 # Upsampling (growing the buffer) needs to work backwards, since we | |
376 # overwrite the buffer as we go. | |
377 if ($upsample) { | |
378 print <<EOF; | |
379 $fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels; | |
380 const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels; | |
381 const $fctype *target = ((const $fctype *) cvt->buf) - $channels; | |
382 EOF | |
383 } else { | |
384 print <<EOF; | |
385 $fctype *dst = ($fctype *) cvt->buf; | |
386 const $fctype *src = ($fctype *) cvt->buf; | |
387 const $fctype *target = (const $fctype *) (cvt->buf + dstsize); | |
388 EOF | |
389 } | |
390 | |
391 for (my $i = 0; $i < $channels; $i++) { | |
392 my $idx = ($upsample) ? (($channels - $i) - 1) : $i; | |
393 my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]"); | |
394 print <<EOF; | |
395 $fctype sample${idx} = $val; | |
396 EOF | |
397 } | |
398 | |
399 for (my $i = 0; $i < $channels; $i++) { | |
400 my $idx = ($upsample) ? (($channels - $i) - 1) : $i; | |
401 print <<EOF; | |
402 $fctype last_sample${idx} = sample${idx}; | |
403 EOF | |
404 } | |
405 | |
406 print <<EOF; | |
407 while (dst != target) { | |
408 EOF | |
409 | |
410 if ($upsample) { | |
411 for (my $i = 0; $i < $channels; $i++) { | |
412 # !!! FIXME: don't do this swap every write, just when the samples change. | |
413 my $idx = (($channels - $i) - 1); | |
414 my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${idx}"); | |
415 print <<EOF; | |
416 dst[$idx] = $val; | |
417 EOF | |
418 } | |
419 | |
420 $incr = ($channels == 1) ? 'dst--' : "dst -= $channels"; | |
421 $incr2 = ($channels == 1) ? 'src--' : "src -= $channels"; | |
422 | |
423 print <<EOF; | |
424 $incr; | |
425 eps += srcsize; | |
426 if ((eps << 1) >= dstsize) { | |
427 $incr2; | |
428 EOF | |
429 } else { # downsample. | |
430 $incr = ($channels == 1) ? 'src++' : "src += $channels"; | |
431 print <<EOF; | |
432 $incr; | |
433 eps += dstsize; | |
434 if ((eps << 1) >= srcsize) { | |
435 EOF | |
436 for (my $i = 0; $i < $channels; $i++) { | |
437 my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${i}"); | |
438 print <<EOF; | |
439 dst[$i] = $val; | |
440 EOF | |
441 } | |
442 | |
443 $incr = ($channels == 1) ? 'dst++' : "dst += $channels"; | |
444 print <<EOF; | |
445 $incr; | |
446 EOF | |
447 } | |
448 | |
449 for (my $i = 0; $i < $channels; $i++) { | |
450 my $idx = ($upsample) ? (($channels - $i) - 1) : $i; | |
451 my $swapped = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]"); | |
452 print <<EOF; | |
453 sample${idx} = ($fctype) (((($bigger) $swapped) + (($bigger) last_sample${idx})) $interp); | |
454 EOF | |
455 } | |
456 | |
457 for (my $i = 0; $i < $channels; $i++) { | |
458 my $idx = ($upsample) ? (($channels - $i) - 1) : $i; | |
459 print <<EOF; | |
460 last_sample${idx} = sample${idx}; | |
461 EOF | |
462 } | |
463 | |
464 print <<EOF; | |
465 eps -= $eps_adjust; | |
466 } | |
467 } | |
468 EOF | |
469 | |
470 print <<EOF; | |
471 cvt->len_cvt = dstsize; | |
472 if (cvt->filters[++cvt->filter_index]) { | |
473 cvt->filters[cvt->filter_index] (cvt, format); | |
474 } | |
475 } | |
476 | |
477 EOF | |
478 | |
479 } | |
480 | |
481 # These handle clean resamples...doubling and quadrupling the sample rate, etc. | |
482 sub buildMultipleResampleFunc { | |
483 # !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc(). | |
484 my ($from, $channels, $upsample, $multiple) = @_; | |
485 my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from); | |
486 | |
487 my $bigger = getBiggerCtype($ffloat, $fsize); | |
488 my $interp = ($ffloat) ? '* 0.5' : '>> 1'; | |
489 my $interp2 = ($ffloat) ? '* 0.25' : '>> 2'; | |
490 my $mult3 = ($ffloat) ? '3.0' : '3'; | |
491 my $lencvtop = ($upsample) ? '*' : '/'; | |
492 | |
493 my $resample = ($upsample) ? 'Upsample' : 'Downsample'; | |
494 my $hashid = getResamplerHashId($from, $channels, $upsample, $multiple); | |
495 my $sym = "SDL_${resample}_${from}_${channels}c_x${multiple}"; | |
496 $funcs{$hashid} = $sym; | |
497 $custom_converters++; | |
498 | |
499 # !!! FIXME: DEBUG_CONVERT should report frequencies. | |
500 print <<EOF; | |
501 static void SDLCALL | |
502 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format) | |
503 { | |
504 #ifdef DEBUG_CONVERT | |
505 fprintf(stderr, "$resample (x${multiple}) AUDIO_${from}, ${channels} channels.\\n"); | |
506 #endif | |
507 | |
508 const int srcsize = cvt->len_cvt; | |
509 const int dstsize = cvt->len_cvt $lencvtop $multiple; | |
510 EOF | |
511 | |
512 # Upsampling (growing the buffer) needs to work backwards, since we | |
513 # overwrite the buffer as we go. | |
514 if ($upsample) { | |
515 print <<EOF; | |
516 $fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels; | |
517 const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels; | |
518 const $fctype *target = ((const $fctype *) cvt->buf) - $channels; | |
519 EOF | |
520 } else { | |
521 print <<EOF; | |
522 $fctype *dst = ($fctype *) cvt->buf; | |
523 const $fctype *src = ($fctype *) cvt->buf; | |
524 const $fctype *target = (const $fctype *) (cvt->buf + dstsize); | |
525 EOF | |
526 } | |
527 | |
528 for (my $i = 0; $i < $channels; $i++) { | |
529 my $idx = ($upsample) ? (($channels - $i) - 1) : $i; | |
530 my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]"); | |
531 print <<EOF; | |
532 $bigger last_sample${idx} = ($bigger) $val; | |
533 EOF | |
534 } | |
535 | |
536 print <<EOF; | |
537 while (dst != target) { | |
538 EOF | |
539 | |
540 for (my $i = 0; $i < $channels; $i++) { | |
541 my $idx = ($upsample) ? (($channels - $i) - 1) : $i; | |
542 my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]"); | |
543 print <<EOF; | |
544 const $bigger sample${idx} = ($bigger) $val; | |
545 EOF | |
546 } | |
547 | |
548 my $incr = ''; | |
549 if ($upsample) { | |
550 $incr = ($channels == 1) ? 'src--' : "src -= $channels"; | |
551 } else { | |
552 my $amount = $channels * $multiple; | |
553 $incr = "src += $amount"; # can't ever be 1, so no "++" version. | |
554 } | |
555 | |
556 | |
557 print <<EOF; | |
558 $incr; | |
559 EOF | |
560 | |
561 # !!! FIXME: This really begs for some Altivec or SSE, etc. | |
562 if ($upsample) { | |
563 if ($multiple == 2) { | |
564 for (my $i = $channels-1; $i >= 0; $i--) { | |
565 my $dsti = $i + $channels; | |
566 print <<EOF; | |
567 dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp); | |
568 EOF | |
569 } | |
570 for (my $i = $channels-1; $i >= 0; $i--) { | |
571 my $dsti = $i; | |
572 print <<EOF; | |
573 dst[$dsti] = ($fctype) sample${i}; | |
574 EOF | |
575 } | |
576 } elsif ($multiple == 4) { | |
577 for (my $i = $channels-1; $i >= 0; $i--) { | |
578 my $dsti = $i + ($channels * 3); | |
579 print <<EOF; | |
580 dst[$dsti] = ($fctype) sample${i}; | |
581 EOF | |
582 } | |
583 | |
584 for (my $i = $channels-1; $i >= 0; $i--) { | |
585 my $dsti = $i + ($channels * 2); | |
586 print <<EOF; | |
587 dst[$dsti] = ($fctype) ((($mult3 * sample${i}) + last_sample${i}) $interp2); | |
588 EOF | |
589 } | |
590 | |
591 for (my $i = $channels-1; $i >= 0; $i--) { | |
592 my $dsti = $i + ($channels * 1); | |
593 print <<EOF; | |
594 dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp); | |
595 EOF | |
596 } | |
597 | |
598 for (my $i = $channels-1; $i >= 0; $i--) { | |
599 my $dsti = $i + ($channels * 0); | |
600 print <<EOF; | |
601 dst[$dsti] = ($fctype) ((sample${i} + ($mult3 * last_sample${i})) $interp2); | |
602 EOF | |
603 } | |
604 } else { | |
605 die('bug in program.'); # we only handle x2 and x4. | |
606 } | |
607 } else { # downsample. | |
608 if ($multiple == 2) { | |
609 for (my $i = 0; $i < $channels; $i++) { | |
610 print <<EOF; | |
611 dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp); | |
612 EOF | |
613 } | |
614 } elsif ($multiple == 4) { | |
615 # !!! FIXME: interpolate all 4 samples? | |
616 for (my $i = 0; $i < $channels; $i++) { | |
617 print <<EOF; | |
618 dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp); | |
619 EOF | |
620 } | |
621 } else { | |
622 die('bug in program.'); # we only handle x2 and x4. | |
623 } | |
624 } | |
625 | |
626 for (my $i = 0; $i < $channels; $i++) { | |
627 my $idx = ($upsample) ? (($channels - $i) - 1) : $i; | |
628 print <<EOF; | |
629 last_sample${idx} = sample${idx}; | |
630 EOF | |
631 } | |
632 | |
633 if ($upsample) { | |
634 my $amount = $channels * $multiple; | |
635 $incr = "dst -= $amount"; # can't ever be 1, so no "--" version. | |
636 } else { | |
637 $incr = ($channels == 1) ? 'dst++' : "dst += $channels"; | |
638 } | |
639 | |
640 print <<EOF; | |
641 $incr; | |
642 } | |
643 | |
644 cvt->len_cvt = dstsize; | |
645 if (cvt->filters[++cvt->filter_index]) { | |
646 cvt->filters[cvt->filter_index] (cvt, format); | |
647 } | |
648 } | |
649 | |
650 EOF | |
651 | |
652 } | |
653 | |
654 sub buildResamplers { | |
655 foreach (@audiotypes) { | |
656 my $from = $_; | |
657 foreach (@channels) { | |
658 my $channel = $_; | |
659 for (my $multiple = 2; $multiple <= 4; $multiple += 2) { | |
660 buildMultipleResampleFunc($from, $channel, 1, $multiple); | |
661 buildMultipleResampleFunc($from, $channel, 0, $multiple); | |
662 } | |
663 buildArbitraryResampleFunc($from, $channel, 1); | |
664 buildArbitraryResampleFunc($from, $channel, 0); | |
665 } | |
666 } | |
667 | |
668 print "const SDL_AudioRateFilters sdl_audio_rate_filters[] =\n{\n"; | |
669 foreach (@audiotypes) { | |
670 my $from = $_; | |
671 foreach (@channels) { | |
672 my $channel = $_; | |
673 for (my $multiple = 0; $multiple <= 4; $multiple += 2) { | |
674 for (my $upsample = 0; $upsample <= 1; $upsample++) { | |
675 my $hashid = getResamplerHashId($from, $channel, $upsample, $multiple); | |
676 my $sym = $funcs{$hashid}; | |
677 print(" { AUDIO_$from, $channel, $upsample, $multiple, $sym },\n"); | |
678 } | |
679 } | |
680 } | |
681 } | |
682 | |
683 print "};\n\n"; | |
684 } | |
685 | |
686 | |
687 # mainline ... | |
688 | |
277 outputHeader(); | 689 outputHeader(); |
278 | 690 buildTypeConverters(); |
279 foreach (@audiotypes) { | 691 buildResamplers(); |
280 my $from = $_; | |
281 foreach (@audiotypes) { | |
282 my $to = $_; | |
283 buildCvtFunc($from, $to); | |
284 } | |
285 } | |
286 | |
287 print <<EOF; | |
288 const SDL_AudioTypeFilters sdl_audio_type_filters[] = | |
289 { | |
290 EOF | |
291 | |
292 foreach (@audiotypes) { | |
293 my $from = $_; | |
294 foreach (@audiotypes) { | |
295 my $to = $_; | |
296 if ($from ne $to) { | |
297 my $hashid = "$from/$to"; | |
298 my $sym = $funcs{$hashid}; | |
299 print(" { AUDIO_$from, AUDIO_$to, $sym },\n"); | |
300 } | |
301 } | |
302 } | |
303 | |
304 print <<EOF; | |
305 }; | |
306 | |
307 | |
308 EOF | |
309 | |
310 outputFooter(); | 692 outputFooter(); |
311 | 693 |
312 exit 0; | 694 exit 0; |
313 | 695 |
314 # end of sdlgenaudiocvt.pl ... | 696 # end of sdlgenaudiocvt.pl ... |