src/audio/sdlgenaudiocvt.pl
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sun, 22 Feb 2015 23:21:32 +0100
changeset 9373 679eb3986e37
parent 8856 5da12bedaace
child 9619 b94b6d0bff0f
permissions -rwxr-xr-x
Emscripten: Fixed out of range joystick device index after joystick disconnect.

After disconnecting a joystick the remaining kept their original device index.
This was not correct because the device index must be a number between 0 and
SDL_NumJoysticks(). It was fixed with ideas from SDL's joystick implementation
for Android. Some range checks were removed as the caller already checks them.
     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-2014 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_internal.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     my $block_align = $channels * $fsize/8;
   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/${block_align})) * cvt->rate_incr) * ${block_align};
   400     register int eps = 0;
   401 EOF
   402 
   403     my $endcomparison = '!=';
   404 
   405     # Upsampling (growing the buffer) needs to work backwards, since we
   406     #  overwrite the buffer as we go.
   407     if ($upsample) {
   408         $endcomparison = '>=';  # dst > target
   409         print <<EOF;
   410     $fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels;
   411     const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
   412     const $fctype *target = ((const $fctype *) cvt->buf);
   413 EOF
   414     } else {
   415         $endcomparison = '<';  # dst < target
   416         print <<EOF;
   417     $fctype *dst = ($fctype *) cvt->buf;
   418     const $fctype *src = ($fctype *) cvt->buf;
   419     const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
   420 EOF
   421     }
   422 
   423     for (my $i = 0; $i < $channels; $i++) {
   424         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   425         my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
   426         print <<EOF;
   427     $fctype sample${idx} = $val;
   428 EOF
   429     }
   430 
   431     for (my $i = 0; $i < $channels; $i++) {
   432         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   433         print <<EOF;
   434     $fctype last_sample${idx} = sample${idx};
   435 EOF
   436     }
   437 
   438     print <<EOF;
   439     while (dst $endcomparison target) {
   440 EOF
   441 
   442     if ($upsample) {
   443         for (my $i = 0; $i < $channels; $i++) {
   444             # !!! FIXME: don't do this swap every write, just when the samples change.
   445             my $idx = (($channels - $i) - 1);
   446             my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${idx}");
   447             print <<EOF;
   448         dst[$idx] = $val;
   449 EOF
   450         }
   451 
   452         $incr = ($channels == 1) ? 'dst--' : "dst -= $channels";
   453         $incr2 = ($channels == 1) ? 'src--' : "src -= $channels";
   454 
   455         print <<EOF;
   456         $incr;
   457         eps += srcsize;
   458         if ((eps << 1) >= dstsize) {
   459             $incr2;
   460 EOF
   461     } else {  # downsample.
   462         $incr = ($channels == 1) ? 'src++' : "src += $channels";
   463         print <<EOF;
   464         $incr;
   465         eps += dstsize;
   466         if ((eps << 1) >= srcsize) {
   467 EOF
   468         for (my $i = 0; $i < $channels; $i++) {
   469             my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${i}");
   470             print <<EOF;
   471             dst[$i] = $val;
   472 EOF
   473         }
   474 
   475         $incr = ($channels == 1) ? 'dst++' : "dst += $channels";
   476         print <<EOF;
   477             $incr;
   478 EOF
   479     }
   480 
   481     for (my $i = 0; $i < $channels; $i++) {
   482         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   483         my $swapped = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
   484         print <<EOF;
   485             sample${idx} = ($fctype) (((($bigger) $swapped) + (($bigger) last_sample${idx})) $interp);
   486 EOF
   487     }
   488 
   489     for (my $i = 0; $i < $channels; $i++) {
   490         my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
   491         print <<EOF;
   492             last_sample${idx} = sample${idx};
   493 EOF
   494     }
   495 
   496     print <<EOF;
   497             eps -= $eps_adjust;
   498         }
   499     }
   500 EOF
   501 
   502         print <<EOF;
   503     cvt->len_cvt = dstsize;
   504     if (cvt->filters[++cvt->filter_index]) {
   505         cvt->filters[cvt->filter_index] (cvt, format);
   506     }
   507 }
   508 
   509 EOF
   510 
   511 }
   512 
   513 # These handle clean resamples...doubling and quadrupling the sample rate, etc.
   514 sub buildMultipleResampleFunc {
   515     # !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
   516     my ($from, $channels, $upsample, $multiple) = @_;
   517     my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
   518 
   519     my $bigger = getBiggerCtype($ffloat, $fsize);
   520     my $interp = ($ffloat) ? '* 0.5' : '>> 1';
   521     my $interp2 = ($ffloat) ? '* 0.25' : '>> 2';
   522     my $mult3 = ($ffloat) ? '3.0' : '3';
   523     my $lencvtop = ($upsample) ? '*' : '/';
   524 
   525     my $resample = ($upsample) ? 'Upsample' : 'Downsample';
   526     my $hashid = getResamplerHashId($from, $channels, $upsample, $multiple);
   527     my $sym = "SDL_${resample}_${from}_${channels}c_x${multiple}";
   528     $funcs{$hashid} = $sym;
   529     $custom_converters++;
   530 
   531     # !!! FIXME: DEBUG_CONVERT should report frequencies.
   532     print <<EOF;
   533 static void SDLCALL
   534 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   535 {
   536 #if DEBUG_CONVERT
   537     fprintf(stderr, "$resample (x${multiple}) AUDIO_${from}, ${channels} channels.\\n");
   538 #endif
   539 
   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 * $multiple;
   551     const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
   552     const $fctype *target = ((const $fctype *) cvt->buf);
   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} + ($mult3 * last_sample${i})) $interp2);
   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) ((sample${i} + last_sample${i}) $interp);
   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) ((($mult3 * sample${i}) + last_sample${i}) $interp2);
   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};
   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