src/audio/sdlgenaudiocvt.pl
author Ryan C. Gordon
Fri, 09 Jan 2009 15:41:45 +0000
changeset 3008 786a48f8309c
parent 2956 1210d5a28e16
child 3019 dfd23eb79be9
permissions -rwxr-xr-x
First shot at autogenerated audio resamplers.

Don't check in a new SDL_audiotypecvt.c yet, though.
     1 #!/usr/bin/perl -w
     2 
     3 use warnings;
     4 use strict;
     5 
     6 my @audiotypes = qw(
     7     U8
     8     S8
     9     U16LSB
    10     S16LSB
    11     U16MSB
    12     S16MSB
    13     S32LSB
    14     S32MSB
    15     F32LSB
    16     F32MSB
    17 );
    18 
    19 my @channels = ( 1, 2, 4, 6, 8 );
    20 my %funcs;
    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 }
    34 
    35 
    36 sub outputHeader {
    37     print <<EOF;
    38 /* DO NOT EDIT!  This file is generated by sdlgenaudiocvt.pl */
    39 /*
    40     SDL - Simple DirectMedia Layer
    41     Copyright (C) 1997-2009 Sam Lantinga
    42 
    43     This library is free software; you can redistribute it and/or
    44     modify it under the terms of the GNU Lesser General Public
    45     License as published by the Free Software Foundation; either
    46     version 2.1 of the License, or (at your option) any later version.
    47 
    48     This library is distributed in the hope that it will be useful,
    49     but WITHOUT ANY WARRANTY; without even the implied warranty of
    50     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    51     Lesser General Public License for more details.
    52 
    53     You should have received a copy of the GNU Lesser General Public
    54     License along with this library; if not, write to the Free Software
    55     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    56 
    57     Sam Lantinga
    58     slouken\@libsdl.org
    59 */
    60 
    61 #include "SDL_config.h"
    62 #include "SDL_audio.h"
    63 #include "SDL_audio_c.h"
    64 
    65 /* *INDENT-OFF* */
    66 
    67 EOF
    68 
    69     my @vals = ( 127, 32767, 2147483647 );
    70     foreach (@vals) {
    71         my $val = $_;
    72         my $fval = 1.0 / $val;
    73         print("#define DIVBY${val} ${fval}f\n");
    74     }
    75 
    76     print("\n");
    77 }
    78 
    79 sub outputFooter {
    80     print <<EOF;
    81 /* $custom_converters converters generated. */
    82 
    83 /* *INDENT-ON* */
    84 
    85 /* vi: set ts=4 sw=4 expandtab: */
    86 EOF
    87 }
    88 
    89 sub splittype {
    90     my $t = shift;
    91     my ($signed, $size, $endian) = $t =~ /([USF])(\d+)([LM]SB|)/;
    92     my $float = ($signed eq 'F') ? 1 : 0;
    93     $signed = (($float) or ($signed eq 'S')) ? 1 : 0;
    94     $endian = 'NONE' if ($endian eq '');
    95 
    96     my $ctype = '';
    97     if ($float) {
    98         $ctype = (($size == 32) ? 'float' : 'double');
    99     } else {
   100         $ctype = (($signed) ? 'S' : 'U') . "int${size}";
   101     }
   102 
   103     return ($signed, $float, $size, $endian, $ctype);
   104 }
   105 
   106 sub getSwapFunc {
   107     my ($size, $signed, $float, $endian, $val) = @_;
   108     my $BEorLE = (($endian eq 'MSB') ? 'BE' : 'LE');
   109     my $code = '';
   110 
   111     if ($float) {
   112         $code = "SDL_SwapFloat${BEorLE}($val)";
   113     } else {
   114         if ($size > 8) {
   115             $code = "SDL_Swap${BEorLE}${size}($val)";
   116         } else {
   117             $code = $val;
   118         }
   119 
   120         if (($signed) and (!$float)) {
   121             $code = "((Sint${size}) $code)";
   122         }
   123     }
   124 
   125     return "${code}";
   126 }
   127 
   128 
   129 sub maxIntVal {
   130     my $size = shift;
   131     if ($size == 8) {
   132         return 0x7F;
   133     } elsif ($size == 16) {
   134         return 0x7FFF;
   135     } elsif ($size == 32) {
   136         return 0x7FFFFFFF;
   137     }
   138 
   139     die("bug in script.\n");
   140 }
   141 
   142 sub getFloatToIntMult {
   143     my $size = shift;
   144     my $val = maxIntVal($size) . '.0';
   145     $val .= 'f' if ($size < 32);
   146     return $val;
   147 }
   148 
   149 sub getIntToFloatDivBy {
   150     my $size = shift;
   151     return 'DIVBY' . maxIntVal($size);
   152 }
   153 
   154 sub getSignFlipVal {
   155     my $size = shift;
   156     if ($size == 8) {
   157         return '0x80';
   158     } elsif ($size == 16) {
   159         return '0x8000';
   160     } elsif ($size == 32) {
   161         return '0x80000000';
   162     }
   163 
   164     die("bug in script.\n");
   165 }
   166 
   167 sub buildCvtFunc {
   168     my ($from, $to) = @_;
   169     my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
   170     my ($tsigned, $tfloat, $tsize, $tendian, $tctype) = splittype($to);
   171     my $diffs = 0;
   172     $diffs++ if ($fsize != $tsize);
   173     $diffs++ if ($fsigned != $tsigned);
   174     $diffs++ if ($ffloat != $tfloat);
   175     $diffs++ if ($fendian ne $tendian);
   176 
   177     return if ($diffs == 0);
   178 
   179     my $hashid = getTypeConvertHashId($from, $to);
   180     if (1) { # !!! FIXME: if ($diffs > 1) {
   181         my $sym = "SDL_Convert_${from}_to_${to}";
   182         $funcs{$hashid} = $sym;
   183         $custom_converters++;
   184 
   185         # Always unsigned for ints, for possible byteswaps.
   186         my $srctype = (($ffloat) ? 'float' : "Uint${fsize}");
   187 
   188         print <<EOF;
   189 static void SDLCALL
   190 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   191 {
   192     int i;
   193     const $srctype *src;
   194     $tctype *dst;
   195 
   196 #ifdef DEBUG_CONVERT
   197     fprintf(stderr, "Converting AUDIO_${from} to AUDIO_${to}.\\n");
   198 #endif
   199 
   200 EOF
   201 
   202         if ($fsize < $tsize) {
   203             my $mult = $tsize / $fsize;
   204             print <<EOF;
   205     src = ((const $srctype *) (cvt->buf + cvt->len_cvt)) - 1;
   206     dst = (($tctype *) (cvt->buf + cvt->len_cvt * $mult)) - 1;
   207     for (i = cvt->len_cvt / sizeof ($srctype); i; --i, --src, --dst) {
   208 EOF
   209         } else {
   210             print <<EOF;
   211     src = (const $srctype *) cvt->buf;
   212     dst = ($tctype *) cvt->buf;
   213     for (i = cvt->len_cvt / sizeof ($srctype); i; --i, ++src, ++dst) {
   214 EOF
   215         }
   216 
   217         # Have to convert to/from float/int.
   218         # !!! FIXME: cast through double for int32<->float?
   219         my $code = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, '*src');
   220         if ($ffloat != $tfloat) {
   221             if ($ffloat) {
   222                 my $mult = getFloatToIntMult($tsize);
   223                 if (!$tsigned) {   # bump from -1.0f/1.0f to 0.0f/2.0f
   224                     $code = "($code + 1.0f)";
   225                 }
   226                 $code = "(($tctype) ($code * $mult))";
   227             } else {
   228                 # $divby will be the reciprocal, to avoid pipeline stalls
   229                 #  from floating point division...so multiply it.
   230                 my $divby = getIntToFloatDivBy($fsize);
   231                 $code = "(((float) $code) * $divby)";
   232                 if (!$fsigned) {   # bump from 0.0f/2.0f to -1.0f/1.0f.
   233                     $code = "($code - 1.0f)";
   234                 }
   235             }
   236         } else {
   237             # All integer conversions here.
   238             if ($fsigned != $tsigned) {
   239                 my $signflipval = getSignFlipVal($fsize);
   240                 $code = "(($code) ^ $signflipval)";
   241             }
   242 
   243             my $shiftval = abs($fsize - $tsize);
   244             if ($fsize < $tsize) {
   245                 $code = "((($tctype) $code) << $shiftval)";
   246             } elsif ($fsize > $tsize) {
   247                 $code = "(($tctype) ($code >> $shiftval))";
   248             }
   249         }
   250 
   251         my $swap = getSwapFunc($tsize, $tsigned, $tfloat, $tendian, 'val');
   252 
   253         print <<EOF;
   254         const $tctype val = $code;
   255         *dst = ${swap};
   256     }
   257 
   258 EOF
   259 
   260         if ($fsize > $tsize) {
   261             my $divby = $fsize / $tsize;
   262             print("    cvt->len_cvt /= $divby;\n");
   263         } elsif ($fsize < $tsize) {
   264             my $mult = $tsize / $fsize;
   265             print("    cvt->len_cvt *= $mult;\n");
   266         }
   267 
   268         print <<EOF;
   269     if (cvt->filters[++cvt->filter_index]) {
   270         cvt->filters[cvt->filter_index] (cvt, AUDIO_$to);
   271     }
   272 }
   273 
   274 EOF
   275 
   276     } else {
   277         if ($fsigned != $tsigned) {
   278             $funcs{$hashid} = 'SDL_ConvertSigned';
   279         } elsif ($ffloat != $tfloat) {
   280             $funcs{$hashid} = 'SDL_ConvertFloat';
   281         } elsif ($fsize != $tsize) {
   282             $funcs{$hashid} = 'SDL_ConvertSize';
   283         } elsif ($fendian ne $tendian) {
   284             $funcs{$hashid} = 'SDL_ConvertEndian';
   285         } else {
   286             die("error in script.\n");
   287         }
   288     }
   289 }
   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 
   689 outputHeader();
   690 buildTypeConverters();
   691 buildResamplers();
   692 outputFooter();
   693 
   694 exit 0;
   695 
   696 # end of sdlgenaudiocvt.pl ...
   697