src/audio/sdlgenaudiocvt.pl
author Sam Lantinga
Fri, 08 Apr 2011 13:03:26 -0700
changeset 5535 96594ac5fd1a
parent 5262 b530ef003506
child 5977 4e09b43f2525
permissions -rwxr-xr-x
SDL 1.3 is now under the zlib license.
     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 srcsize = cvt->len_cvt;
   540     const int dstsize = cvt->len_cvt $lencvtop $multiple;
   541 EOF
   542 
   543     my $endcomparison = '!=';
   544 
   545     # Upsampling (growing the buffer) needs to work backwards, since we
   546     #  overwrite the buffer as we go.
   547     if ($upsample) {
   548         $endcomparison = '>';  # dst > target
   549         print <<EOF;
   550     $fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels;
   551     const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
   552     const $fctype *target = ((const $fctype *) cvt->buf) - $channels;
   553 EOF
   554     } else {
   555         $endcomparison = '<';  # dst < target
   556         print <<EOF;
   557     $fctype *dst = ($fctype *) cvt->buf;
   558     const $fctype *src = ($fctype *) cvt->buf;
   559     const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
   560 EOF
   561     }
   562 
   563     for (my $i = 0; $i < $channels; $i++) {
   564         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   565         my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
   566         print <<EOF;
   567     $bigger last_sample${idx} = ($bigger) $val;
   568 EOF
   569     }
   570 
   571     print <<EOF;
   572     while (dst $endcomparison target) {
   573 EOF
   574 
   575     for (my $i = 0; $i < $channels; $i++) {
   576         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   577         my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
   578         print <<EOF;
   579         const $bigger sample${idx} = ($bigger) $val;
   580 EOF
   581     }
   582 
   583     my $incr = '';
   584     if ($upsample) {
   585         $incr = ($channels == 1) ? 'src--' : "src -= $channels";
   586     } else {
   587         my $amount = $channels * $multiple;
   588         $incr = "src += $amount";  # can't ever be 1, so no "++" version.
   589     }
   590 
   591 
   592     print <<EOF;
   593         $incr;
   594 EOF
   595 
   596     # !!! FIXME: This really begs for some Altivec or SSE, etc.
   597     if ($upsample) {
   598         if ($multiple == 2) {
   599             for (my $i = $channels-1; $i >= 0; $i--) {
   600                 my $dsti = $i + $channels;
   601                 print <<EOF;
   602         dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
   603 EOF
   604             }
   605             for (my $i = $channels-1; $i >= 0; $i--) {
   606                 my $dsti = $i;
   607                 print <<EOF;
   608         dst[$dsti] = ($fctype) sample${i};
   609 EOF
   610             }
   611         } elsif ($multiple == 4) {
   612             for (my $i = $channels-1; $i >= 0; $i--) {
   613                 my $dsti = $i + ($channels * 3);
   614                 print <<EOF;
   615         dst[$dsti] = ($fctype) sample${i};
   616 EOF
   617             }
   618 
   619             for (my $i = $channels-1; $i >= 0; $i--) {
   620                 my $dsti = $i + ($channels * 2);
   621                 print <<EOF;
   622         dst[$dsti] = ($fctype) ((($mult3 * sample${i}) + last_sample${i}) $interp2);
   623 EOF
   624             }
   625 
   626             for (my $i = $channels-1; $i >= 0; $i--) {
   627                 my $dsti = $i + ($channels * 1);
   628                 print <<EOF;
   629         dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
   630 EOF
   631             }
   632 
   633             for (my $i = $channels-1; $i >= 0; $i--) {
   634                 my $dsti = $i + ($channels * 0);
   635                 print <<EOF;
   636         dst[$dsti] = ($fctype) ((sample${i} + ($mult3 * last_sample${i})) $interp2);
   637 EOF
   638             }
   639         } else {
   640             die('bug in program.');  # we only handle x2 and x4.
   641         }
   642     } else {  # downsample.
   643         if ($multiple == 2) {
   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         } elsif ($multiple == 4) {
   650             # !!! FIXME: interpolate all 4 samples?
   651             for (my $i = 0; $i < $channels; $i++) {
   652                 print <<EOF;
   653         dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
   654 EOF
   655             }
   656         } else {
   657             die('bug in program.');  # we only handle x2 and x4.
   658         }
   659     }
   660 
   661     for (my $i = 0; $i < $channels; $i++) {
   662         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   663         print <<EOF;
   664         last_sample${idx} = sample${idx};
   665 EOF
   666     }
   667 
   668     if ($upsample) {
   669         my $amount = $channels * $multiple;
   670         $incr = "dst -= $amount";  # can't ever be 1, so no "--" version.
   671     } else {
   672         $incr = ($channels == 1) ? 'dst++' : "dst += $channels";
   673     }
   674 
   675     print <<EOF;
   676         $incr;
   677     }
   678 
   679     cvt->len_cvt = dstsize;
   680     if (cvt->filters[++cvt->filter_index]) {
   681         cvt->filters[cvt->filter_index] (cvt, format);
   682     }
   683 }
   684 
   685 EOF
   686 
   687 }
   688 
   689 sub buildResamplers {
   690     print "#if !NO_RESAMPLERS\n\n";
   691     foreach (@audiotypes) {
   692         my $from = $_;
   693         foreach (@channels) {
   694             my $channel = $_;
   695             buildArbitraryResampleFunc($from, $channel, 1);
   696             buildArbitraryResampleFunc($from, $channel, 0);
   697         }
   698     }
   699 
   700     print "\n#if !LESS_RESAMPLERS\n\n";
   701     foreach (@audiotypes) {
   702         my $from = $_;
   703         foreach (@channels) {
   704             my $channel = $_;
   705             for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
   706                 buildMultipleResampleFunc($from, $channel, 1, $multiple);
   707                 buildMultipleResampleFunc($from, $channel, 0, $multiple);
   708             }
   709         }
   710     }
   711 
   712     print "#endif  /* !LESS_RESAMPLERS */\n";
   713     print "#endif  /* !NO_RESAMPLERS */\n\n\n";
   714 
   715     print "const SDL_AudioRateFilters sdl_audio_rate_filters[] =\n{\n";
   716     print "#if !NO_RESAMPLERS\n";
   717     foreach (@audiotypes) {
   718         my $from = $_;
   719         foreach (@channels) {
   720             my $channel = $_;
   721             for (my $upsample = 0; $upsample <= 1; $upsample++) {
   722                 my $hashid = getResamplerHashId($from, $channel, $upsample, 0);
   723                 my $sym = $funcs{$hashid};
   724                 print("    { AUDIO_$from, $channel, $upsample, 0, $sym },\n");
   725             }
   726         }
   727     }
   728 
   729     print "#if !LESS_RESAMPLERS\n";
   730     foreach (@audiotypes) {
   731         my $from = $_;
   732         foreach (@channels) {
   733             my $channel = $_;
   734             for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
   735                 for (my $upsample = 0; $upsample <= 1; $upsample++) {
   736                     my $hashid = getResamplerHashId($from, $channel, $upsample, $multiple);
   737                     my $sym = $funcs{$hashid};
   738                     print("    { AUDIO_$from, $channel, $upsample, $multiple, $sym },\n");
   739                 }
   740             }
   741         }
   742     }
   743 
   744     print "#endif  /* !LESS_RESAMPLERS */\n";
   745     print "#endif  /* !NO_RESAMPLERS */\n";
   746     print("    { 0, 0, 0, 0, NULL }\n");
   747     print "};\n\n";
   748 }
   749 
   750 
   751 # mainline ...
   752 
   753 outputHeader();
   754 buildTypeConverters();
   755 buildResamplers();
   756 outputFooter();
   757 
   758 exit 0;
   759 
   760 # end of sdlgenaudiocvt.pl ...
   761