Reworked audio converter code.
This no longer uses a script to generate code for every possible type conversion or resampler. This caused a bloat in binary size and and compile times. Now we use a handful of more generic functions and assume staying in the CPU cache is the most important thing anyhow. This shrinks the size of the final build (in this case: macOS X amd64, -Os to optimize for size) by 15%. When compiling on a single core, build times drop by about 15% too (although the previous cost was largely hidden by multicore builds).
parent
7e65d88f01
commit
f3456e9a93
|
@ -20,6 +20,16 @@
|
|||
*/
|
||||
#include "../SDL_internal.h"
|
||||
|
||||
#ifndef DEBUG_CONVERT
|
||||
#define DEBUG_CONVERT 0
|
||||
#endif
|
||||
|
||||
#if DEBUG_CONVERT
|
||||
#define LOG_DEBUG_CONVERT(from, to) fprintf(stderr, "Converting %s to %s.\n", from, to);
|
||||
#else
|
||||
#define LOG_DEBUG_CONVERT(from, to)
|
||||
#endif
|
||||
|
||||
/* Functions and variables exported from SDL_audio.c for SDL_sysaudio.c */
|
||||
|
||||
/* Functions to get a list of "close" audio formats */
|
||||
|
@ -29,24 +39,20 @@ extern SDL_AudioFormat SDL_NextAudioFormat(void);
|
|||
/* Function to calculate the size and silence for a SDL_AudioSpec */
|
||||
extern void SDL_CalculateAudioSpec(SDL_AudioSpec * spec);
|
||||
|
||||
/* this is used internally to access some autogenerated code. */
|
||||
typedef struct
|
||||
{
|
||||
SDL_AudioFormat src_fmt;
|
||||
SDL_AudioFormat dst_fmt;
|
||||
SDL_AudioFilter filter;
|
||||
} SDL_AudioTypeFilters;
|
||||
extern const SDL_AudioTypeFilters sdl_audio_type_filters[];
|
||||
|
||||
/* this is used internally to access some autogenerated code. */
|
||||
typedef struct
|
||||
{
|
||||
SDL_AudioFormat fmt;
|
||||
int channels;
|
||||
int upsample;
|
||||
int multiple;
|
||||
SDL_AudioFilter filter;
|
||||
} SDL_AudioRateFilters;
|
||||
extern const SDL_AudioRateFilters sdl_audio_rate_filters[];
|
||||
void SDLCALL SDL_Convert_S8_to_F32(SDL_AudioCVT *cvt, SDL_AudioFormat format);
|
||||
void SDLCALL SDL_Convert_U8_to_F32(SDL_AudioCVT *cvt, SDL_AudioFormat format);
|
||||
void SDLCALL SDL_Convert_S16_to_F32(SDL_AudioCVT *cvt, SDL_AudioFormat format);
|
||||
void SDLCALL SDL_Convert_U16_to_F32(SDL_AudioCVT *cvt, SDL_AudioFormat format);
|
||||
void SDLCALL SDL_Convert_S32_to_F32(SDL_AudioCVT *cvt, SDL_AudioFormat format);
|
||||
void SDLCALL SDL_Convert_F32_to_S8(SDL_AudioCVT *cvt, SDL_AudioFormat format);
|
||||
void SDLCALL SDL_Convert_F32_to_U8(SDL_AudioCVT *cvt, SDL_AudioFormat format);
|
||||
void SDLCALL SDL_Convert_F32_to_S16(SDL_AudioCVT *cvt, SDL_AudioFormat format);
|
||||
void SDLCALL SDL_Convert_F32_to_U16(SDL_AudioCVT *cvt, SDL_AudioFormat format);
|
||||
void SDLCALL SDL_Convert_F32_to_S32(SDL_AudioCVT *cvt, SDL_AudioFormat format);
|
||||
void SDL_Upsample_Arbitrary(SDL_AudioCVT *cvt, const int channels);
|
||||
void SDL_Downsample_Arbitrary(SDL_AudioCVT *cvt, const int channels);
|
||||
void SDL_Upsample_x2(SDL_AudioCVT *cvt, const int channels);
|
||||
void SDL_Upsample_x4(SDL_AudioCVT *cvt, const int channels);
|
||||
void SDL_Downsample_Multiple(SDL_AudioCVT *cvt, const int multiple, const int channels);
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,761 +0,0 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
my @audiotypes = qw(
|
||||
U8
|
||||
S8
|
||||
U16LSB
|
||||
S16LSB
|
||||
U16MSB
|
||||
S16MSB
|
||||
S32LSB
|
||||
S32MSB
|
||||
F32LSB
|
||||
F32MSB
|
||||
);
|
||||
|
||||
my @channels = ( 1, 2, 4, 6, 8 );
|
||||
my %funcs;
|
||||
my $custom_converters = 0;
|
||||
|
||||
|
||||
sub getTypeConvertHashId {
|
||||
my ($from, $to) = @_;
|
||||
return "TYPECONVERTER $from/$to";
|
||||
}
|
||||
|
||||
|
||||
sub getResamplerHashId {
|
||||
my ($from, $channels, $upsample, $multiple) = @_;
|
||||
return "RESAMPLER $from/$channels/$upsample/$multiple";
|
||||
}
|
||||
|
||||
|
||||
sub outputHeader {
|
||||
print <<EOF;
|
||||
/* DO NOT EDIT! This file is generated by sdlgenaudiocvt.pl */
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken\@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../SDL_internal.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_audio_c.h"
|
||||
|
||||
#ifndef DEBUG_CONVERT
|
||||
#define DEBUG_CONVERT 0
|
||||
#endif
|
||||
|
||||
|
||||
/* If you can guarantee your data and need space, you can eliminate code... */
|
||||
|
||||
/* Just build the arbitrary resamplers if you're saving code space. */
|
||||
#ifndef LESS_RESAMPLERS
|
||||
#define LESS_RESAMPLERS 0
|
||||
#endif
|
||||
|
||||
/* Don't build any resamplers if you're REALLY saving code space. */
|
||||
#ifndef NO_RESAMPLERS
|
||||
#define NO_RESAMPLERS 0
|
||||
#endif
|
||||
|
||||
/* Don't build any type converters if you're saving code space. */
|
||||
#ifndef NO_CONVERTERS
|
||||
#define NO_CONVERTERS 0
|
||||
#endif
|
||||
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
EOF
|
||||
|
||||
my @vals = ( 127, 32767, 2147483647 );
|
||||
foreach (@vals) {
|
||||
my $val = $_;
|
||||
my $fval = 1.0 / $val;
|
||||
print("#define DIVBY${val} ${fval}f\n");
|
||||
}
|
||||
|
||||
print("\n");
|
||||
}
|
||||
|
||||
sub outputFooter {
|
||||
print <<EOF;
|
||||
/* $custom_converters converters generated. */
|
||||
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
EOF
|
||||
}
|
||||
|
||||
sub splittype {
|
||||
my $t = shift;
|
||||
my ($signed, $size, $endian) = $t =~ /([USF])(\d+)([LM]SB|)/;
|
||||
my $float = ($signed eq 'F') ? 1 : 0;
|
||||
$signed = (($float) or ($signed eq 'S')) ? 1 : 0;
|
||||
$endian = 'NONE' if ($endian eq '');
|
||||
|
||||
my $ctype = '';
|
||||
if ($float) {
|
||||
$ctype = (($size == 32) ? 'float' : 'double');
|
||||
} else {
|
||||
$ctype = (($signed) ? 'S' : 'U') . "int${size}";
|
||||
}
|
||||
|
||||
return ($signed, $float, $size, $endian, $ctype);
|
||||
}
|
||||
|
||||
sub getSwapFunc {
|
||||
my ($size, $signed, $float, $endian, $val) = @_;
|
||||
my $BEorLE = (($endian eq 'MSB') ? 'BE' : 'LE');
|
||||
my $code = '';
|
||||
|
||||
if ($float) {
|
||||
$code = "SDL_SwapFloat${BEorLE}($val)";
|
||||
} else {
|
||||
if ($size > 8) {
|
||||
$code = "SDL_Swap${BEorLE}${size}($val)";
|
||||
} else {
|
||||
$code = $val;
|
||||
}
|
||||
|
||||
if (($signed) and (!$float)) {
|
||||
$code = "((Sint${size}) $code)";
|
||||
}
|
||||
}
|
||||
|
||||
return "${code}";
|
||||
}
|
||||
|
||||
|
||||
sub maxIntVal {
|
||||
my $size = shift;
|
||||
if ($size == 8) {
|
||||
return 0x7F;
|
||||
} elsif ($size == 16) {
|
||||
return 0x7FFF;
|
||||
} elsif ($size == 32) {
|
||||
return 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
die("bug in script.\n");
|
||||
}
|
||||
|
||||
sub getFloatToIntMult {
|
||||
my $size = shift;
|
||||
my $val = maxIntVal($size) . '.0';
|
||||
$val .= 'f' if ($size < 32);
|
||||
return $val;
|
||||
}
|
||||
|
||||
sub getIntToFloatDivBy {
|
||||
my $size = shift;
|
||||
return 'DIVBY' . maxIntVal($size);
|
||||
}
|
||||
|
||||
sub getSignFlipVal {
|
||||
my $size = shift;
|
||||
if ($size == 8) {
|
||||
return '0x80';
|
||||
} elsif ($size == 16) {
|
||||
return '0x8000';
|
||||
} elsif ($size == 32) {
|
||||
return '0x80000000';
|
||||
}
|
||||
|
||||
die("bug in script.\n");
|
||||
}
|
||||
|
||||
sub buildCvtFunc {
|
||||
my ($from, $to) = @_;
|
||||
my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
|
||||
my ($tsigned, $tfloat, $tsize, $tendian, $tctype) = splittype($to);
|
||||
my $diffs = 0;
|
||||
$diffs++ if ($fsize != $tsize);
|
||||
$diffs++ if ($fsigned != $tsigned);
|
||||
$diffs++ if ($ffloat != $tfloat);
|
||||
$diffs++ if ($fendian ne $tendian);
|
||||
|
||||
return if ($diffs == 0);
|
||||
|
||||
my $hashid = getTypeConvertHashId($from, $to);
|
||||
if (1) { # !!! FIXME: if ($diffs > 1) {
|
||||
my $sym = "SDL_Convert_${from}_to_${to}";
|
||||
$funcs{$hashid} = $sym;
|
||||
$custom_converters++;
|
||||
|
||||
# Always unsigned for ints, for possible byteswaps.
|
||||
my $srctype = (($ffloat) ? 'float' : "Uint${fsize}");
|
||||
|
||||
print <<EOF;
|
||||
static void SDLCALL
|
||||
${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||
{
|
||||
int i;
|
||||
const $srctype *src;
|
||||
$tctype *dst;
|
||||
|
||||
#if DEBUG_CONVERT
|
||||
fprintf(stderr, "Converting AUDIO_${from} to AUDIO_${to}.\\n");
|
||||
#endif
|
||||
|
||||
EOF
|
||||
|
||||
if ($fsize < $tsize) {
|
||||
my $mult = $tsize / $fsize;
|
||||
print <<EOF;
|
||||
src = ((const $srctype *) (cvt->buf + cvt->len_cvt)) - 1;
|
||||
dst = (($tctype *) (cvt->buf + cvt->len_cvt * $mult)) - 1;
|
||||
for (i = cvt->len_cvt / sizeof ($srctype); i; --i, --src, --dst) {
|
||||
EOF
|
||||
} else {
|
||||
print <<EOF;
|
||||
src = (const $srctype *) cvt->buf;
|
||||
dst = ($tctype *) cvt->buf;
|
||||
for (i = cvt->len_cvt / sizeof ($srctype); i; --i, ++src, ++dst) {
|
||||
EOF
|
||||
}
|
||||
|
||||
# Have to convert to/from float/int.
|
||||
# !!! FIXME: cast through double for int32<->float?
|
||||
my $code = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, '*src');
|
||||
if ($ffloat != $tfloat) {
|
||||
if ($ffloat) {
|
||||
my $mult = getFloatToIntMult($tsize);
|
||||
if (!$tsigned) { # bump from -1.0f/1.0f to 0.0f/2.0f
|
||||
$code = "($code + 1.0f)";
|
||||
}
|
||||
$code = "(($tctype) ($code * $mult))";
|
||||
} else {
|
||||
# $divby will be the reciprocal, to avoid pipeline stalls
|
||||
# from floating point division...so multiply it.
|
||||
my $divby = getIntToFloatDivBy($fsize);
|
||||
$code = "(((float) $code) * $divby)";
|
||||
if (!$fsigned) { # bump from 0.0f/2.0f to -1.0f/1.0f.
|
||||
$code = "($code - 1.0f)";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# All integer conversions here.
|
||||
if ($fsigned != $tsigned) {
|
||||
my $signflipval = getSignFlipVal($fsize);
|
||||
$code = "(($code) ^ $signflipval)";
|
||||
}
|
||||
|
||||
my $shiftval = abs($fsize - $tsize);
|
||||
if ($fsize < $tsize) {
|
||||
$code = "((($tctype) $code) << $shiftval)";
|
||||
} elsif ($fsize > $tsize) {
|
||||
$code = "(($tctype) ($code >> $shiftval))";
|
||||
}
|
||||
}
|
||||
|
||||
my $swap = getSwapFunc($tsize, $tsigned, $tfloat, $tendian, 'val');
|
||||
|
||||
print <<EOF;
|
||||
const $tctype val = $code;
|
||||
*dst = ${swap};
|
||||
}
|
||||
|
||||
EOF
|
||||
|
||||
if ($fsize > $tsize) {
|
||||
my $divby = $fsize / $tsize;
|
||||
print(" cvt->len_cvt /= $divby;\n");
|
||||
} elsif ($fsize < $tsize) {
|
||||
my $mult = $tsize / $fsize;
|
||||
print(" cvt->len_cvt *= $mult;\n");
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
if (cvt->filters[++cvt->filter_index]) {
|
||||
cvt->filters[cvt->filter_index] (cvt, AUDIO_$to);
|
||||
}
|
||||
}
|
||||
|
||||
EOF
|
||||
|
||||
} else {
|
||||
if ($fsigned != $tsigned) {
|
||||
$funcs{$hashid} = 'SDL_ConvertSigned';
|
||||
} elsif ($ffloat != $tfloat) {
|
||||
$funcs{$hashid} = 'SDL_ConvertFloat';
|
||||
} elsif ($fsize != $tsize) {
|
||||
$funcs{$hashid} = 'SDL_ConvertSize';
|
||||
} elsif ($fendian ne $tendian) {
|
||||
$funcs{$hashid} = 'SDL_ConvertEndian';
|
||||
} else {
|
||||
die("error in script.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub buildTypeConverters {
|
||||
print "#if !NO_CONVERTERS\n\n";
|
||||
foreach (@audiotypes) {
|
||||
my $from = $_;
|
||||
foreach (@audiotypes) {
|
||||
my $to = $_;
|
||||
buildCvtFunc($from, $to);
|
||||
}
|
||||
}
|
||||
print "#endif /* !NO_CONVERTERS */\n\n\n";
|
||||
|
||||
print "const SDL_AudioTypeFilters sdl_audio_type_filters[] =\n{\n";
|
||||
print "#if !NO_CONVERTERS\n";
|
||||
foreach (@audiotypes) {
|
||||
my $from = $_;
|
||||
foreach (@audiotypes) {
|
||||
my $to = $_;
|
||||
if ($from ne $to) {
|
||||
my $hashid = getTypeConvertHashId($from, $to);
|
||||
my $sym = $funcs{$hashid};
|
||||
print(" { AUDIO_$from, AUDIO_$to, $sym },\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
print "#endif /* !NO_CONVERTERS */\n";
|
||||
|
||||
print(" { 0, 0, NULL }\n");
|
||||
print "};\n\n\n";
|
||||
}
|
||||
|
||||
sub getBiggerCtype {
|
||||
my ($isfloat, $size) = @_;
|
||||
|
||||
if ($isfloat) {
|
||||
if ($size == 32) {
|
||||
return 'double';
|
||||
}
|
||||
die("bug in script.\n");
|
||||
}
|
||||
|
||||
if ($size == 8) {
|
||||
return 'Sint16';
|
||||
} elsif ($size == 16) {
|
||||
return 'Sint32'
|
||||
} elsif ($size == 32) {
|
||||
return 'Sint64'
|
||||
}
|
||||
|
||||
die("bug in script.\n");
|
||||
}
|
||||
|
||||
|
||||
# These handle arbitrary resamples...44100Hz to 48000Hz, for example.
|
||||
# Man, this code is skanky.
|
||||
sub buildArbitraryResampleFunc {
|
||||
# !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
|
||||
my ($from, $channels, $upsample) = @_;
|
||||
my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
|
||||
|
||||
my $bigger = getBiggerCtype($ffloat, $fsize);
|
||||
my $interp = ($ffloat) ? '* 0.5' : '>> 1';
|
||||
|
||||
my $resample = ($upsample) ? 'Upsample' : 'Downsample';
|
||||
my $hashid = getResamplerHashId($from, $channels, $upsample, 0);
|
||||
my $sym = "SDL_${resample}_${from}_${channels}c";
|
||||
$funcs{$hashid} = $sym;
|
||||
$custom_converters++;
|
||||
|
||||
my $fudge = $fsize * $channels * 2; # !!! FIXME
|
||||
my $eps_adjust = ($upsample) ? 'dstsize' : 'srcsize';
|
||||
my $incr = '';
|
||||
my $incr2 = '';
|
||||
my $block_align = $channels * $fsize/8;
|
||||
|
||||
|
||||
# !!! FIXME: DEBUG_CONVERT should report frequencies.
|
||||
print <<EOF;
|
||||
static void SDLCALL
|
||||
${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||
{
|
||||
#if DEBUG_CONVERT
|
||||
fprintf(stderr, "$resample arbitrary (x%f) AUDIO_${from}, ${channels} channels.\\n", cvt->rate_incr);
|
||||
#endif
|
||||
|
||||
const int srcsize = cvt->len_cvt - $fudge;
|
||||
const int dstsize = (int) (((double)(cvt->len_cvt/${block_align})) * cvt->rate_incr) * ${block_align};
|
||||
register int eps = 0;
|
||||
EOF
|
||||
|
||||
my $endcomparison = '!=';
|
||||
|
||||
# Upsampling (growing the buffer) needs to work backwards, since we
|
||||
# overwrite the buffer as we go.
|
||||
if ($upsample) {
|
||||
$endcomparison = '>='; # dst > target
|
||||
print <<EOF;
|
||||
$fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels;
|
||||
const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
|
||||
const $fctype *target = ((const $fctype *) cvt->buf);
|
||||
EOF
|
||||
} else {
|
||||
$endcomparison = '<'; # dst < target
|
||||
print <<EOF;
|
||||
$fctype *dst = ($fctype *) cvt->buf;
|
||||
const $fctype *src = ($fctype *) cvt->buf;
|
||||
const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
|
||||
EOF
|
||||
}
|
||||
|
||||
for (my $i = 0; $i < $channels; $i++) {
|
||||
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
|
||||
my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
|
||||
print <<EOF;
|
||||
$fctype sample${idx} = $val;
|
||||
EOF
|
||||
}
|
||||
|
||||
for (my $i = 0; $i < $channels; $i++) {
|
||||
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
|
||||
print <<EOF;
|
||||
$fctype last_sample${idx} = sample${idx};
|
||||
EOF
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
while (dst $endcomparison target) {
|
||||
EOF
|
||||
|
||||
if ($upsample) {
|
||||
for (my $i = 0; $i < $channels; $i++) {
|
||||
# !!! FIXME: don't do this swap every write, just when the samples change.
|
||||
my $idx = (($channels - $i) - 1);
|
||||
my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${idx}");
|
||||
print <<EOF;
|
||||
dst[$idx] = $val;
|
||||
EOF
|
||||
}
|
||||
|
||||
$incr = ($channels == 1) ? 'dst--' : "dst -= $channels";
|
||||
$incr2 = ($channels == 1) ? 'src--' : "src -= $channels";
|
||||
|
||||
print <<EOF;
|
||||
$incr;
|
||||
eps += srcsize;
|
||||
if ((eps << 1) >= dstsize) {
|
||||
$incr2;
|
||||
EOF
|
||||
} else { # downsample.
|
||||
$incr = ($channels == 1) ? 'src++' : "src += $channels";
|
||||
print <<EOF;
|
||||
$incr;
|
||||
eps += dstsize;
|
||||
if ((eps << 1) >= srcsize) {
|
||||
EOF
|
||||
for (my $i = 0; $i < $channels; $i++) {
|
||||
my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${i}");
|
||||
print <<EOF;
|
||||
dst[$i] = $val;
|
||||
EOF
|
||||
}
|
||||
|
||||
$incr = ($channels == 1) ? 'dst++' : "dst += $channels";
|
||||
print <<EOF;
|
||||
$incr;
|
||||
EOF
|
||||
}
|
||||
|
||||
for (my $i = 0; $i < $channels; $i++) {
|
||||
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
|
||||
my $swapped = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
|
||||
print <<EOF;
|
||||
sample${idx} = ($fctype) (((($bigger) $swapped) + (($bigger) last_sample${idx})) $interp);
|
||||
EOF
|
||||
}
|
||||
|
||||
for (my $i = 0; $i < $channels; $i++) {
|
||||
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
|
||||
print <<EOF;
|
||||
last_sample${idx} = sample${idx};
|
||||
EOF
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
eps -= $eps_adjust;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
print <<EOF;
|
||||
cvt->len_cvt = dstsize;
|
||||
if (cvt->filters[++cvt->filter_index]) {
|
||||
cvt->filters[cvt->filter_index] (cvt, format);
|
||||
}
|
||||
}
|
||||
|
||||
EOF
|
||||
|
||||
}
|
||||
|
||||
# These handle clean resamples...doubling and quadrupling the sample rate, etc.
|
||||
sub buildMultipleResampleFunc {
|
||||
# !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
|
||||
my ($from, $channels, $upsample, $multiple) = @_;
|
||||
my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
|
||||
|
||||
my $bigger = getBiggerCtype($ffloat, $fsize);
|
||||
my $interp = ($ffloat) ? '* 0.5' : '>> 1';
|
||||
my $interp2 = ($ffloat) ? '* 0.25' : '>> 2';
|
||||
my $mult3 = ($ffloat) ? '3.0' : '3';
|
||||
my $lencvtop = ($upsample) ? '*' : '/';
|
||||
|
||||
my $resample = ($upsample) ? 'Upsample' : 'Downsample';
|
||||
my $hashid = getResamplerHashId($from, $channels, $upsample, $multiple);
|
||||
my $sym = "SDL_${resample}_${from}_${channels}c_x${multiple}";
|
||||
$funcs{$hashid} = $sym;
|
||||
$custom_converters++;
|
||||
|
||||
# !!! FIXME: DEBUG_CONVERT should report frequencies.
|
||||
print <<EOF;
|
||||
static void SDLCALL
|
||||
${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
||||
{
|
||||
#if DEBUG_CONVERT
|
||||
fprintf(stderr, "$resample (x${multiple}) AUDIO_${from}, ${channels} channels.\\n");
|
||||
#endif
|
||||
|
||||
const int dstsize = cvt->len_cvt $lencvtop $multiple;
|
||||
EOF
|
||||
|
||||
my $endcomparison = '!=';
|
||||
|
||||
# Upsampling (growing the buffer) needs to work backwards, since we
|
||||
# overwrite the buffer as we go.
|
||||
if ($upsample) {
|
||||
$endcomparison = '>='; # dst > target
|
||||
print <<EOF;
|
||||
$fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels * $multiple;
|
||||
const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
|
||||
const $fctype *target = ((const $fctype *) cvt->buf);
|
||||
EOF
|
||||
} else {
|
||||
$endcomparison = '<'; # dst < target
|
||||
print <<EOF;
|
||||
$fctype *dst = ($fctype *) cvt->buf;
|
||||
const $fctype *src = ($fctype *) cvt->buf;
|
||||
const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
|
||||
EOF
|
||||
}
|
||||
|
||||
for (my $i = 0; $i < $channels; $i++) {
|
||||
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
|
||||
my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
|
||||
print <<EOF;
|
||||
$bigger last_sample${idx} = ($bigger) $val;
|
||||
EOF
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
while (dst $endcomparison target) {
|
||||
EOF
|
||||
|
||||
for (my $i = 0; $i < $channels; $i++) {
|
||||
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
|
||||
my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
|
||||
print <<EOF;
|
||||
const $bigger sample${idx} = ($bigger) $val;
|
||||
EOF
|
||||
}
|
||||
|
||||
my $incr = '';
|
||||
if ($upsample) {
|
||||
$incr = ($channels == 1) ? 'src--' : "src -= $channels";
|
||||
} else {
|
||||
my $amount = $channels * $multiple;
|
||||
$incr = "src += $amount"; # can't ever be 1, so no "++" version.
|
||||
}
|
||||
|
||||
|
||||
print <<EOF;
|
||||
$incr;
|
||||
EOF
|
||||
|
||||
# !!! FIXME: This really begs for some Altivec or SSE, etc.
|
||||
if ($upsample) {
|
||||
if ($multiple == 2) {
|
||||
for (my $i = $channels-1; $i >= 0; $i--) {
|
||||
my $dsti = $i + $channels;
|
||||
print <<EOF;
|
||||
dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
|
||||
EOF
|
||||
}
|
||||
for (my $i = $channels-1; $i >= 0; $i--) {
|
||||
my $dsti = $i;
|
||||
print <<EOF;
|
||||
dst[$dsti] = ($fctype) sample${i};
|
||||
EOF
|
||||
}
|
||||
} elsif ($multiple == 4) {
|
||||
for (my $i = $channels-1; $i >= 0; $i--) {
|
||||
my $dsti = $i + ($channels * 3);
|
||||
print <<EOF;
|
||||
dst[$dsti] = ($fctype) ((sample${i} + ($mult3 * last_sample${i})) $interp2);
|
||||
EOF
|
||||
}
|
||||
|
||||
for (my $i = $channels-1; $i >= 0; $i--) {
|
||||
my $dsti = $i + ($channels * 2);
|
||||
print <<EOF;
|
||||
dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
|
||||
EOF
|
||||
}
|
||||
|
||||
for (my $i = $channels-1; $i >= 0; $i--) {
|
||||
my $dsti = $i + ($channels * 1);
|
||||
print <<EOF;
|
||||
dst[$dsti] = ($fctype) ((($mult3 * sample${i}) + last_sample${i}) $interp2);
|
||||
EOF
|
||||
}
|
||||
|
||||
for (my $i = $channels-1; $i >= 0; $i--) {
|
||||
my $dsti = $i + ($channels * 0);
|
||||
print <<EOF;
|
||||
dst[$dsti] = ($fctype) sample${i};
|
||||
EOF
|
||||
}
|
||||
} else {
|
||||
die('bug in program.'); # we only handle x2 and x4.
|
||||
}
|
||||
} else { # downsample.
|
||||
if ($multiple == 2) {
|
||||
for (my $i = 0; $i < $channels; $i++) {
|
||||
print <<EOF;
|
||||
dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
|
||||
EOF
|
||||
}
|
||||
} elsif ($multiple == 4) {
|
||||
# !!! FIXME: interpolate all 4 samples?
|
||||
for (my $i = 0; $i < $channels; $i++) {
|
||||
print <<EOF;
|
||||
dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
|
||||
EOF
|
||||
}
|
||||
} else {
|
||||
die('bug in program.'); # we only handle x2 and x4.
|
||||
}
|
||||
}
|
||||
|
||||
for (my $i = 0; $i < $channels; $i++) {
|
||||
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
|
||||
print <<EOF;
|
||||
last_sample${idx} = sample${idx};
|
||||
EOF
|
||||
}
|
||||
|
||||
if ($upsample) {
|
||||
my $amount = $channels * $multiple;
|
||||
$incr = "dst -= $amount"; # can't ever be 1, so no "--" version.
|
||||
} else {
|
||||
$incr = ($channels == 1) ? 'dst++' : "dst += $channels";
|
||||
}
|
||||
|
||||
print <<EOF;
|
||||
$incr;
|
||||
}
|
||||
|
||||
cvt->len_cvt = dstsize;
|
||||
if (cvt->filters[++cvt->filter_index]) {
|
||||
cvt->filters[cvt->filter_index] (cvt, format);
|
||||
}
|
||||
}
|
||||
|
||||
EOF
|
||||
|
||||
}
|
||||
|
||||
sub buildResamplers {
|
||||
print "#if !NO_RESAMPLERS\n\n";
|
||||
foreach (@audiotypes) {
|
||||
my $from = $_;
|
||||
foreach (@channels) {
|
||||
my $channel = $_;
|
||||
buildArbitraryResampleFunc($from, $channel, 1);
|
||||
buildArbitraryResampleFunc($from, $channel, 0);
|
||||
}
|
||||
}
|
||||
|
||||
print "\n#if !LESS_RESAMPLERS\n\n";
|
||||
foreach (@audiotypes) {
|
||||
my $from = $_;
|
||||
foreach (@channels) {
|
||||
my $channel = $_;
|
||||
for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
|
||||
buildMultipleResampleFunc($from, $channel, 1, $multiple);
|
||||
buildMultipleResampleFunc($from, $channel, 0, $multiple);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print "#endif /* !LESS_RESAMPLERS */\n";
|
||||
print "#endif /* !NO_RESAMPLERS */\n\n\n";
|
||||
|
||||
print "const SDL_AudioRateFilters sdl_audio_rate_filters[] =\n{\n";
|
||||
print "#if !NO_RESAMPLERS\n";
|
||||
foreach (@audiotypes) {
|
||||
my $from = $_;
|
||||
foreach (@channels) {
|
||||
my $channel = $_;
|
||||
for (my $upsample = 0; $upsample <= 1; $upsample++) {
|
||||
my $hashid = getResamplerHashId($from, $channel, $upsample, 0);
|
||||
my $sym = $funcs{$hashid};
|
||||
print(" { AUDIO_$from, $channel, $upsample, 0, $sym },\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print "#if !LESS_RESAMPLERS\n";
|
||||
foreach (@audiotypes) {
|
||||
my $from = $_;
|
||||
foreach (@channels) {
|
||||
my $channel = $_;
|
||||
for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
|
||||
for (my $upsample = 0; $upsample <= 1; $upsample++) {
|
||||
my $hashid = getResamplerHashId($from, $channel, $upsample, $multiple);
|
||||
my $sym = $funcs{$hashid};
|
||||
print(" { AUDIO_$from, $channel, $upsample, $multiple, $sym },\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print "#endif /* !LESS_RESAMPLERS */\n";
|
||||
print "#endif /* !NO_RESAMPLERS */\n";
|
||||
print(" { 0, 0, 0, 0, NULL }\n");
|
||||
print "};\n\n";
|
||||
}
|
||||
|
||||
|
||||
# mainline ...
|
||||
|
||||
outputHeader();
|
||||
buildTypeConverters();
|
||||
buildResamplers();
|
||||
outputFooter();
|
||||
|
||||
exit 0;
|
||||
|
||||
# end of sdlgenaudiocvt.pl ...
|
||||
|
Loading…
Reference in New Issue