src/audio/sdlgenaudiocvt.pl
author Ryan C. Gordon <icculus@icculus.org>
Tue, 26 May 2015 21:19:23 -0400
changeset 9649 d7762e30ba24
parent 9619 b94b6d0bff0f
child 9998 f67cf37e9cd4
permissions -rwxr-xr-x
Stack hint should look for 0, not -1, and not care about environment variables.
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@3008
    19
my @channels = ( 1, 2, 4, 6, 8 );
icculus@1982
    20
my %funcs;
icculus@3008
    21
my $custom_converters = 0;
icculus@1982
    22
icculus@3008
    23
icculus@3008
    24
sub getTypeConvertHashId {
icculus@3008
    25
    my ($from, $to) = @_;
icculus@3008
    26
    return "TYPECONVERTER $from/$to";
icculus@3008
    27
}
icculus@3008
    28
icculus@3008
    29
icculus@3008
    30
sub getResamplerHashId {
icculus@3008
    31
    my ($from, $channels, $upsample, $multiple) = @_;
icculus@3008
    32
    return "RESAMPLER $from/$channels/$upsample/$multiple";
icculus@3008
    33
}
icculus@1982
    34
icculus@1982
    35
icculus@1982
    36
sub outputHeader {
icculus@1982
    37
    print <<EOF;
slouken@1985
    38
/* DO NOT EDIT!  This file is generated by sdlgenaudiocvt.pl */
icculus@1982
    39
/*
slouken@5535
    40
  Simple DirectMedia Layer
slouken@9619
    41
  Copyright (C) 1997-2015 Sam Lantinga <slouken\@libsdl.org>
icculus@1982
    42
slouken@5535
    43
  This software is provided 'as-is', without any express or implied
slouken@5535
    44
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
    45
  arising from the use of this software.
icculus@1982
    46
slouken@5535
    47
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    48
  including commercial applications, and to alter it and redistribute it
slouken@5535
    49
  freely, subject to the following restrictions:
icculus@1982
    50
slouken@5535
    51
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    52
     claim that you wrote the original software. If you use this software
slouken@5535
    53
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    54
     appreciated but is not required.
slouken@5535
    55
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    56
     misrepresented as being the original software.
slouken@5535
    57
  3. This notice may not be removed or altered from any source distribution.
icculus@1982
    58
*/
icculus@1982
    59
icculus@8093
    60
#include "../SDL_internal.h"
icculus@1982
    61
#include "SDL_audio.h"
icculus@1982
    62
#include "SDL_audio_c.h"
icculus@1982
    63
icculus@3019
    64
#ifndef DEBUG_CONVERT
icculus@3019
    65
#define DEBUG_CONVERT 0
icculus@3019
    66
#endif
icculus@3019
    67
icculus@3019
    68
icculus@3019
    69
/* If you can guarantee your data and need space, you can eliminate code... */
icculus@3019
    70
icculus@3019
    71
/* Just build the arbitrary resamplers if you're saving code space. */
icculus@3019
    72
#ifndef LESS_RESAMPLERS
icculus@3019
    73
#define LESS_RESAMPLERS 0
icculus@3019
    74
#endif
icculus@3019
    75
icculus@3019
    76
/* Don't build any resamplers if you're REALLY saving code space. */
icculus@3019
    77
#ifndef NO_RESAMPLERS
icculus@3019
    78
#define NO_RESAMPLERS 0
icculus@3019
    79
#endif
icculus@3019
    80
icculus@3019
    81
/* Don't build any type converters if you're saving code space. */
icculus@3019
    82
#ifndef NO_CONVERTERS
icculus@3019
    83
#define NO_CONVERTERS 0
icculus@3019
    84
#endif
icculus@3019
    85
icculus@3019
    86
slouken@1985
    87
/* *INDENT-OFF* */
icculus@1982
    88
icculus@1982
    89
EOF
icculus@1982
    90
icculus@2011
    91
    my @vals = ( 127, 32767, 2147483647 );
icculus@1982
    92
    foreach (@vals) {
icculus@1982
    93
        my $val = $_;
icculus@1982
    94
        my $fval = 1.0 / $val;
icculus@1982
    95
        print("#define DIVBY${val} ${fval}f\n");
icculus@1982
    96
    }
icculus@1982
    97
icculus@1982
    98
    print("\n");
icculus@1982
    99
}
icculus@1982
   100
slouken@1985
   101
sub outputFooter {
slouken@1985
   102
    print <<EOF;
icculus@3008
   103
/* $custom_converters converters generated. */
icculus@3008
   104
slouken@1985
   105
/* *INDENT-ON* */
slouken@1985
   106
slouken@1985
   107
/* vi: set ts=4 sw=4 expandtab: */
slouken@1985
   108
EOF
slouken@1985
   109
}
icculus@1982
   110
icculus@1982
   111
sub splittype {
icculus@1982
   112
    my $t = shift;
icculus@1982
   113
    my ($signed, $size, $endian) = $t =~ /([USF])(\d+)([LM]SB|)/;
icculus@1982
   114
    my $float = ($signed eq 'F') ? 1 : 0;
icculus@1982
   115
    $signed = (($float) or ($signed eq 'S')) ? 1 : 0;
icculus@1982
   116
    $endian = 'NONE' if ($endian eq '');
icculus@1982
   117
icculus@1982
   118
    my $ctype = '';
icculus@1982
   119
    if ($float) {
icculus@1982
   120
        $ctype = (($size == 32) ? 'float' : 'double');
icculus@1982
   121
    } else {
icculus@1982
   122
        $ctype = (($signed) ? 'S' : 'U') . "int${size}";
icculus@1982
   123
    }
icculus@1982
   124
icculus@1982
   125
    return ($signed, $float, $size, $endian, $ctype);
icculus@1982
   126
}
icculus@1982
   127
icculus@1982
   128
sub getSwapFunc {
icculus@1982
   129
    my ($size, $signed, $float, $endian, $val) = @_;
icculus@1982
   130
    my $BEorLE = (($endian eq 'MSB') ? 'BE' : 'LE');
icculus@1982
   131
    my $code = '';
icculus@1982
   132
icculus@1982
   133
    if ($float) {
icculus@1982
   134
        $code = "SDL_SwapFloat${BEorLE}($val)";
icculus@1982
   135
    } else {
icculus@1982
   136
        if ($size > 8) {
icculus@1982
   137
            $code = "SDL_Swap${BEorLE}${size}($val)";
icculus@1982
   138
        } else {
icculus@1982
   139
            $code = $val;
icculus@1982
   140
        }
icculus@1982
   141
icculus@1982
   142
        if (($signed) and (!$float)) {
icculus@1982
   143
            $code = "((Sint${size}) $code)";
icculus@1982
   144
        }
icculus@1982
   145
    }
icculus@1982
   146
icculus@1982
   147
    return "${code}";
icculus@1982
   148
}
icculus@1982
   149
icculus@1982
   150
icculus@1982
   151
sub maxIntVal {
icculus@2011
   152
    my $size = shift;
icculus@2011
   153
    if ($size == 8) {
icculus@2011
   154
        return 0x7F;
icculus@2011
   155
    } elsif ($size == 16) {
icculus@2011
   156
        return 0x7FFF;
icculus@2011
   157
    } elsif ($size == 32) {
icculus@2011
   158
        return 0x7FFFFFFF;
icculus@1982
   159
    }
icculus@1982
   160
icculus@1982
   161
    die("bug in script.\n");
icculus@1982
   162
}
icculus@1982
   163
icculus@1982
   164
sub getFloatToIntMult {
icculus@2011
   165
    my $size = shift;
icculus@2011
   166
    my $val = maxIntVal($size) . '.0';
icculus@1982
   167
    $val .= 'f' if ($size < 32);
icculus@1982
   168
    return $val;
icculus@1982
   169
}
icculus@1982
   170
icculus@1982
   171
sub getIntToFloatDivBy {
icculus@2011
   172
    my $size = shift;
icculus@2011
   173
    return 'DIVBY' . maxIntVal($size);
icculus@1982
   174
}
icculus@1982
   175
icculus@1982
   176
sub getSignFlipVal {
icculus@1982
   177
    my $size = shift;
icculus@1982
   178
    if ($size == 8) {
icculus@1982
   179
        return '0x80';
icculus@1982
   180
    } elsif ($size == 16) {
icculus@1982
   181
        return '0x8000';
icculus@1982
   182
    } elsif ($size == 32) {
icculus@1982
   183
        return '0x80000000';
icculus@1982
   184
    }
icculus@1982
   185
icculus@1982
   186
    die("bug in script.\n");
icculus@1982
   187
}
icculus@1982
   188
icculus@1982
   189
sub buildCvtFunc {
icculus@1982
   190
    my ($from, $to) = @_;
icculus@1982
   191
    my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
icculus@1982
   192
    my ($tsigned, $tfloat, $tsize, $tendian, $tctype) = splittype($to);
icculus@1982
   193
    my $diffs = 0;
icculus@1982
   194
    $diffs++ if ($fsize != $tsize);
icculus@1982
   195
    $diffs++ if ($fsigned != $tsigned);
icculus@1982
   196
    $diffs++ if ($ffloat != $tfloat);
icculus@1982
   197
    $diffs++ if ($fendian ne $tendian);
icculus@1982
   198
icculus@1982
   199
    return if ($diffs == 0);
icculus@1982
   200
icculus@3008
   201
    my $hashid = getTypeConvertHashId($from, $to);
icculus@1982
   202
    if (1) { # !!! FIXME: if ($diffs > 1) {
icculus@1982
   203
        my $sym = "SDL_Convert_${from}_to_${to}";
icculus@1982
   204
        $funcs{$hashid} = $sym;
icculus@1982
   205
        $custom_converters++;
icculus@1982
   206
icculus@1982
   207
        # Always unsigned for ints, for possible byteswaps.
icculus@1982
   208
        my $srctype = (($ffloat) ? 'float' : "Uint${fsize}");
icculus@1982
   209
icculus@1982
   210
        print <<EOF;
icculus@1982
   211
static void SDLCALL
icculus@1982
   212
${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
icculus@1982
   213
{
icculus@1982
   214
    int i;
icculus@1982
   215
    const $srctype *src;
icculus@1982
   216
    $tctype *dst;
icculus@1982
   217
slouken@3032
   218
#if DEBUG_CONVERT
icculus@1982
   219
    fprintf(stderr, "Converting AUDIO_${from} to AUDIO_${to}.\\n");
icculus@1982
   220
#endif
icculus@1982
   221
icculus@1982
   222
EOF
icculus@1982
   223
icculus@1982
   224
        if ($fsize < $tsize) {
icculus@1982
   225
            my $mult = $tsize / $fsize;
icculus@1982
   226
            print <<EOF;
icculus@2956
   227
    src = ((const $srctype *) (cvt->buf + cvt->len_cvt)) - 1;
icculus@2956
   228
    dst = (($tctype *) (cvt->buf + cvt->len_cvt * $mult)) - 1;
icculus@1982
   229
    for (i = cvt->len_cvt / sizeof ($srctype); i; --i, --src, --dst) {
icculus@1982
   230
EOF
icculus@1982
   231
        } else {
icculus@1982
   232
            print <<EOF;
icculus@1982
   233
    src = (const $srctype *) cvt->buf;
icculus@1982
   234
    dst = ($tctype *) cvt->buf;
icculus@1982
   235
    for (i = cvt->len_cvt / sizeof ($srctype); i; --i, ++src, ++dst) {
icculus@1982
   236
EOF
icculus@1982
   237
        }
icculus@1982
   238
icculus@1982
   239
        # Have to convert to/from float/int.
icculus@1982
   240
        # !!! FIXME: cast through double for int32<->float?
icculus@1982
   241
        my $code = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, '*src');
icculus@1982
   242
        if ($ffloat != $tfloat) {
icculus@1982
   243
            if ($ffloat) {
icculus@2011
   244
                my $mult = getFloatToIntMult($tsize);
icculus@2011
   245
                if (!$tsigned) {   # bump from -1.0f/1.0f to 0.0f/2.0f
icculus@2011
   246
                    $code = "($code + 1.0f)";
icculus@2011
   247
                }
icculus@1982
   248
                $code = "(($tctype) ($code * $mult))";
icculus@1982
   249
            } else {
icculus@1982
   250
                # $divby will be the reciprocal, to avoid pipeline stalls
icculus@1982
   251
                #  from floating point division...so multiply it.
icculus@2011
   252
                my $divby = getIntToFloatDivBy($fsize);
icculus@1982
   253
                $code = "(((float) $code) * $divby)";
icculus@2011
   254
                if (!$fsigned) {   # bump from 0.0f/2.0f to -1.0f/1.0f.
icculus@2011
   255
                    $code = "($code - 1.0f)";
icculus@2011
   256
                }
icculus@1982
   257
            }
icculus@1982
   258
        } else {
icculus@1982
   259
            # All integer conversions here.
icculus@1982
   260
            if ($fsigned != $tsigned) {
icculus@1982
   261
                my $signflipval = getSignFlipVal($fsize);
icculus@1982
   262
                $code = "(($code) ^ $signflipval)";
icculus@1982
   263
            }
icculus@1982
   264
icculus@1982
   265
            my $shiftval = abs($fsize - $tsize);
icculus@1982
   266
            if ($fsize < $tsize) {
icculus@1982
   267
                $code = "((($tctype) $code) << $shiftval)";
icculus@1982
   268
            } elsif ($fsize > $tsize) {
icculus@1982
   269
                $code = "(($tctype) ($code >> $shiftval))";
icculus@1982
   270
            }
icculus@1982
   271
        }
icculus@1982
   272
icculus@1982
   273
        my $swap = getSwapFunc($tsize, $tsigned, $tfloat, $tendian, 'val');
icculus@1982
   274
icculus@1982
   275
        print <<EOF;
icculus@1982
   276
        const $tctype val = $code;
icculus@1982
   277
        *dst = ${swap};
icculus@1982
   278
    }
icculus@1982
   279
icculus@1982
   280
EOF
icculus@1982
   281
icculus@1982
   282
        if ($fsize > $tsize) {
icculus@1982
   283
            my $divby = $fsize / $tsize;
icculus@1982
   284
            print("    cvt->len_cvt /= $divby;\n");
icculus@1982
   285
        } elsif ($fsize < $tsize) {
icculus@1982
   286
            my $mult = $tsize / $fsize;
icculus@1982
   287
            print("    cvt->len_cvt *= $mult;\n");
icculus@1982
   288
        }
icculus@1982
   289
icculus@1982
   290
        print <<EOF;
icculus@1982
   291
    if (cvt->filters[++cvt->filter_index]) {
icculus@2955
   292
        cvt->filters[cvt->filter_index] (cvt, AUDIO_$to);
icculus@1982
   293
    }
icculus@1982
   294
}
icculus@1982
   295
icculus@1982
   296
EOF
icculus@1982
   297
icculus@1982
   298
    } else {
icculus@1982
   299
        if ($fsigned != $tsigned) {
icculus@1982
   300
            $funcs{$hashid} = 'SDL_ConvertSigned';
icculus@1982
   301
        } elsif ($ffloat != $tfloat) {
icculus@1982
   302
            $funcs{$hashid} = 'SDL_ConvertFloat';
icculus@1982
   303
        } elsif ($fsize != $tsize) {
icculus@1982
   304
            $funcs{$hashid} = 'SDL_ConvertSize';
icculus@1982
   305
        } elsif ($fendian ne $tendian) {
icculus@1982
   306
            $funcs{$hashid} = 'SDL_ConvertEndian';
icculus@1982
   307
        } else {
icculus@1982
   308
            die("error in script.\n");
icculus@1982
   309
        }
icculus@1982
   310
    }
icculus@1982
   311
}
icculus@1982
   312
icculus@1982
   313
icculus@3008
   314
sub buildTypeConverters {
icculus@3019
   315
    print "#if !NO_CONVERTERS\n\n";
icculus@1982
   316
    foreach (@audiotypes) {
icculus@3008
   317
        my $from = $_;
icculus@3008
   318
        foreach (@audiotypes) {
icculus@3008
   319
            my $to = $_;
icculus@3008
   320
            buildCvtFunc($from, $to);
icculus@3008
   321
        }
icculus@3008
   322
    }
icculus@3019
   323
    print "#endif  /* !NO_CONVERTERS */\n\n\n";
icculus@3008
   324
icculus@3008
   325
    print "const SDL_AudioTypeFilters sdl_audio_type_filters[] =\n{\n";
icculus@3019
   326
    print "#if !NO_CONVERTERS\n";
icculus@3008
   327
    foreach (@audiotypes) {
icculus@3008
   328
        my $from = $_;
icculus@3008
   329
        foreach (@audiotypes) {
icculus@3008
   330
            my $to = $_;
icculus@3008
   331
            if ($from ne $to) {
icculus@3008
   332
                my $hashid = getTypeConvertHashId($from, $to);
icculus@3008
   333
                my $sym = $funcs{$hashid};
icculus@3008
   334
                print("    { AUDIO_$from, AUDIO_$to, $sym },\n");
icculus@3008
   335
            }
icculus@3008
   336
        }
icculus@3008
   337
    }
icculus@3019
   338
    print "#endif  /* !NO_CONVERTERS */\n";
icculus@3008
   339
icculus@3020
   340
    print("    { 0, 0, NULL }\n");
icculus@3008
   341
    print "};\n\n\n";
icculus@3008
   342
}
icculus@3008
   343
icculus@3008
   344
sub getBiggerCtype {
icculus@3008
   345
    my ($isfloat, $size) = @_;
icculus@3008
   346
icculus@3008
   347
    if ($isfloat) {
icculus@3008
   348
        if ($size == 32) {
icculus@3008
   349
            return 'double';
icculus@3008
   350
        }
icculus@3008
   351
        die("bug in script.\n");
icculus@3008
   352
    }
icculus@3008
   353
icculus@3008
   354
    if ($size == 8) {
icculus@3008
   355
        return 'Sint16';
icculus@3008
   356
    } elsif ($size == 16) {
icculus@3008
   357
        return 'Sint32'
icculus@3008
   358
    } elsif ($size == 32) {
icculus@3008
   359
        return 'Sint64'
icculus@3008
   360
    }
icculus@3008
   361
icculus@3008
   362
    die("bug in script.\n");
icculus@3008
   363
}
icculus@3008
   364
icculus@3008
   365
icculus@3008
   366
# These handle arbitrary resamples...44100Hz to 48000Hz, for example.
icculus@3008
   367
# Man, this code is skanky.
icculus@3008
   368
sub buildArbitraryResampleFunc {
icculus@3008
   369
    # !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
icculus@3008
   370
    my ($from, $channels, $upsample) = @_;
icculus@3008
   371
    my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
icculus@3008
   372
icculus@3008
   373
    my $bigger = getBiggerCtype($ffloat, $fsize);
icculus@3008
   374
    my $interp = ($ffloat) ? '* 0.5' : '>> 1';
icculus@3008
   375
icculus@3008
   376
    my $resample = ($upsample) ? 'Upsample' : 'Downsample';
icculus@3008
   377
    my $hashid = getResamplerHashId($from, $channels, $upsample, 0);
icculus@3008
   378
    my $sym = "SDL_${resample}_${from}_${channels}c";
icculus@3008
   379
    $funcs{$hashid} = $sym;
icculus@3008
   380
    $custom_converters++;
icculus@3008
   381
icculus@3008
   382
    my $fudge = $fsize * $channels * 2;  # !!! FIXME
icculus@3008
   383
    my $eps_adjust = ($upsample) ? 'dstsize' : 'srcsize';
icculus@3008
   384
    my $incr = '';
icculus@3008
   385
    my $incr2 = '';
icculus@8856
   386
    my $block_align = $channels * $fsize/8;
icculus@3008
   387
icculus@3008
   388
icculus@3008
   389
    # !!! FIXME: DEBUG_CONVERT should report frequencies.
icculus@3008
   390
    print <<EOF;
icculus@3008
   391
static void SDLCALL
icculus@3008
   392
${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
icculus@3008
   393
{
slouken@3032
   394
#if DEBUG_CONVERT
icculus@3008
   395
    fprintf(stderr, "$resample arbitrary (x%f) AUDIO_${from}, ${channels} channels.\\n", cvt->rate_incr);
icculus@3008
   396
#endif
icculus@3008
   397
icculus@3008
   398
    const int srcsize = cvt->len_cvt - $fudge;
icculus@8856
   399
    const int dstsize = (int) (((double)(cvt->len_cvt/${block_align})) * cvt->rate_incr) * ${block_align};
icculus@3008
   400
    register int eps = 0;
icculus@3008
   401
EOF
icculus@3008
   402
slouken@4889
   403
    my $endcomparison = '!=';
slouken@4889
   404
icculus@3008
   405
    # Upsampling (growing the buffer) needs to work backwards, since we
icculus@3008
   406
    #  overwrite the buffer as we go.
icculus@3008
   407
    if ($upsample) {
slouken@6194
   408
        $endcomparison = '>=';  # dst > target
icculus@3008
   409
        print <<EOF;
icculus@3008
   410
    $fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels;
icculus@3008
   411
    const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
slouken@6194
   412
    const $fctype *target = ((const $fctype *) cvt->buf);
icculus@3008
   413
EOF
icculus@3008
   414
    } else {
slouken@4889
   415
        $endcomparison = '<';  # dst < target
icculus@3008
   416
        print <<EOF;
icculus@3008
   417
    $fctype *dst = ($fctype *) cvt->buf;
icculus@3008
   418
    const $fctype *src = ($fctype *) cvt->buf;
icculus@3008
   419
    const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
icculus@3008
   420
EOF
icculus@3008
   421
    }
icculus@3008
   422
icculus@3008
   423
    for (my $i = 0; $i < $channels; $i++) {
icculus@3008
   424
        my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
icculus@3008
   425
        my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
icculus@3008
   426
        print <<EOF;
icculus@3008
   427
    $fctype sample${idx} = $val;
icculus@3008
   428
EOF
icculus@3008
   429
    }
icculus@3008
   430
icculus@3008
   431
    for (my $i = 0; $i < $channels; $i++) {
icculus@3008
   432
        my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
icculus@3008
   433
        print <<EOF;
icculus@3008
   434
    $fctype last_sample${idx} = sample${idx};
icculus@3008
   435
EOF
icculus@3008
   436
    }
icculus@3008
   437
icculus@3008
   438
    print <<EOF;
slouken@4889
   439
    while (dst $endcomparison target) {
icculus@3008
   440
EOF
icculus@3008
   441
icculus@3008
   442
    if ($upsample) {
icculus@3008
   443
        for (my $i = 0; $i < $channels; $i++) {
icculus@3008
   444
            # !!! FIXME: don't do this swap every write, just when the samples change.
icculus@3008
   445
            my $idx = (($channels - $i) - 1);
icculus@3008
   446
            my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${idx}");
icculus@3008
   447
            print <<EOF;
icculus@3008
   448
        dst[$idx] = $val;
icculus@3008
   449
EOF
icculus@3008
   450
        }
icculus@3008
   451
icculus@3008
   452
        $incr = ($channels == 1) ? 'dst--' : "dst -= $channels";
icculus@3008
   453
        $incr2 = ($channels == 1) ? 'src--' : "src -= $channels";
icculus@3008
   454
icculus@3008
   455
        print <<EOF;
icculus@3008
   456
        $incr;
icculus@3008
   457
        eps += srcsize;
icculus@3008
   458
        if ((eps << 1) >= dstsize) {
icculus@3008
   459
            $incr2;
icculus@3008
   460
EOF
icculus@3008
   461
    } else {  # downsample.
icculus@3008
   462
        $incr = ($channels == 1) ? 'src++' : "src += $channels";
icculus@3008
   463
        print <<EOF;
icculus@3008
   464
        $incr;
icculus@3008
   465
        eps += dstsize;
icculus@3008
   466
        if ((eps << 1) >= srcsize) {
icculus@3008
   467
EOF
icculus@3008
   468
        for (my $i = 0; $i < $channels; $i++) {
icculus@3008
   469
            my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${i}");
icculus@3008
   470
            print <<EOF;
icculus@3008
   471
            dst[$i] = $val;
icculus@3008
   472
EOF
icculus@3008
   473
        }
icculus@3008
   474
icculus@3008
   475
        $incr = ($channels == 1) ? 'dst++' : "dst += $channels";
icculus@3008
   476
        print <<EOF;
icculus@3008
   477
            $incr;
icculus@3008
   478
EOF
icculus@3008
   479
    }
icculus@3008
   480
icculus@3008
   481
    for (my $i = 0; $i < $channels; $i++) {
icculus@3008
   482
        my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
icculus@3008
   483
        my $swapped = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
icculus@3008
   484
        print <<EOF;
icculus@3008
   485
            sample${idx} = ($fctype) (((($bigger) $swapped) + (($bigger) last_sample${idx})) $interp);
icculus@3008
   486
EOF
icculus@3008
   487
    }
icculus@3008
   488
icculus@3008
   489
    for (my $i = 0; $i < $channels; $i++) {
icculus@3008
   490
        my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
icculus@3008
   491
        print <<EOF;
icculus@3008
   492
            last_sample${idx} = sample${idx};
icculus@3008
   493
EOF
icculus@3008
   494
    }
icculus@3008
   495
icculus@3008
   496
    print <<EOF;
icculus@3008
   497
            eps -= $eps_adjust;
icculus@3008
   498
        }
icculus@3008
   499
    }
icculus@3008
   500
EOF
icculus@3008
   501
icculus@3008
   502
        print <<EOF;
icculus@3008
   503
    cvt->len_cvt = dstsize;
icculus@3008
   504
    if (cvt->filters[++cvt->filter_index]) {
icculus@3008
   505
        cvt->filters[cvt->filter_index] (cvt, format);
icculus@1982
   506
    }
icculus@1982
   507
}
icculus@1982
   508
icculus@1982
   509
EOF
icculus@1982
   510
icculus@3008
   511
}
icculus@3008
   512
icculus@3008
   513
# These handle clean resamples...doubling and quadrupling the sample rate, etc.
icculus@3008
   514
sub buildMultipleResampleFunc {
icculus@3008
   515
    # !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
icculus@3008
   516
    my ($from, $channels, $upsample, $multiple) = @_;
icculus@3008
   517
    my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
icculus@3008
   518
icculus@3008
   519
    my $bigger = getBiggerCtype($ffloat, $fsize);
icculus@3008
   520
    my $interp = ($ffloat) ? '* 0.5' : '>> 1';
icculus@3008
   521
    my $interp2 = ($ffloat) ? '* 0.25' : '>> 2';
icculus@3008
   522
    my $mult3 = ($ffloat) ? '3.0' : '3';
icculus@3008
   523
    my $lencvtop = ($upsample) ? '*' : '/';
icculus@3008
   524
icculus@3008
   525
    my $resample = ($upsample) ? 'Upsample' : 'Downsample';
icculus@3008
   526
    my $hashid = getResamplerHashId($from, $channels, $upsample, $multiple);
icculus@3008
   527
    my $sym = "SDL_${resample}_${from}_${channels}c_x${multiple}";
icculus@3008
   528
    $funcs{$hashid} = $sym;
icculus@3008
   529
    $custom_converters++;
icculus@3008
   530
icculus@3008
   531
    # !!! FIXME: DEBUG_CONVERT should report frequencies.
icculus@3008
   532
    print <<EOF;
icculus@3008
   533
static void SDLCALL
icculus@3008
   534
${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
icculus@3008
   535
{
slouken@3032
   536
#if DEBUG_CONVERT
icculus@3008
   537
    fprintf(stderr, "$resample (x${multiple}) AUDIO_${from}, ${channels} channels.\\n");
icculus@3008
   538
#endif
icculus@3008
   539
icculus@3008
   540
    const int dstsize = cvt->len_cvt $lencvtop $multiple;
icculus@3008
   541
EOF
icculus@3008
   542
icculus@3602
   543
    my $endcomparison = '!=';
icculus@3602
   544
icculus@3008
   545
    # Upsampling (growing the buffer) needs to work backwards, since we
icculus@3008
   546
    #  overwrite the buffer as we go.
icculus@3008
   547
    if ($upsample) {
slouken@6194
   548
        $endcomparison = '>=';  # dst > target
icculus@3008
   549
        print <<EOF;
slouken@6196
   550
    $fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels * $multiple;
icculus@3008
   551
    const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
slouken@6194
   552
    const $fctype *target = ((const $fctype *) cvt->buf);
icculus@3008
   553
EOF
icculus@3008
   554
    } else {
icculus@3602
   555
        $endcomparison = '<';  # dst < target
icculus@3008
   556
        print <<EOF;
icculus@3008
   557
    $fctype *dst = ($fctype *) cvt->buf;
icculus@3008
   558
    const $fctype *src = ($fctype *) cvt->buf;
icculus@3008
   559
    const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
icculus@3008
   560
EOF
icculus@3008
   561
    }
icculus@3008
   562
icculus@3008
   563
    for (my $i = 0; $i < $channels; $i++) {
icculus@3008
   564
        my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
icculus@3008
   565
        my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
icculus@3008
   566
        print <<EOF;
icculus@3008
   567
    $bigger last_sample${idx} = ($bigger) $val;
icculus@3008
   568
EOF
icculus@3008
   569
    }
icculus@3008
   570
icculus@3008
   571
    print <<EOF;
icculus@3602
   572
    while (dst $endcomparison target) {
icculus@3008
   573
EOF
icculus@3008
   574
icculus@3008
   575
    for (my $i = 0; $i < $channels; $i++) {
icculus@3008
   576
        my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
icculus@3008
   577
        my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
icculus@3008
   578
        print <<EOF;
icculus@3008
   579
        const $bigger sample${idx} = ($bigger) $val;
icculus@3008
   580
EOF
icculus@3008
   581
    }
icculus@3008
   582
icculus@3008
   583
    my $incr = '';
icculus@3008
   584
    if ($upsample) {
icculus@3008
   585
        $incr = ($channels == 1) ? 'src--' : "src -= $channels";
icculus@3008
   586
    } else {
icculus@3008
   587
        my $amount = $channels * $multiple;
icculus@3008
   588
        $incr = "src += $amount";  # can't ever be 1, so no "++" version.
icculus@3008
   589
    }
icculus@3008
   590
icculus@3008
   591
icculus@3008
   592
    print <<EOF;
icculus@3008
   593
        $incr;
icculus@3008
   594
EOF
icculus@3008
   595
icculus@3008
   596
    # !!! FIXME: This really begs for some Altivec or SSE, etc.
icculus@3008
   597
    if ($upsample) {
icculus@3008
   598
        if ($multiple == 2) {
icculus@3008
   599
            for (my $i = $channels-1; $i >= 0; $i--) {
icculus@3008
   600
                my $dsti = $i + $channels;
icculus@3008
   601
                print <<EOF;
icculus@3008
   602
        dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
icculus@3008
   603
EOF
icculus@3008
   604
            }
icculus@3008
   605
            for (my $i = $channels-1; $i >= 0; $i--) {
icculus@3008
   606
                my $dsti = $i;
icculus@3008
   607
                print <<EOF;
icculus@3008
   608
        dst[$dsti] = ($fctype) sample${i};
icculus@3008
   609
EOF
icculus@3008
   610
            }
icculus@3008
   611
        } elsif ($multiple == 4) {
icculus@3008
   612
            for (my $i = $channels-1; $i >= 0; $i--) {
icculus@3008
   613
                my $dsti = $i + ($channels * 3);
icculus@3008
   614
                print <<EOF;
slouken@6211
   615
        dst[$dsti] = ($fctype) ((sample${i} + ($mult3 * last_sample${i})) $interp2);
icculus@3008
   616
EOF
icculus@3008
   617
            }
icculus@3008
   618
icculus@3008
   619
            for (my $i = $channels-1; $i >= 0; $i--) {
icculus@3008
   620
                my $dsti = $i + ($channels * 2);
icculus@3008
   621
                print <<EOF;
slouken@6211
   622
        dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
icculus@3008
   623
EOF
icculus@3008
   624
            }
icculus@3008
   625
icculus@3008
   626
            for (my $i = $channels-1; $i >= 0; $i--) {
icculus@3008
   627
                my $dsti = $i + ($channels * 1);
icculus@3008
   628
                print <<EOF;
slouken@6211
   629
        dst[$dsti] = ($fctype) ((($mult3 * sample${i}) + last_sample${i}) $interp2);
icculus@3008
   630
EOF
icculus@3008
   631
            }
icculus@3008
   632
icculus@3008
   633
            for (my $i = $channels-1; $i >= 0; $i--) {
icculus@3008
   634
                my $dsti = $i + ($channels * 0);
icculus@3008
   635
                print <<EOF;
slouken@6211
   636
        dst[$dsti] = ($fctype) sample${i};
icculus@3008
   637
EOF
icculus@3008
   638
            }
icculus@3008
   639
        } else {
icculus@3008
   640
            die('bug in program.');  # we only handle x2 and x4.
icculus@1982
   641
        }
icculus@3008
   642
    } else {  # downsample.
icculus@3008
   643
        if ($multiple == 2) {
icculus@3008
   644
            for (my $i = 0; $i < $channels; $i++) {
icculus@3008
   645
                print <<EOF;
icculus@3008
   646
        dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
icculus@3008
   647
EOF
icculus@3008
   648
            }
icculus@3008
   649
        } elsif ($multiple == 4) {
icculus@3008
   650
            # !!! FIXME: interpolate all 4 samples?
icculus@3008
   651
            for (my $i = 0; $i < $channels; $i++) {
icculus@3008
   652
                print <<EOF;
icculus@3008
   653
        dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
icculus@3008
   654
EOF
icculus@3008
   655
            }
icculus@3008
   656
        } else {
icculus@3008
   657
            die('bug in program.');  # we only handle x2 and x4.
icculus@3008
   658
        }
icculus@3008
   659
    }
icculus@3008
   660
icculus@3008
   661
    for (my $i = 0; $i < $channels; $i++) {
icculus@3008
   662
        my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
icculus@3008
   663
        print <<EOF;
icculus@3008
   664
        last_sample${idx} = sample${idx};
icculus@3008
   665
EOF
icculus@3008
   666
    }
icculus@3008
   667
icculus@3008
   668
    if ($upsample) {
icculus@3008
   669
        my $amount = $channels * $multiple;
icculus@3008
   670
        $incr = "dst -= $amount";  # can't ever be 1, so no "--" version.
icculus@3008
   671
    } else {
icculus@3008
   672
        $incr = ($channels == 1) ? 'dst++' : "dst += $channels";
icculus@3008
   673
    }
icculus@3008
   674
icculus@3008
   675
    print <<EOF;
icculus@3008
   676
        $incr;
icculus@3008
   677
    }
icculus@3008
   678
icculus@3008
   679
    cvt->len_cvt = dstsize;
icculus@3008
   680
    if (cvt->filters[++cvt->filter_index]) {
icculus@3008
   681
        cvt->filters[cvt->filter_index] (cvt, format);
icculus@1982
   682
    }
icculus@1982
   683
}
icculus@1982
   684
icculus@1982
   685
EOF
icculus@1982
   686
icculus@3008
   687
}
icculus@3008
   688
icculus@3008
   689
sub buildResamplers {
icculus@3019
   690
    print "#if !NO_RESAMPLERS\n\n";
icculus@3019
   691
    foreach (@audiotypes) {
icculus@3019
   692
        my $from = $_;
icculus@3019
   693
        foreach (@channels) {
icculus@3019
   694
            my $channel = $_;
icculus@3019
   695
            buildArbitraryResampleFunc($from, $channel, 1);
icculus@3019
   696
            buildArbitraryResampleFunc($from, $channel, 0);
icculus@3019
   697
        }
icculus@3019
   698
    }
icculus@3019
   699
icculus@3019
   700
    print "\n#if !LESS_RESAMPLERS\n\n";
icculus@3008
   701
    foreach (@audiotypes) {
icculus@3008
   702
        my $from = $_;
icculus@3008
   703
        foreach (@channels) {
icculus@3008
   704
            my $channel = $_;
icculus@3008
   705
            for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
icculus@3008
   706
                buildMultipleResampleFunc($from, $channel, 1, $multiple);
icculus@3008
   707
                buildMultipleResampleFunc($from, $channel, 0, $multiple);
icculus@3008
   708
            }
icculus@3008
   709
        }
icculus@3008
   710
    }
icculus@3008
   711
icculus@3019
   712
    print "#endif  /* !LESS_RESAMPLERS */\n";
icculus@3019
   713
    print "#endif  /* !NO_RESAMPLERS */\n\n\n";
icculus@3019
   714
icculus@3008
   715
    print "const SDL_AudioRateFilters sdl_audio_rate_filters[] =\n{\n";
icculus@3019
   716
    print "#if !NO_RESAMPLERS\n";
icculus@3008
   717
    foreach (@audiotypes) {
icculus@3008
   718
        my $from = $_;
icculus@3008
   719
        foreach (@channels) {
icculus@3008
   720
            my $channel = $_;
icculus@3019
   721
            for (my $upsample = 0; $upsample <= 1; $upsample++) {
icculus@3019
   722
                my $hashid = getResamplerHashId($from, $channel, $upsample, 0);
icculus@3019
   723
                my $sym = $funcs{$hashid};
icculus@3019
   724
                print("    { AUDIO_$from, $channel, $upsample, 0, $sym },\n");
icculus@3019
   725
            }
icculus@3019
   726
        }
icculus@3019
   727
    }
icculus@3019
   728
icculus@3019
   729
    print "#if !LESS_RESAMPLERS\n";
icculus@3019
   730
    foreach (@audiotypes) {
icculus@3019
   731
        my $from = $_;
icculus@3019
   732
        foreach (@channels) {
icculus@3019
   733
            my $channel = $_;
icculus@3019
   734
            for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
icculus@3008
   735
                for (my $upsample = 0; $upsample <= 1; $upsample++) {
icculus@3008
   736
                    my $hashid = getResamplerHashId($from, $channel, $upsample, $multiple);
icculus@3008
   737
                    my $sym = $funcs{$hashid};
icculus@3008
   738
                    print("    { AUDIO_$from, $channel, $upsample, $multiple, $sym },\n");
icculus@3008
   739
                }
icculus@3008
   740
            }
icculus@3008
   741
        }
icculus@3008
   742
    }
icculus@3008
   743
icculus@3019
   744
    print "#endif  /* !LESS_RESAMPLERS */\n";
icculus@3019
   745
    print "#endif  /* !NO_RESAMPLERS */\n";
icculus@3020
   746
    print("    { 0, 0, 0, 0, NULL }\n");
icculus@3008
   747
    print "};\n\n";
icculus@3008
   748
}
icculus@3008
   749
icculus@3008
   750
icculus@3008
   751
# mainline ...
icculus@3008
   752
icculus@3008
   753
outputHeader();
icculus@3008
   754
buildTypeConverters();
icculus@3008
   755
buildResamplers();
slouken@1985
   756
outputFooter();
slouken@1985
   757
icculus@1982
   758
exit 0;
icculus@1982
   759
slouken@1985
   760
# end of sdlgenaudiocvt.pl ...
icculus@1982
   761