src/audio/sdlgenaudiocvt.pl
author Sam Lantinga
Mon, 08 Dec 2008 00:27:32 +0000
changeset 2859 99210400e8b9
parent 2011 b2b7154ce016
child 2955 2692999d5271
permissions -rwxr-xr-x
Updated copyright date
     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     format = AUDIO_$to;
   256     if (cvt->filters[++cvt->filter_index]) {
   257         cvt->filters[cvt->filter_index] (cvt, format);
   258     }
   259 }
   260 
   261 EOF
   262 
   263     } else {
   264         if ($fsigned != $tsigned) {
   265             $funcs{$hashid} = 'SDL_ConvertSigned';
   266         } elsif ($ffloat != $tfloat) {
   267             $funcs{$hashid} = 'SDL_ConvertFloat';
   268         } elsif ($fsize != $tsize) {
   269             $funcs{$hashid} = 'SDL_ConvertSize';
   270         } elsif ($fendian ne $tendian) {
   271             $funcs{$hashid} = 'SDL_ConvertEndian';
   272         } else {
   273             die("error in script.\n");
   274         }
   275     }
   276 }
   277 
   278 outputHeader();
   279 
   280 foreach (@audiotypes) {
   281     my $from = $_;
   282     foreach (@audiotypes) {
   283         my $to = $_;
   284         buildCvtFunc($from, $to);
   285     }
   286 }
   287 
   288 print <<EOF;
   289 const SDL_AudioTypeFilters sdl_audio_type_filters[] =
   290 {
   291 EOF
   292 
   293 foreach (@audiotypes) {
   294     my $from = $_;
   295     foreach (@audiotypes) {
   296         my $to = $_;
   297         if ($from ne $to) {
   298             my $hashid = "$from/$to";
   299             my $sym = $funcs{$hashid};
   300             print("    { AUDIO_$from, AUDIO_$to, $sym },\n");
   301         }
   302     }
   303 }
   304 
   305 print <<EOF;
   306 };
   307 
   308 
   309 EOF
   310 
   311 outputFooter();
   312 
   313 exit 0;
   314 
   315 # end of sdlgenaudiocvt.pl ...
   316