Mercurial > SDL_sound_CoreAudio
diff alt_audio_convert.c @ 365:f61eadea1f44
More revisions from Frank.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Tue, 18 Jun 2002 21:49:44 +0000 |
parents | c984aa6990f7 |
children | eda146d666d1 |
line wrap: on
line diff
--- a/alt_audio_convert.c Thu Jun 13 23:15:37 2002 +0000 +++ b/alt_audio_convert.c Tue Jun 18 21:49:44 2002 +0000 @@ -1,50 +1,117 @@ /* - Extended Audio Converter for SDL (Simple DirectMedia Layer) - Copyright (C) 2002 Frank Ranostaj - Institute of Applied Physik - Johann Wolfgang Goethe-Universität - Frankfurt am Main, Germany - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. + * Extended Audio Converter for SDL (Simple DirectMedia Layer) + * Copyright (C) 2002 Frank Ranostaj + * Institute of Applied Physik + * Johann Wolfgang Goethe-Universität + * Frankfurt am Main, Germany + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Frank Ranostaj + * ranostaj@stud.uni-frankfurt.de + * + * (This code blatantly abducted for SDL_sound. Thanks, Frank! --ryan.) + */ - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Frank Ranostaj - ranostaj@stud.uni-frankfurt.de - -(This code blatantly abducted for SDL_sound. Thanks, Frank! --ryan.) - -*/ #include "alt_audio_convert.h" #include <stdlib.h> #include <math.h> +/* just to make sure this is defined... */ + +#ifndef min +#define min(x, y) ( ((x) < (y)) ? (x) : (y) ) +#endif + +#ifndef max +#define max(x, y) ( ((x) > (y)) ? (x) : (y) ) +#endif + + /* some macros for "parsing" format */ #define IS_8BIT(x) ((x).format & 0x0008) #define IS_16BIT(x) ((x).format & 0x0010) -#define IS_FLOAT(x) ((x).format & 0x0020) /* !!! FIXME: is this ok? */ +#define IS_FLOAT(x) ((x).format & 0x0020) #define IS_SIGNED(x) ((x).format & 0x8000) -#define IS_SYSENDIAN(x) ((AUDIO_U16SYS ^ (x).format) & 0x1000) +#define IS_SYSENDIAN(x) ((~AUDIO_U16SYS ^ (x).format) & 0x1000) /*-------------------------------------------------------------------------*/ /* this filter (Kaiser-window beta=6.8) gives a decent -80dB attentuation */ -static const int filter[_fsize/2] = { +static const int filter[_fsize / 2] = +{ 0, 20798, 0, -6764, 0, 3863, 0, -2560, 0, 1800, 0, -1295, 0, 936, 0, -671, 0, 474, 0, -326, 0, 217, 0, -138, - 0, 83, 0, -46, 0, 23, 0, -9 }; + 0, 83, 0, -46, 0, 23, 0, -9 +}; + + +/*-------------------------------------------------------------------------*/ +/* the purpose of the RateConverterBuffer is to provide a continous storage + for head and tail of the (sample)-buffer. This allows a simple and + perfomant implemantation of the sample rate converters. Depending of the + operation mode, two layouts for the RateConverterBuffer.inbuffer are + possible: + + in the Loop Mode: + ... T-4 T-3 T-2 T-1 H+0 H+1 H+2 H+3 H+4 ... + | + linp, finp + + in the Single Mode (non Loop): + ... T-4 T-3 T-2 T-1 0 0 0 ... 0 0 0 H+0 H+1 H+2 H+3 H+4 ... + | | + linp finp + + The RateConverterBuffer allows an accurate attack and decay of the + filters in the rate Converters. + + The pointer finp are actually shifted against the depicted position so + that on the first invocation of the rate converter the input of the + filter is nearly complete in the zero region, only one input value is + used. After the calculation of the first output value, the pointer are + incremented or decremented depending on down or up conversion and the + first two input value are taken into account. This procedure repeats + until the filter has processed all zeroes. The distance of the pointer + movement is stored in flength. + + Further a pointer cinp to the sample buffer itself is stored. The pointer + to the sample buffer is shifted too, so that on the first use of this + pointer the filter is complete in the sample buffer. The pointer moves + over the sample buffer until it reaches the other end. The distance of + the movement is stored in clength. + + Finally the decay of the filter is done by linp, llength like finp, + flength, but in reverse order. + + buffer denotes the start or the end of the output buffer, depending + on direction of the rate conversion. + + All pointer and length referring the buffer as Sint16. All length + are refering to the input buffer */ + +typedef struct +{ + Sint16 inbuffer[6*_fsize]; + Sint16 *finp, *cinp, *linp; + Sint16 *buffer; + int flength, clength, llength; +} RateConverterBuffer; + /* Mono (1 channel ) */ #define Suffix(x) x##1 @@ -56,9 +123,10 @@ #include "filter_templates.h" #undef Suffix + /*-------------------------------------------------------------------------*/ static int ConvertAudio( Sound_AudioCVT *Data, - Uint8* buffer, int length, int mode ) + Uint8* buffer, int length, int mode ) { AdapterC Temp; int i; @@ -293,71 +361,157 @@ } /*-------------------------------------------------------------------------*/ -static int doubleRateStereo( AdapterC Data, int length ) +static void initRateConverterBuffer( RateConverterBuffer *rcb, + AdapterC* Data, int length, int rel_size ) { - length >>= 2; - _doubleRate2( (Sint16*)Data.buffer, Data.mode, length ); - return 4*_doubleRate2( (Sint16*)Data.buffer+1, Data.mode, length ); -} + int size, slength; + int den, num; + int i; + + den = Data->filter->denominator; + num = Data->filter->numerator; + size = _fsize * rel_size; + length >>= 1; + slength = rel_size > 0 ? length : -length; + + rcb->buffer = (Sint16*)( Data->buffer ); -static int doubleRateMono( AdapterC Data, int length ) -{ - return 2*_doubleRate1( (Sint16*)Data.buffer, Data.mode, length>>1 ); + if( Data->mode & SDL_AI_Loop ) + { + // !!!FIXME: modulo length, take scale into account + for( i = 0; i < size; i++ ) + { + rcb->inbuffer[i] = rcb->buffer[length-size+i]; + rcb->inbuffer[i+size] = rcb->buffer[i]; + } + rcb->finp = rcb->linp = rcb->inbuffer + size; + if( size < 0 ) + rcb->buffer += num * ( length + 2 * size ) / den; + } + else + { + for( i = 0; i < size; i++ ) + { + int j; + j = length-size+i; + rcb->inbuffer[i] = j < 0 ? 0 : rcb->buffer[j]; + rcb->inbuffer[i+size] = 0; + rcb->inbuffer[i+2*size] = i < length ? rcb->buffer[i] : 0; + } + // !!!FIXME: take lenght < size into account + rcb->finp = rcb->inbuffer + abs( 3*size/2 ) + size/2; + rcb->linp = rcb->inbuffer + abs( 3*size/2 ) - size/2; + rcb->flength = rcb->llength = 2*size; + rcb->clength = slength - 2*size; + + if( size < 0 ) + rcb->buffer += num * ( length + 2 * size ) / den; + } } -/*-------------------------------------------------------------------------*/ -static int halfRateStereo( AdapterC Data, int length ) +static void nextRateConverterBuffer( RateConverterBuffer *rcb ) { - length >>= 2; - _halfRate2( (Sint16*)Data.buffer, Data.mode, length ); - return 4*_halfRate2( (Sint16*)Data.buffer+1, Data.mode, length ); + rcb->buffer++; + rcb->finp++; + rcb->cinp++; + rcb->linp++; } -static int halfRateMono( AdapterC Data, int length ) +typedef Sint16* (*RateConverter)( Sint16*, Sint16*, int, VarFilter*, int*); +static int doRateConversion( RateConverterBuffer* rcb, + RateConverter ffp, VarFilter* filter ) { - return 2*_halfRate2( (Sint16*)Data.buffer, Data.mode, length>>1 ); + int pos = 0; + Sint16 *outp; + outp = rcb->buffer; + + outp = (*ffp)( outp, rcb->finp, rcb->flength, filter, &pos ); + outp = (*ffp)( outp, rcb->cinp, rcb->clength, filter, &pos ); + outp = (*ffp)( outp, rcb->linp, rcb->llength, filter, &pos ); + return 2 * abs( rcb->buffer - outp ); +} + + +/*-------------------------------------------------------------------------*/ +static int doubleRateMono( AdapterC Data, int length ) +{ + RateConverterBuffer rcb; + initRateConverterBuffer( &rcb, &Data, length, 1 ); + return doRateConversion( &rcb, doubleRate1, NULL ); +} + +static int doubleRateStereo( AdapterC Data, int length ) +{ + RateConverterBuffer rcb; + initRateConverterBuffer( &rcb, &Data, length, 2 ); + doRateConversion( &rcb, doubleRate2, NULL ); + nextRateConverterBuffer( &rcb ); + return 2 + doRateConversion( &rcb, doubleRate2, NULL ); } /*-------------------------------------------------------------------------*/ -static int varRateUpStereo( AdapterC Data, int length ) +static int halfRateMono( AdapterC Data, int length ) { - length >>= 2; - _varRateUp2( (Sint16*)Data.buffer, Data.mode, Data.filter, length ); - return 4 * _varRateUp2( (Sint16*)Data.buffer+1, - Data.mode, Data.filter, length ); + RateConverterBuffer rcb; + initRateConverterBuffer( &rcb, &Data, length, -1 ); + return doRateConversion( &rcb, halfRate1, NULL ); } -static int varRateUpMono( AdapterC Data, int length ) +static int halfRateStereo( AdapterC Data, int length ) { - return 2 * _varRateUp1( (Sint16*)Data.buffer, - Data.mode, Data.filter, length>>1 ); + RateConverterBuffer rcb; + initRateConverterBuffer( &rcb, &Data, length, -2 ); + doRateConversion( &rcb, halfRate2, NULL ); + nextRateConverterBuffer( &rcb ); + return 2 + doRateConversion( &rcb, halfRate2, NULL ); +} + +/*-------------------------------------------------------------------------*/ +static int increaseRateMono( AdapterC Data, int length ) +{ + RateConverterBuffer rcb; + initRateConverterBuffer( &rcb, &Data, length, 2 ); + return doRateConversion( &rcb, increaseRate1, Data.filter ); } -static int varRateDownStereo( AdapterC Data, int length ) +static int increaseRateStereo( AdapterC Data, int length ) { - length >>= 2; - _varRateDown2( (Sint16*)Data.buffer, Data.mode, Data.filter, length ); - return 2 * _varRateDown2( (Sint16*)Data.buffer+1, - Data.mode, Data.filter, length ); + RateConverterBuffer rcb; + initRateConverterBuffer( &rcb, &Data, length, 4 ); + doRateConversion( &rcb, increaseRate2, Data.filter ); + nextRateConverterBuffer( &rcb ); + return 2 + doRateConversion( &rcb, increaseRate2, Data.filter ); } -static int varRateDownMono( AdapterC Data, int length ) +/*-------------------------------------------------------------------------*/ +static int decreaseRateMono( AdapterC Data, int length ) { - return _varRateDown1( (Sint16*)Data.buffer, - Data.mode, Data.filter, length>>1 ); + RateConverterBuffer rcb; + initRateConverterBuffer( &rcb, &Data, length, -2 ); + return doRateConversion( &rcb, decreaseRate1, Data.filter ); } +static int decreaseRateStereo( AdapterC Data, int length ) +{ + RateConverterBuffer rcb; + initRateConverterBuffer( &rcb, &Data, length, -4 ); + doRateConversion( &rcb, decreaseRate2, Data.filter ); + nextRateConverterBuffer( &rcb ); + return doRateConversion( &rcb, decreaseRate2, Data.filter ); +} + + /*-------------------------------------------------------------------------*/ typedef struct{ Sint16 denominator; Sint16 numerator; } Fraction; +/* gives a maximal error of 3% and typical less than 0.2% */ static Fraction findFraction( float Value ) { -/* gives a maximal error of 3% and typical less than 0.2% */ - const Uint8 frac[96]={ - 1, 2, -1, /* /1 */ + const Sint8 frac[95]={ + 2, -1, /* /1 */ 1, 3, -1, /* /2 */ 2, 4, 5, -1, /* /3 */ 3, 5, 7, -1, /* /4 */ @@ -376,12 +530,12 @@ Fraction Result = {0,0}; - int n,num,den=1; + int n,num=1,den=1; float RelErr, BestErr = 0; if( Value < 31/64. || Value > 64/31. ) return Result; - for( n = 0; n < sizeof(frac); num=frac[++n] ) + for( n = 0; n < sizeof(frac); num=frac[n++] ) { if( num < 0 ) den++; RelErr = Value * num / den; @@ -403,7 +557,8 @@ else return sin(x)/x; } -static void calculateVarFilter( Sint16* dst, float Ratio, float phase, float scale ) +static void calculateVarFilter( Sint16* dst, + float Ratio, float phase, float scale ) { const Uint16 KaiserWindow7[]= { 22930, 16292, 14648, 14288, 14470, 14945, 15608, 16404, @@ -440,13 +595,14 @@ { int i,n,d; Fraction IRatio; - float phase; + float phase = 0.; IRatio = findFraction( Ratio ); Ratio = min( Ratio, 1/Ratio ); n = IRatio.numerator; d = IRatio.denominator; - filter->pos_mod = d; + filter->denominator = d; + filter->numerator = n; for( i = 0; i < d; i++ ) { @@ -466,7 +622,7 @@ /*-------------------------------------------------------------------------*/ static void createRateConverter( Sound_AudioCVT *Data, int* fip, - int SrcRate, int DestRate, int Channel ) + int SrcRate, int DestRate, int Channel ) { int filter_index = *fip; @@ -506,7 +662,7 @@ { setupVarFilter( &Data->filter, Ratio, Up ); Data->adapter[VarPos] = - Mono ? varRateUpMono : varRateUpStereo; + Mono ? increaseRateMono : increaseRateStereo; Data->len_mult *= 2; Data->add *= 2; Data->add += _fsize; @@ -515,7 +671,7 @@ { setupVarFilter( &Data->filter, Ratio, Down ); Data->adapter[filter_index++] = - Mono ? varRateDownMono : varRateDownStereo; + Mono ? decreaseRateMono : decreaseRateStereo; } *fip = filter_index; } @@ -643,8 +799,8 @@ /*-------------------------------------------------------------------------*/ -DECLSPEC int BuildAudioCVT(Sound_AudioCVT *Data, - SDL_AudioSpec src, SDL_AudioSpec dst ) +int BuildAudioCVT( Sound_AudioCVT *Data, + SDL_AudioSpec src, SDL_AudioSpec dst ) { SDL_AudioSpec intrm; int filter_index = 0; @@ -733,14 +889,14 @@ AdapterDesc(convertMonoToStereo16Bit), AdapterDesc(convertMonoToStereo8Bit), AdapterDesc(minus5dB), + AdapterDesc(doubleRateMono), AdapterDesc(doubleRateStereo), - AdapterDesc(doubleRateMono), - AdapterDesc(halfRateStereo), AdapterDesc(halfRateMono), - AdapterDesc(varRateUpStereo), - AdapterDesc(varRateUpMono), - AdapterDesc(varRateDownStereo), - AdapterDesc(varRateDownMono), + AdapterDesc(halfRateStereo), + AdapterDesc(increaseRateMono), + AdapterDesc(increaseRateStereo), + AdapterDesc(decreaseRateMono), + AdapterDesc(decreaseRateStereo), { NULL, "----------NULL-----------" } }; const int AdapterDescMax = sizeof(AdapterDescription) @@ -766,8 +922,8 @@ int Sound_BuildAudioCVT(Sound_AudioCVT *Data, - Uint16 src_format, Uint8 src_channels, int src_rate, - Uint16 dst_format, Uint8 dst_channels, int dst_rate) + Uint16 src_format, Uint8 src_channels, int src_rate, + Uint16 dst_format, Uint8 dst_channels, int dst_rate) { SDL_AudioSpec src, dst; int ret;