src/audio/sdlgenaudiocvt.pl
author Ryan C. Gordon <icculus@icculus.org>
Tue, 11 Oct 2011 22:35:19 -0400
changeset 5978 717d540f1970
parent 5977 4e09b43f2525
child 6138 4c64952a58fb
permissions -rwxr-xr-x
Fixed compiler warning for unused variable in generated C code.
     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   Simple DirectMedia Layer
    41   Copyright (C) 1997-2011 Sam Lantinga <slouken\@libsdl.org>
    42 
    43   This software is provided 'as-is', without any express or implied
    44   warranty.  In no event will the authors be held liable for any damages
    45   arising from the use of this software.
    46 
    47   Permission is granted to anyone to use this software for any purpose,
    48   including commercial applications, and to alter it and redistribute it
    49   freely, subject to the following restrictions:
    50 
    51   1. The origin of this software must not be misrepresented; you must not
    52      claim that you wrote the original software. If you use this software
    53      in a product, an acknowledgment in the product documentation would be
    54      appreciated but is not required.
    55   2. Altered source versions must be plainly marked as such, and must not be
    56      misrepresented as being the original software.
    57   3. This notice may not be removed or altered from any source distribution.
    58 */
    59 
    60 #include "SDL_config.h"
    61 #include "SDL_audio.h"
    62 #include "SDL_audio_c.h"
    63 
    64 #ifndef DEBUG_CONVERT
    65 #define DEBUG_CONVERT 0
    66 #endif
    67 
    68 
    69 /* If you can guarantee your data and need space, you can eliminate code... */
    70 
    71 /* Just build the arbitrary resamplers if you're saving code space. */
    72 #ifndef LESS_RESAMPLERS
    73 #define LESS_RESAMPLERS 0
    74 #endif
    75 
    76 /* Don't build any resamplers if you're REALLY saving code space. */
    77 #ifndef NO_RESAMPLERS
    78 #define NO_RESAMPLERS 0
    79 #endif
    80 
    81 /* Don't build any type converters if you're saving code space. */
    82 #ifndef NO_CONVERTERS
    83 #define NO_CONVERTERS 0
    84 #endif
    85 
    86 
    87 /* *INDENT-OFF* */
    88 
    89 EOF
    90 
    91     my @vals = ( 127, 32767, 2147483647 );
    92     foreach (@vals) {
    93         my $val = $_;
    94         my $fval = 1.0 / $val;
    95         print("#define DIVBY${val} ${fval}f\n");
    96     }
    97 
    98     print("\n");
    99 }
   100 
   101 sub outputFooter {
   102     print <<EOF;
   103 /* $custom_converters converters generated. */
   104 
   105 /* *INDENT-ON* */
   106 
   107 /* vi: set ts=4 sw=4 expandtab: */
   108 EOF
   109 }
   110 
   111 sub splittype {
   112     my $t = shift;
   113     my ($signed, $size, $endian) = $t =~ /([USF])(\d+)([LM]SB|)/;
   114     my $float = ($signed eq 'F') ? 1 : 0;
   115     $signed = (($float) or ($signed eq 'S')) ? 1 : 0;
   116     $endian = 'NONE' if ($endian eq '');
   117 
   118     my $ctype = '';
   119     if ($float) {
   120         $ctype = (($size == 32) ? 'float' : 'double');
   121     } else {
   122         $ctype = (($signed) ? 'S' : 'U') . "int${size}";
   123     }
   124 
   125     return ($signed, $float, $size, $endian, $ctype);
   126 }
   127 
   128 sub getSwapFunc {
   129     my ($size, $signed, $float, $endian, $val) = @_;
   130     my $BEorLE = (($endian eq 'MSB') ? 'BE' : 'LE');
   131     my $code = '';
   132 
   133     if ($float) {
   134         $code = "SDL_SwapFloat${BEorLE}($val)";
   135     } else {
   136         if ($size > 8) {
   137             $code = "SDL_Swap${BEorLE}${size}($val)";
   138         } else {
   139             $code = $val;
   140         }
   141 
   142         if (($signed) and (!$float)) {
   143             $code = "((Sint${size}) $code)";
   144         }
   145     }
   146 
   147     return "${code}";
   148 }
   149 
   150 
   151 sub maxIntVal {
   152     my $size = shift;
   153     if ($size == 8) {
   154         return 0x7F;
   155     } elsif ($size == 16) {
   156         return 0x7FFF;
   157     } elsif ($size == 32) {
   158         return 0x7FFFFFFF;
   159     }
   160 
   161     die("bug in script.\n");
   162 }
   163 
   164 sub getFloatToIntMult {
   165     my $size = shift;
   166     my $val = maxIntVal($size) . '.0';
   167     $val .= 'f' if ($size < 32);
   168     return $val;
   169 }
   170 
   171 sub getIntToFloatDivBy {
   172     my $size = shift;
   173     return 'DIVBY' . maxIntVal($size);
   174 }
   175 
   176 sub getSignFlipVal {
   177     my $size = shift;
   178     if ($size == 8) {
   179         return '0x80';
   180     } elsif ($size == 16) {
   181         return '0x8000';
   182     } elsif ($size == 32) {
   183         return '0x80000000';
   184     }
   185 
   186     die("bug in script.\n");
   187 }
   188 
   189 sub buildCvtFunc {
   190     my ($from, $to) = @_;
   191     my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
   192     my ($tsigned, $tfloat, $tsize, $tendian, $tctype) = splittype($to);
   193     my $diffs = 0;
   194     $diffs++ if ($fsize != $tsize);
   195     $diffs++ if ($fsigned != $tsigned);
   196     $diffs++ if ($ffloat != $tfloat);
   197     $diffs++ if ($fendian ne $tendian);
   198 
   199     return if ($diffs == 0);
   200 
   201     my $hashid = getTypeConvertHashId($from, $to);
   202     if (1) { # !!! FIXME: if ($diffs > 1) {
   203         my $sym = "SDL_Convert_${from}_to_${to}";
   204         $funcs{$hashid} = $sym;
   205         $custom_converters++;
   206 
   207         # Always unsigned for ints, for possible byteswaps.
   208         my $srctype = (($ffloat) ? 'float' : "Uint${fsize}");
   209 
   210         print <<EOF;
   211 static void SDLCALL
   212 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   213 {
   214     int i;
   215     const $srctype *src;
   216     $tctype *dst;
   217 
   218 #if DEBUG_CONVERT
   219     fprintf(stderr, "Converting AUDIO_${from} to AUDIO_${to}.\\n");
   220 #endif
   221 
   222 EOF
   223 
   224         if ($fsize < $tsize) {
   225             my $mult = $tsize / $fsize;
   226             print <<EOF;
   227     src = ((const $srctype *) (cvt->buf + cvt->len_cvt)) - 1;
   228     dst = (($tctype *) (cvt->buf + cvt->len_cvt * $mult)) - 1;
   229     for (i = cvt->len_cvt / sizeof ($srctype); i; --i, --src, --dst) {
   230 EOF
   231         } else {
   232             print <<EOF;
   233     src = (const $srctype *) cvt->buf;
   234     dst = ($tctype *) cvt->buf;
   235     for (i = cvt->len_cvt / sizeof ($srctype); i; --i, ++src, ++dst) {
   236 EOF
   237         }
   238 
   239         # Have to convert to/from float/int.
   240         # !!! FIXME: cast through double for int32<->float?
   241         my $code = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, '*src');
   242         if ($ffloat != $tfloat) {
   243             if ($ffloat) {
   244                 my $mult = getFloatToIntMult($tsize);
   245                 if (!$tsigned) {   # bump from -1.0f/1.0f to 0.0f/2.0f
   246                     $code = "($code + 1.0f)";
   247                 }
   248                 $code = "(($tctype) ($code * $mult))";
   249             } else {
   250                 # $divby will be the reciprocal, to avoid pipeline stalls
   251                 #  from floating point division...so multiply it.
   252                 my $divby = getIntToFloatDivBy($fsize);
   253                 $code = "(((float) $code) * $divby)";
   254                 if (!$fsigned) {   # bump from 0.0f/2.0f to -1.0f/1.0f.
   255                     $code = "($code - 1.0f)";
   256                 }
   257             }
   258         } else {
   259             # All integer conversions here.
   260             if ($fsigned != $tsigned) {
   261                 my $signflipval = getSignFlipVal($fsize);
   262                 $code = "(($code) ^ $signflipval)";
   263             }
   264 
   265             my $shiftval = abs($fsize - $tsize);
   266             if ($fsize < $tsize) {
   267                 $code = "((($tctype) $code) << $shiftval)";
   268             } elsif ($fsize > $tsize) {
   269                 $code = "(($tctype) ($code >> $shiftval))";
   270             }
   271         }
   272 
   273         my $swap = getSwapFunc($tsize, $tsigned, $tfloat, $tendian, 'val');
   274 
   275         print <<EOF;
   276         const $tctype val = $code;
   277         *dst = ${swap};
   278     }
   279 
   280 EOF
   281 
   282         if ($fsize > $tsize) {
   283             my $divby = $fsize / $tsize;
   284             print("    cvt->len_cvt /= $divby;\n");
   285         } elsif ($fsize < $tsize) {
   286             my $mult = $tsize / $fsize;
   287             print("    cvt->len_cvt *= $mult;\n");
   288         }
   289 
   290         print <<EOF;
   291     if (cvt->filters[++cvt->filter_index]) {
   292         cvt->filters[cvt->filter_index] (cvt, AUDIO_$to);
   293     }
   294 }
   295 
   296 EOF
   297 
   298     } else {
   299         if ($fsigned != $tsigned) {
   300             $funcs{$hashid} = 'SDL_ConvertSigned';
   301         } elsif ($ffloat != $tfloat) {
   302             $funcs{$hashid} = 'SDL_ConvertFloat';
   303         } elsif ($fsize != $tsize) {
   304             $funcs{$hashid} = 'SDL_ConvertSize';
   305         } elsif ($fendian ne $tendian) {
   306             $funcs{$hashid} = 'SDL_ConvertEndian';
   307         } else {
   308             die("error in script.\n");
   309         }
   310     }
   311 }
   312 
   313 
   314 sub buildTypeConverters {
   315     print "#if !NO_CONVERTERS\n\n";
   316     foreach (@audiotypes) {
   317         my $from = $_;
   318         foreach (@audiotypes) {
   319             my $to = $_;
   320             buildCvtFunc($from, $to);
   321         }
   322     }
   323     print "#endif  /* !NO_CONVERTERS */\n\n\n";
   324 
   325     print "const SDL_AudioTypeFilters sdl_audio_type_filters[] =\n{\n";
   326     print "#if !NO_CONVERTERS\n";
   327     foreach (@audiotypes) {
   328         my $from = $_;
   329         foreach (@audiotypes) {
   330             my $to = $_;
   331             if ($from ne $to) {
   332                 my $hashid = getTypeConvertHashId($from, $to);
   333                 my $sym = $funcs{$hashid};
   334                 print("    { AUDIO_$from, AUDIO_$to, $sym },\n");
   335             }
   336         }
   337     }
   338     print "#endif  /* !NO_CONVERTERS */\n";
   339 
   340     print("    { 0, 0, NULL }\n");
   341     print "};\n\n\n";
   342 }
   343 
   344 sub getBiggerCtype {
   345     my ($isfloat, $size) = @_;
   346 
   347     if ($isfloat) {
   348         if ($size == 32) {
   349             return 'double';
   350         }
   351         die("bug in script.\n");
   352     }
   353 
   354     if ($size == 8) {
   355         return 'Sint16';
   356     } elsif ($size == 16) {
   357         return 'Sint32'
   358     } elsif ($size == 32) {
   359         return 'Sint64'
   360     }
   361 
   362     die("bug in script.\n");
   363 }
   364 
   365 
   366 # These handle arbitrary resamples...44100Hz to 48000Hz, for example.
   367 # Man, this code is skanky.
   368 sub buildArbitraryResampleFunc {
   369     # !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
   370     my ($from, $channels, $upsample) = @_;
   371     my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
   372 
   373     my $bigger = getBiggerCtype($ffloat, $fsize);
   374     my $interp = ($ffloat) ? '* 0.5' : '>> 1';
   375 
   376     my $resample = ($upsample) ? 'Upsample' : 'Downsample';
   377     my $hashid = getResamplerHashId($from, $channels, $upsample, 0);
   378     my $sym = "SDL_${resample}_${from}_${channels}c";
   379     $funcs{$hashid} = $sym;
   380     $custom_converters++;
   381 
   382     my $fudge = $fsize * $channels * 2;  # !!! FIXME
   383     my $eps_adjust = ($upsample) ? 'dstsize' : 'srcsize';
   384     my $incr = '';
   385     my $incr2 = '';
   386 
   387 
   388     # !!! FIXME: DEBUG_CONVERT should report frequencies.
   389     print <<EOF;
   390 static void SDLCALL
   391 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   392 {
   393 #if DEBUG_CONVERT
   394     fprintf(stderr, "$resample arbitrary (x%f) AUDIO_${from}, ${channels} channels.\\n", cvt->rate_incr);
   395 #endif
   396 
   397     const int srcsize = cvt->len_cvt - $fudge;
   398     const int dstsize = (int) (((double)cvt->len_cvt) * cvt->rate_incr);
   399     register int eps = 0;
   400 EOF
   401 
   402     my $endcomparison = '!=';
   403 
   404     # Upsampling (growing the buffer) needs to work backwards, since we
   405     #  overwrite the buffer as we go.
   406     if ($upsample) {
   407         $endcomparison = '>';  # dst > target
   408         print <<EOF;
   409     $fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels;
   410     const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
   411     const $fctype *target = ((const $fctype *) cvt->buf) - $channels;
   412 EOF
   413     } else {
   414         $endcomparison = '<';  # dst < target
   415         print <<EOF;
   416     $fctype *dst = ($fctype *) cvt->buf;
   417     const $fctype *src = ($fctype *) cvt->buf;
   418     const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
   419 EOF
   420     }
   421 
   422     for (my $i = 0; $i < $channels; $i++) {
   423         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   424         my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
   425         print <<EOF;
   426     $fctype sample${idx} = $val;
   427 EOF
   428     }
   429 
   430     for (my $i = 0; $i < $channels; $i++) {
   431         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   432         print <<EOF;
   433     $fctype last_sample${idx} = sample${idx};
   434 EOF
   435     }
   436 
   437     print <<EOF;
   438     while (dst $endcomparison target) {
   439 EOF
   440 
   441     if ($upsample) {
   442         for (my $i = 0; $i < $channels; $i++) {
   443             # !!! FIXME: don't do this swap every write, just when the samples change.
   444             my $idx = (($channels - $i) - 1);
   445             my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${idx}");
   446             print <<EOF;
   447         dst[$idx] = $val;
   448 EOF
   449         }
   450 
   451         $incr = ($channels == 1) ? 'dst--' : "dst -= $channels";
   452         $incr2 = ($channels == 1) ? 'src--' : "src -= $channels";
   453 
   454         print <<EOF;
   455         $incr;
   456         eps += srcsize;
   457         if ((eps << 1) >= dstsize) {
   458             $incr2;
   459 EOF
   460     } else {  # downsample.
   461         $incr = ($channels == 1) ? 'src++' : "src += $channels";
   462         print <<EOF;
   463         $incr;
   464         eps += dstsize;
   465         if ((eps << 1) >= srcsize) {
   466 EOF
   467         for (my $i = 0; $i < $channels; $i++) {
   468             my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${i}");
   469             print <<EOF;
   470             dst[$i] = $val;
   471 EOF
   472         }
   473 
   474         $incr = ($channels == 1) ? 'dst++' : "dst += $channels";
   475         print <<EOF;
   476             $incr;
   477 EOF
   478     }
   479 
   480     for (my $i = 0; $i < $channels; $i++) {
   481         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   482         my $swapped = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
   483         print <<EOF;
   484             sample${idx} = ($fctype) (((($bigger) $swapped) + (($bigger) last_sample${idx})) $interp);
   485 EOF
   486     }
   487 
   488     for (my $i = 0; $i < $channels; $i++) {
   489         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   490         print <<EOF;
   491             last_sample${idx} = sample${idx};
   492 EOF
   493     }
   494 
   495     print <<EOF;
   496             eps -= $eps_adjust;
   497         }
   498     }
   499 EOF
   500 
   501         print <<EOF;
   502     cvt->len_cvt = dstsize;
   503     if (cvt->filters[++cvt->filter_index]) {
   504         cvt->filters[cvt->filter_index] (cvt, format);
   505     }
   506 }
   507 
   508 EOF
   509 
   510 }
   511 
   512 # These handle clean resamples...doubling and quadrupling the sample rate, etc.
   513 sub buildMultipleResampleFunc {
   514     # !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
   515     my ($from, $channels, $upsample, $multiple) = @_;
   516     my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
   517 
   518     my $bigger = getBiggerCtype($ffloat, $fsize);
   519     my $interp = ($ffloat) ? '* 0.5' : '>> 1';
   520     my $interp2 = ($ffloat) ? '* 0.25' : '>> 2';
   521     my $mult3 = ($ffloat) ? '3.0' : '3';
   522     my $lencvtop = ($upsample) ? '*' : '/';
   523 
   524     my $resample = ($upsample) ? 'Upsample' : 'Downsample';
   525     my $hashid = getResamplerHashId($from, $channels, $upsample, $multiple);
   526     my $sym = "SDL_${resample}_${from}_${channels}c_x${multiple}";
   527     $funcs{$hashid} = $sym;
   528     $custom_converters++;
   529 
   530     # !!! FIXME: DEBUG_CONVERT should report frequencies.
   531     print <<EOF;
   532 static void SDLCALL
   533 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   534 {
   535 #if DEBUG_CONVERT
   536     fprintf(stderr, "$resample (x${multiple}) AUDIO_${from}, ${channels} channels.\\n");
   537 #endif
   538 
   539     const int dstsize = cvt->len_cvt $lencvtop $multiple;
   540 EOF
   541 
   542     my $endcomparison = '!=';
   543 
   544     # Upsampling (growing the buffer) needs to work backwards, since we
   545     #  overwrite the buffer as we go.
   546     if ($upsample) {
   547         $endcomparison = '>';  # dst > target
   548         print <<EOF;
   549     $fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels;
   550     const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
   551     const $fctype *target = ((const $fctype *) cvt->buf) - $channels;
   552 EOF
   553     } else {
   554         $endcomparison = '<';  # dst < target
   555         print <<EOF;
   556     $fctype *dst = ($fctype *) cvt->buf;
   557     const $fctype *src = ($fctype *) cvt->buf;
   558     const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
   559 EOF
   560     }
   561 
   562     for (my $i = 0; $i < $channels; $i++) {
   563         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   564         my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
   565         print <<EOF;
   566     $bigger last_sample${idx} = ($bigger) $val;
   567 EOF
   568     }
   569 
   570     print <<EOF;
   571     while (dst $endcomparison target) {
   572 EOF
   573 
   574     for (my $i = 0; $i < $channels; $i++) {
   575         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   576         my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
   577         print <<EOF;
   578         const $bigger sample${idx} = ($bigger) $val;
   579 EOF
   580     }
   581 
   582     my $incr = '';
   583     if ($upsample) {
   584         $incr = ($channels == 1) ? 'src--' : "src -= $channels";
   585     } else {
   586         my $amount = $channels * $multiple;
   587         $incr = "src += $amount";  # can't ever be 1, so no "++" version.
   588     }
   589 
   590 
   591     print <<EOF;
   592         $incr;
   593 EOF
   594 
   595     # !!! FIXME: This really begs for some Altivec or SSE, etc.
   596     if ($upsample) {
   597         if ($multiple == 2) {
   598             for (my $i = $channels-1; $i >= 0; $i--) {
   599                 my $dsti = $i + $channels;
   600                 print <<EOF;
   601         dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
   602 EOF
   603             }
   604             for (my $i = $channels-1; $i >= 0; $i--) {
   605                 my $dsti = $i;
   606                 print <<EOF;
   607         dst[$dsti] = ($fctype) sample${i};
   608 EOF
   609             }
   610         } elsif ($multiple == 4) {
   611             for (my $i = $channels-1; $i >= 0; $i--) {
   612                 my $dsti = $i + ($channels * 3);
   613                 print <<EOF;
   614         dst[$dsti] = ($fctype) sample${i};
   615 EOF
   616             }
   617 
   618             for (my $i = $channels-1; $i >= 0; $i--) {
   619                 my $dsti = $i + ($channels * 2);
   620                 print <<EOF;
   621         dst[$dsti] = ($fctype) ((($mult3 * sample${i}) + last_sample${i}) $interp2);
   622 EOF
   623             }
   624 
   625             for (my $i = $channels-1; $i >= 0; $i--) {
   626                 my $dsti = $i + ($channels * 1);
   627                 print <<EOF;
   628         dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
   629 EOF
   630             }
   631 
   632             for (my $i = $channels-1; $i >= 0; $i--) {
   633                 my $dsti = $i + ($channels * 0);
   634                 print <<EOF;
   635         dst[$dsti] = ($fctype) ((sample${i} + ($mult3 * last_sample${i})) $interp2);
   636 EOF
   637             }
   638         } else {
   639             die('bug in program.');  # we only handle x2 and x4.
   640         }
   641     } else {  # downsample.
   642         if ($multiple == 2) {
   643             for (my $i = 0; $i < $channels; $i++) {
   644                 print <<EOF;
   645         dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
   646 EOF
   647             }
   648         } elsif ($multiple == 4) {
   649             # !!! FIXME: interpolate all 4 samples?
   650             for (my $i = 0; $i < $channels; $i++) {
   651                 print <<EOF;
   652         dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
   653 EOF
   654             }
   655         } else {
   656             die('bug in program.');  # we only handle x2 and x4.
   657         }
   658     }
   659 
   660     for (my $i = 0; $i < $channels; $i++) {
   661         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   662         print <<EOF;
   663         last_sample${idx} = sample${idx};
   664 EOF
   665     }
   666 
   667     if ($upsample) {
   668         my $amount = $channels * $multiple;
   669         $incr = "dst -= $amount";  # can't ever be 1, so no "--" version.
   670     } else {
   671         $incr = ($channels == 1) ? 'dst++' : "dst += $channels";
   672     }
   673 
   674     print <<EOF;
   675         $incr;
   676     }
   677 
   678     cvt->len_cvt = dstsize;
   679     if (cvt->filters[++cvt->filter_index]) {
   680         cvt->filters[cvt->filter_index] (cvt, format);
   681     }
   682 }
   683 
   684 EOF
   685 
   686 }
   687 
   688 sub buildResamplers {
   689     print "#if !NO_RESAMPLERS\n\n";
   690     foreach (@audiotypes) {
   691         my $from = $_;
   692         foreach (@channels) {
   693             my $channel = $_;
   694             buildArbitraryResampleFunc($from, $channel, 1);
   695             buildArbitraryResampleFunc($from, $channel, 0);
   696         }
   697     }
   698 
   699     print "\n#if !LESS_RESAMPLERS\n\n";
   700     foreach (@audiotypes) {
   701         my $from = $_;
   702         foreach (@channels) {
   703             my $channel = $_;
   704             for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
   705                 buildMultipleResampleFunc($from, $channel, 1, $multiple);
   706                 buildMultipleResampleFunc($from, $channel, 0, $multiple);
   707             }
   708         }
   709     }
   710 
   711     print "#endif  /* !LESS_RESAMPLERS */\n";
   712     print "#endif  /* !NO_RESAMPLERS */\n\n\n";
   713 
   714     print "const SDL_AudioRateFilters sdl_audio_rate_filters[] =\n{\n";
   715     print "#if !NO_RESAMPLERS\n";
   716     foreach (@audiotypes) {
   717         my $from = $_;
   718         foreach (@channels) {
   719             my $channel = $_;
   720             for (my $upsample = 0; $upsample <= 1; $upsample++) {
   721                 my $hashid = getResamplerHashId($from, $channel, $upsample, 0);
   722                 my $sym = $funcs{$hashid};
   723                 print("    { AUDIO_$from, $channel, $upsample, 0, $sym },\n");
   724             }
   725         }
   726     }
   727 
   728     print "#if !LESS_RESAMPLERS\n";
   729     foreach (@audiotypes) {
   730         my $from = $_;
   731         foreach (@channels) {
   732             my $channel = $_;
   733             for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
   734                 for (my $upsample = 0; $upsample <= 1; $upsample++) {
   735                     my $hashid = getResamplerHashId($from, $channel, $upsample, $multiple);
   736                     my $sym = $funcs{$hashid};
   737                     print("    { AUDIO_$from, $channel, $upsample, $multiple, $sym },\n");
   738                 }
   739             }
   740         }
   741     }
   742 
   743     print "#endif  /* !LESS_RESAMPLERS */\n";
   744     print "#endif  /* !NO_RESAMPLERS */\n";
   745     print("    { 0, 0, 0, 0, NULL }\n");
   746     print "};\n\n";
   747 }
   748 
   749 
   750 # mainline ...
   751 
   752 outputHeader();
   753 buildTypeConverters();
   754 buildResamplers();
   755 outputFooter();
   756 
   757 exit 0;
   758 
   759 # end of sdlgenaudiocvt.pl ...
   760