src/audio/sdlgenaudiocvt.pl
author Ryan C. Gordon
Fri, 02 Jan 2009 07:34:01 +0000
changeset 2955 2692999d5271
parent 2859 99210400e8b9
child 2956 1210d5a28e16
permissions -rwxr-xr-x
Avoid unnecessary assignment in generated audio type converters.
     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 %funcs;
    20 
    21 my $custom_converters = 0;
    22 
    23 
    24 sub outputHeader {
    25     print <<EOF;
    26 /* DO NOT EDIT!  This file is generated by sdlgenaudiocvt.pl */
    27 /*
    28     SDL - Simple DirectMedia Layer
    29     Copyright (C) 1997-2009 Sam Lantinga
    30 
    31     This library is free software; you can redistribute it and/or
    32     modify it under the terms of the GNU Lesser General Public
    33     License as published by the Free Software Foundation; either
    34     version 2.1 of the License, or (at your option) any later version.
    35 
    36     This library is distributed in the hope that it will be useful,
    37     but WITHOUT ANY WARRANTY; without even the implied warranty of
    38     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    39     Lesser General Public License for more details.
    40 
    41     You should have received a copy of the GNU Lesser General Public
    42     License along with this library; if not, write to the Free Software
    43     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    44 
    45     Sam Lantinga
    46     slouken\@libsdl.org
    47 */
    48 
    49 #include "SDL_config.h"
    50 #include "SDL_audio.h"
    51 #include "SDL_audio_c.h"
    52 
    53 /* *INDENT-OFF* */
    54 
    55 EOF
    56 
    57     my @vals = ( 127, 32767, 2147483647 );
    58     foreach (@vals) {
    59         my $val = $_;
    60         my $fval = 1.0 / $val;
    61         print("#define DIVBY${val} ${fval}f\n");
    62     }
    63 
    64     print("\n");
    65 }
    66 
    67 sub outputFooter {
    68     print <<EOF;
    69 /* *INDENT-ON* */
    70 
    71 /* vi: set ts=4 sw=4 expandtab: */
    72 EOF
    73 }
    74 
    75 sub splittype {
    76     my $t = shift;
    77     my ($signed, $size, $endian) = $t =~ /([USF])(\d+)([LM]SB|)/;
    78     my $float = ($signed eq 'F') ? 1 : 0;
    79     $signed = (($float) or ($signed eq 'S')) ? 1 : 0;
    80     $endian = 'NONE' if ($endian eq '');
    81 
    82     my $ctype = '';
    83     if ($float) {
    84         $ctype = (($size == 32) ? 'float' : 'double');
    85     } else {
    86         $ctype = (($signed) ? 'S' : 'U') . "int${size}";
    87     }
    88 
    89     return ($signed, $float, $size, $endian, $ctype);
    90 }
    91 
    92 sub getSwapFunc {
    93     my ($size, $signed, $float, $endian, $val) = @_;
    94     my $BEorLE = (($endian eq 'MSB') ? 'BE' : 'LE');
    95     my $code = '';
    96 
    97     if ($float) {
    98         $code = "SDL_SwapFloat${BEorLE}($val)";
    99     } else {
   100         if ($size > 8) {
   101             $code = "SDL_Swap${BEorLE}${size}($val)";
   102         } else {
   103             $code = $val;
   104         }
   105 
   106         if (($signed) and (!$float)) {
   107             $code = "((Sint${size}) $code)";
   108         }
   109     }
   110 
   111     return "${code}";
   112 }
   113 
   114 
   115 sub maxIntVal {
   116     my $size = shift;
   117     if ($size == 8) {
   118         return 0x7F;
   119     } elsif ($size == 16) {
   120         return 0x7FFF;
   121     } elsif ($size == 32) {
   122         return 0x7FFFFFFF;
   123     }
   124 
   125     die("bug in script.\n");
   126 }
   127 
   128 sub getFloatToIntMult {
   129     my $size = shift;
   130     my $val = maxIntVal($size) . '.0';
   131     $val .= 'f' if ($size < 32);
   132     return $val;
   133 }
   134 
   135 sub getIntToFloatDivBy {
   136     my $size = shift;
   137     return 'DIVBY' . maxIntVal($size);
   138 }
   139 
   140 sub getSignFlipVal {
   141     my $size = shift;
   142     if ($size == 8) {
   143         return '0x80';
   144     } elsif ($size == 16) {
   145         return '0x8000';
   146     } elsif ($size == 32) {
   147         return '0x80000000';
   148     }
   149 
   150     die("bug in script.\n");
   151 }
   152 
   153 sub buildCvtFunc {
   154     my ($from, $to) = @_;
   155     my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
   156     my ($tsigned, $tfloat, $tsize, $tendian, $tctype) = splittype($to);
   157     my $diffs = 0;
   158     $diffs++ if ($fsize != $tsize);
   159     $diffs++ if ($fsigned != $tsigned);
   160     $diffs++ if ($ffloat != $tfloat);
   161     $diffs++ if ($fendian ne $tendian);
   162 
   163     return if ($diffs == 0);
   164 
   165     my $hashid = "$from/$to";
   166     if (1) { # !!! FIXME: if ($diffs > 1) {
   167         my $sym = "SDL_Convert_${from}_to_${to}";
   168         $funcs{$hashid} = $sym;
   169         $custom_converters++;
   170 
   171         # Always unsigned for ints, for possible byteswaps.
   172         my $srctype = (($ffloat) ? 'float' : "Uint${fsize}");
   173 
   174         print <<EOF;
   175 static void SDLCALL
   176 ${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   177 {
   178     int i;
   179     const $srctype *src;
   180     $tctype *dst;
   181 
   182 #ifdef DEBUG_CONVERT
   183     fprintf(stderr, "Converting AUDIO_${from} to AUDIO_${to}.\\n");
   184 #endif
   185 
   186 EOF
   187 
   188         if ($fsize < $tsize) {
   189             my $mult = $tsize / $fsize;
   190             print <<EOF;
   191     src = (const $srctype *) (cvt->buf + cvt->len_cvt);
   192     dst = ($tctype *) (cvt->buf + cvt->len_cvt * $mult);
   193     for (i = cvt->len_cvt / sizeof ($srctype); i; --i, --src, --dst) {
   194 EOF
   195         } else {
   196             print <<EOF;
   197     src = (const $srctype *) cvt->buf;
   198     dst = ($tctype *) cvt->buf;
   199     for (i = cvt->len_cvt / sizeof ($srctype); i; --i, ++src, ++dst) {
   200 EOF
   201         }
   202 
   203         # Have to convert to/from float/int.
   204         # !!! FIXME: cast through double for int32<->float?
   205         my $code = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, '*src');
   206         if ($ffloat != $tfloat) {
   207             if ($ffloat) {
   208                 my $mult = getFloatToIntMult($tsize);
   209                 if (!$tsigned) {   # bump from -1.0f/1.0f to 0.0f/2.0f
   210                     $code = "($code + 1.0f)";
   211                 }
   212                 $code = "(($tctype) ($code * $mult))";
   213             } else {
   214                 # $divby will be the reciprocal, to avoid pipeline stalls
   215                 #  from floating point division...so multiply it.
   216                 my $divby = getIntToFloatDivBy($fsize);
   217                 $code = "(((float) $code) * $divby)";
   218                 if (!$fsigned) {   # bump from 0.0f/2.0f to -1.0f/1.0f.
   219                     $code = "($code - 1.0f)";
   220                 }
   221             }
   222         } else {
   223             # All integer conversions here.
   224             if ($fsigned != $tsigned) {
   225                 my $signflipval = getSignFlipVal($fsize);
   226                 $code = "(($code) ^ $signflipval)";
   227             }
   228 
   229             my $shiftval = abs($fsize - $tsize);
   230             if ($fsize < $tsize) {
   231                 $code = "((($tctype) $code) << $shiftval)";
   232             } elsif ($fsize > $tsize) {
   233                 $code = "(($tctype) ($code >> $shiftval))";
   234             }
   235         }
   236 
   237         my $swap = getSwapFunc($tsize, $tsigned, $tfloat, $tendian, 'val');
   238 
   239         print <<EOF;
   240         const $tctype val = $code;
   241         *dst = ${swap};
   242     }
   243 
   244 EOF
   245 
   246         if ($fsize > $tsize) {
   247             my $divby = $fsize / $tsize;
   248             print("    cvt->len_cvt /= $divby;\n");
   249         } elsif ($fsize < $tsize) {
   250             my $mult = $tsize / $fsize;
   251             print("    cvt->len_cvt *= $mult;\n");
   252         }
   253 
   254         print <<EOF;
   255     if (cvt->filters[++cvt->filter_index]) {
   256         cvt->filters[cvt->filter_index] (cvt, AUDIO_$to);
   257     }
   258 }
   259 
   260 EOF
   261 
   262     } else {
   263         if ($fsigned != $tsigned) {
   264             $funcs{$hashid} = 'SDL_ConvertSigned';
   265         } elsif ($ffloat != $tfloat) {
   266             $funcs{$hashid} = 'SDL_ConvertFloat';
   267         } elsif ($fsize != $tsize) {
   268             $funcs{$hashid} = 'SDL_ConvertSize';
   269         } elsif ($fendian ne $tendian) {
   270             $funcs{$hashid} = 'SDL_ConvertEndian';
   271         } else {
   272             die("error in script.\n");
   273         }
   274     }
   275 }
   276 
   277 outputHeader();
   278 
   279 foreach (@audiotypes) {
   280     my $from = $_;
   281     foreach (@audiotypes) {
   282         my $to = $_;
   283         buildCvtFunc($from, $to);
   284     }
   285 }
   286 
   287 print <<EOF;
   288 const SDL_AudioTypeFilters sdl_audio_type_filters[] =
   289 {
   290 EOF
   291 
   292 foreach (@audiotypes) {
   293     my $from = $_;
   294     foreach (@audiotypes) {
   295         my $to = $_;
   296         if ($from ne $to) {
   297             my $hashid = "$from/$to";
   298             my $sym = $funcs{$hashid};
   299             print("    { AUDIO_$from, AUDIO_$to, $sym },\n");
   300         }
   301     }
   302 }
   303 
   304 print <<EOF;
   305 };
   306 
   307 
   308 EOF
   309 
   310 outputFooter();
   311 
   312 exit 0;
   313 
   314 # end of sdlgenaudiocvt.pl ...
   315