src/audio/sdlgenaudiocvt.pl
author Ryan C. Gordon
Thu, 24 Aug 2006 12:10:46 +0000
changeset 1982 3b4ce57c6215
child 1985 8055185ae4ed
permissions -rwxr-xr-x
First shot at new audio data types (int32 and float32).

Notable changes:
- Converters between types are autogenerated. Instead of making multiple
passes over the data with seperate filters for endianess, size, signedness,
etc, converting between data types is always one specialized filter. This
simplifies SDL_BuildAudioCVT(), which otherwise had a million edge cases
with the new types, and makes the actually conversions more CPU cache
friendly. Left a stub for adding specific optimized versions of these
routines (SSE/MMX/Altivec, assembler, etc)
- Autogenerated converters are built by SDL/src/audio/sdlgenaudiocvt.pl. This
does not need to be run unless tweaking the code, and thus doesn't need
integration into the build system.
- Went through all the drivers and tried to weed out all the "Uint16"
references that are better specified with the new SDL_AudioFormat typedef.
- Cleaned out a bunch of hardcoded bitwise magic numbers and replaced them
with new SDL_AUDIO_* macros.
- Added initial float32 and int32 support code. Theoretically, existing
drivers will push these through converters to get the data they want to
feed to the hardware.

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