src/audio/sdlgenaudiocvt.pl
author Ryan C. Gordon
Sun, 11 Jan 2009 04:39:09 +0000
changeset 3019 dfd23eb79be9
parent 3008 786a48f8309c
child 3020 70d876a0b90e
permissions -rwxr-xr-x
Allow builds that reduce or eliminate the converters/resamplers.

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