src/audio/sdlgenaudiocvt.pl
author Sam Lantinga
Mon, 12 Jan 2009 08:46:28 +0000
changeset 3032 77c3e67f0740
parent 3020 70d876a0b90e
child 3602 bfa8d34ce03a
permissions -rwxr-xr-x
Fixed Visual C++ build
     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 #if 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("    { 0, 0, NULL }\n");
   342     print "};\n\n\n";
   343 }
   344 
   345 sub getBiggerCtype {
   346     my ($isfloat, $size) = @_;
   347 
   348     if ($isfloat) {
   349         if ($size == 32) {
   350             return 'double';
   351         }
   352         die("bug in script.\n");
   353     }
   354 
   355     if ($size == 8) {
   356         return 'Sint16';
   357     } elsif ($size == 16) {
   358         return 'Sint32'
   359     } elsif ($size == 32) {
   360         return 'Sint64'
   361     }
   362 
   363     die("bug in script.\n");
   364 }
   365 
   366 
   367 # These handle arbitrary resamples...44100Hz to 48000Hz, for example.
   368 # Man, this code is skanky.
   369 sub buildArbitraryResampleFunc {
   370     # !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
   371     my ($from, $channels, $upsample) = @_;
   372     my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
   373 
   374     my $bigger = getBiggerCtype($ffloat, $fsize);
   375     my $interp = ($ffloat) ? '* 0.5' : '>> 1';
   376 
   377     my $resample = ($upsample) ? 'Upsample' : 'Downsample';
   378     my $hashid = getResamplerHashId($from, $channels, $upsample, 0);
   379     my $sym = "SDL_${resample}_${from}_${channels}c";
   380     $funcs{$hashid} = $sym;
   381     $custom_converters++;
   382 
   383     my $fudge = $fsize * $channels * 2;  # !!! FIXME
   384     my $eps_adjust = ($upsample) ? 'dstsize' : 'srcsize';
   385     my $incr = '';
   386     my $incr2 = '';
   387 
   388 
   389     # !!! FIXME: DEBUG_CONVERT should report frequencies.
   390     print <<EOF;
   391 static void SDLCALL
   392 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   393 {
   394 #if DEBUG_CONVERT
   395     fprintf(stderr, "$resample arbitrary (x%f) AUDIO_${from}, ${channels} channels.\\n", cvt->rate_incr);
   396 #endif
   397 
   398     const int srcsize = cvt->len_cvt - $fudge;
   399     const int dstsize = (int) (((double)cvt->len_cvt) * cvt->rate_incr);
   400     register int eps = 0;
   401 EOF
   402 
   403     # Upsampling (growing the buffer) needs to work backwards, since we
   404     #  overwrite the buffer as we go.
   405     if ($upsample) {
   406         print <<EOF;
   407     $fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels;
   408     const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
   409     const $fctype *target = ((const $fctype *) cvt->buf) - $channels;
   410 EOF
   411     } else {
   412         print <<EOF;
   413     $fctype *dst = ($fctype *) cvt->buf;
   414     const $fctype *src = ($fctype *) cvt->buf;
   415     const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
   416 EOF
   417     }
   418 
   419     for (my $i = 0; $i < $channels; $i++) {
   420         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   421         my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
   422         print <<EOF;
   423     $fctype sample${idx} = $val;
   424 EOF
   425     }
   426 
   427     for (my $i = 0; $i < $channels; $i++) {
   428         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   429         print <<EOF;
   430     $fctype last_sample${idx} = sample${idx};
   431 EOF
   432     }
   433 
   434     print <<EOF;
   435     while (dst != target) {
   436 EOF
   437 
   438     if ($upsample) {
   439         for (my $i = 0; $i < $channels; $i++) {
   440             # !!! FIXME: don't do this swap every write, just when the samples change.
   441             my $idx = (($channels - $i) - 1);
   442             my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${idx}");
   443             print <<EOF;
   444         dst[$idx] = $val;
   445 EOF
   446         }
   447 
   448         $incr = ($channels == 1) ? 'dst--' : "dst -= $channels";
   449         $incr2 = ($channels == 1) ? 'src--' : "src -= $channels";
   450 
   451         print <<EOF;
   452         $incr;
   453         eps += srcsize;
   454         if ((eps << 1) >= dstsize) {
   455             $incr2;
   456 EOF
   457     } else {  # downsample.
   458         $incr = ($channels == 1) ? 'src++' : "src += $channels";
   459         print <<EOF;
   460         $incr;
   461         eps += dstsize;
   462         if ((eps << 1) >= srcsize) {
   463 EOF
   464         for (my $i = 0; $i < $channels; $i++) {
   465             my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${i}");
   466             print <<EOF;
   467             dst[$i] = $val;
   468 EOF
   469         }
   470 
   471         $incr = ($channels == 1) ? 'dst++' : "dst += $channels";
   472         print <<EOF;
   473             $incr;
   474 EOF
   475     }
   476 
   477     for (my $i = 0; $i < $channels; $i++) {
   478         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   479         my $swapped = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
   480         print <<EOF;
   481             sample${idx} = ($fctype) (((($bigger) $swapped) + (($bigger) last_sample${idx})) $interp);
   482 EOF
   483     }
   484 
   485     for (my $i = 0; $i < $channels; $i++) {
   486         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   487         print <<EOF;
   488             last_sample${idx} = sample${idx};
   489 EOF
   490     }
   491 
   492     print <<EOF;
   493             eps -= $eps_adjust;
   494         }
   495     }
   496 EOF
   497 
   498         print <<EOF;
   499     cvt->len_cvt = dstsize;
   500     if (cvt->filters[++cvt->filter_index]) {
   501         cvt->filters[cvt->filter_index] (cvt, format);
   502     }
   503 }
   504 
   505 EOF
   506 
   507 }
   508 
   509 # These handle clean resamples...doubling and quadrupling the sample rate, etc.
   510 sub buildMultipleResampleFunc {
   511     # !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
   512     my ($from, $channels, $upsample, $multiple) = @_;
   513     my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
   514 
   515     my $bigger = getBiggerCtype($ffloat, $fsize);
   516     my $interp = ($ffloat) ? '* 0.5' : '>> 1';
   517     my $interp2 = ($ffloat) ? '* 0.25' : '>> 2';
   518     my $mult3 = ($ffloat) ? '3.0' : '3';
   519     my $lencvtop = ($upsample) ? '*' : '/';
   520 
   521     my $resample = ($upsample) ? 'Upsample' : 'Downsample';
   522     my $hashid = getResamplerHashId($from, $channels, $upsample, $multiple);
   523     my $sym = "SDL_${resample}_${from}_${channels}c_x${multiple}";
   524     $funcs{$hashid} = $sym;
   525     $custom_converters++;
   526 
   527     # !!! FIXME: DEBUG_CONVERT should report frequencies.
   528     print <<EOF;
   529 static void SDLCALL
   530 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   531 {
   532 #if DEBUG_CONVERT
   533     fprintf(stderr, "$resample (x${multiple}) AUDIO_${from}, ${channels} channels.\\n");
   534 #endif
   535 
   536     const int srcsize = cvt->len_cvt;
   537     const int dstsize = cvt->len_cvt $lencvtop $multiple;
   538 EOF
   539 
   540     # Upsampling (growing the buffer) needs to work backwards, since we
   541     #  overwrite the buffer as we go.
   542     if ($upsample) {
   543         print <<EOF;
   544     $fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels;
   545     const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
   546     const $fctype *target = ((const $fctype *) cvt->buf) - $channels;
   547 EOF
   548     } else {
   549         print <<EOF;
   550     $fctype *dst = ($fctype *) cvt->buf;
   551     const $fctype *src = ($fctype *) cvt->buf;
   552     const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
   553 EOF
   554     }
   555 
   556     for (my $i = 0; $i < $channels; $i++) {
   557         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   558         my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
   559         print <<EOF;
   560     $bigger last_sample${idx} = ($bigger) $val;
   561 EOF
   562     }
   563 
   564     print <<EOF;
   565     while (dst != target) {
   566 EOF
   567 
   568     for (my $i = 0; $i < $channels; $i++) {
   569         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   570         my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
   571         print <<EOF;
   572         const $bigger sample${idx} = ($bigger) $val;
   573 EOF
   574     }
   575 
   576     my $incr = '';
   577     if ($upsample) {
   578         $incr = ($channels == 1) ? 'src--' : "src -= $channels";
   579     } else {
   580         my $amount = $channels * $multiple;
   581         $incr = "src += $amount";  # can't ever be 1, so no "++" version.
   582     }
   583 
   584 
   585     print <<EOF;
   586         $incr;
   587 EOF
   588 
   589     # !!! FIXME: This really begs for some Altivec or SSE, etc.
   590     if ($upsample) {
   591         if ($multiple == 2) {
   592             for (my $i = $channels-1; $i >= 0; $i--) {
   593                 my $dsti = $i + $channels;
   594                 print <<EOF;
   595         dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
   596 EOF
   597             }
   598             for (my $i = $channels-1; $i >= 0; $i--) {
   599                 my $dsti = $i;
   600                 print <<EOF;
   601         dst[$dsti] = ($fctype) sample${i};
   602 EOF
   603             }
   604         } elsif ($multiple == 4) {
   605             for (my $i = $channels-1; $i >= 0; $i--) {
   606                 my $dsti = $i + ($channels * 3);
   607                 print <<EOF;
   608         dst[$dsti] = ($fctype) sample${i};
   609 EOF
   610             }
   611 
   612             for (my $i = $channels-1; $i >= 0; $i--) {
   613                 my $dsti = $i + ($channels * 2);
   614                 print <<EOF;
   615         dst[$dsti] = ($fctype) ((($mult3 * sample${i}) + last_sample${i}) $interp2);
   616 EOF
   617             }
   618 
   619             for (my $i = $channels-1; $i >= 0; $i--) {
   620                 my $dsti = $i + ($channels * 1);
   621                 print <<EOF;
   622         dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
   623 EOF
   624             }
   625 
   626             for (my $i = $channels-1; $i >= 0; $i--) {
   627                 my $dsti = $i + ($channels * 0);
   628                 print <<EOF;
   629         dst[$dsti] = ($fctype) ((sample${i} + ($mult3 * last_sample${i})) $interp2);
   630 EOF
   631             }
   632         } else {
   633             die('bug in program.');  # we only handle x2 and x4.
   634         }
   635     } else {  # downsample.
   636         if ($multiple == 2) {
   637             for (my $i = 0; $i < $channels; $i++) {
   638                 print <<EOF;
   639         dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
   640 EOF
   641             }
   642         } elsif ($multiple == 4) {
   643             # !!! FIXME: interpolate all 4 samples?
   644             for (my $i = 0; $i < $channels; $i++) {
   645                 print <<EOF;
   646         dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
   647 EOF
   648             }
   649         } else {
   650             die('bug in program.');  # we only handle x2 and x4.
   651         }
   652     }
   653 
   654     for (my $i = 0; $i < $channels; $i++) {
   655         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   656         print <<EOF;
   657         last_sample${idx} = sample${idx};
   658 EOF
   659     }
   660 
   661     if ($upsample) {
   662         my $amount = $channels * $multiple;
   663         $incr = "dst -= $amount";  # can't ever be 1, so no "--" version.
   664     } else {
   665         $incr = ($channels == 1) ? 'dst++' : "dst += $channels";
   666     }
   667 
   668     print <<EOF;
   669         $incr;
   670     }
   671 
   672     cvt->len_cvt = dstsize;
   673     if (cvt->filters[++cvt->filter_index]) {
   674         cvt->filters[cvt->filter_index] (cvt, format);
   675     }
   676 }
   677 
   678 EOF
   679 
   680 }
   681 
   682 sub buildResamplers {
   683     print "#if !NO_RESAMPLERS\n\n";
   684     foreach (@audiotypes) {
   685         my $from = $_;
   686         foreach (@channels) {
   687             my $channel = $_;
   688             buildArbitraryResampleFunc($from, $channel, 1);
   689             buildArbitraryResampleFunc($from, $channel, 0);
   690         }
   691     }
   692 
   693     print "\n#if !LESS_RESAMPLERS\n\n";
   694     foreach (@audiotypes) {
   695         my $from = $_;
   696         foreach (@channels) {
   697             my $channel = $_;
   698             for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
   699                 buildMultipleResampleFunc($from, $channel, 1, $multiple);
   700                 buildMultipleResampleFunc($from, $channel, 0, $multiple);
   701             }
   702         }
   703     }
   704 
   705     print "#endif  /* !LESS_RESAMPLERS */\n";
   706     print "#endif  /* !NO_RESAMPLERS */\n\n\n";
   707 
   708     print "const SDL_AudioRateFilters sdl_audio_rate_filters[] =\n{\n";
   709     print "#if !NO_RESAMPLERS\n";
   710     foreach (@audiotypes) {
   711         my $from = $_;
   712         foreach (@channels) {
   713             my $channel = $_;
   714             for (my $upsample = 0; $upsample <= 1; $upsample++) {
   715                 my $hashid = getResamplerHashId($from, $channel, $upsample, 0);
   716                 my $sym = $funcs{$hashid};
   717                 print("    { AUDIO_$from, $channel, $upsample, 0, $sym },\n");
   718             }
   719         }
   720     }
   721 
   722     print "#if !LESS_RESAMPLERS\n";
   723     foreach (@audiotypes) {
   724         my $from = $_;
   725         foreach (@channels) {
   726             my $channel = $_;
   727             for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
   728                 for (my $upsample = 0; $upsample <= 1; $upsample++) {
   729                     my $hashid = getResamplerHashId($from, $channel, $upsample, $multiple);
   730                     my $sym = $funcs{$hashid};
   731                     print("    { AUDIO_$from, $channel, $upsample, $multiple, $sym },\n");
   732                 }
   733             }
   734         }
   735     }
   736 
   737     print "#endif  /* !LESS_RESAMPLERS */\n";
   738     print "#endif  /* !NO_RESAMPLERS */\n";
   739     print("    { 0, 0, 0, 0, NULL }\n");
   740     print "};\n\n";
   741 }
   742 
   743 
   744 # mainline ...
   745 
   746 outputHeader();
   747 buildTypeConverters();
   748 buildResamplers();
   749 outputFooter();
   750 
   751 exit 0;
   752 
   753 # end of sdlgenaudiocvt.pl ...
   754