changeset 365:f61eadea1f44

More revisions from Frank.
author Ryan C. Gordon <icculus@icculus.org>
date Tue, 18 Jun 2002 21:49:44 +0000
parents 4bcbc442d145
children eda146d666d1
files alt_audio_convert.c alt_audio_convert.h filter_templates.h
diffstat 3 files changed, 387 insertions(+), 341 deletions(-) [+]
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;
--- a/alt_audio_convert.h	Thu Jun 13 23:15:37 2002 +0000
+++ b/alt_audio_convert.h	Tue Jun 18 21:49:44 2002 +0000
@@ -1,33 +1,32 @@
 /*
-   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.)
-
-*/
-
-#ifndef _INCLUDE_AUDIO_CONVERT_H_
-#define _INCLUDE_AUDIO_CONVERT_H_
+#ifndef _INCLUDE_ALT_AUDIO_CONVERT_H_
+#define _INCLUDE_ALT_AUDIO_CONVERT_H_
 
 #include "SDL_audio.h"
 #define Sound_AI_Loop 0x2
@@ -37,7 +36,8 @@
 typedef struct{
    Sint16 c[16][2*_fsize];
    char incr[16];
-   int pos_mod;
+   int denominator;
+   int numerator;
 } VarFilter;
 
 typedef struct{
@@ -74,5 +74,5 @@
    Uint16 src_format, Uint8 src_channels, int src_rate,
    Uint16 dst_format, Uint8 dst_channels, int dst_rate );
 
-#endif /* _INCLUDE_AUDIO_CONVERT_H_ */
+#endif /* _INCLUDE_ALT_AUDIO_CONVERT_H_ */
 
--- a/filter_templates.h	Thu Jun 13 23:15:37 2002 +0000
+++ b/filter_templates.h	Tue Jun 18 21:49:44 2002 +0000
@@ -1,259 +1,149 @@
-/*
-    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
-*/
-
-#ifndef Suffix
-#error include filter_template.h with defined Suffix macro!
-#else
-#define CH(x) (Suffix((x)*))
-//---------------------------------------------------------------------------
-int Suffix(_doubleRate)( short *buffer, int mode, int length )
-{
-    const fsize = _fsize/2;
-    int i,di,border;
-    short inbuffer[_fsize];
+/*
+ *  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.)
+ */
 
-    if( mode & SDL_AI_Loop )
-    {
-        for( i = 0; i < fsize; i++ )
-        {
-            inbuffer[CH(i+fsize)] = buffer[CH(length+i)] = buffer[CH(i)];
-            inbuffer[CH(i)] = buffer[CH(length-fsize+i)];
-        }
-        border = 0;
-    }
-    else
-    {
-        for( i = 0; i < fsize; i++ )
-        {
-            inbuffer[CH(i)] = buffer[CH(length+i)] = 0;
-            inbuffer[CH(i+fsize)] = buffer[CH(i)];
-        }
-        border = fsize/2;
-    }
+#ifndef Suffix
+#error include filter_template.h with defined Suffix macro!
+#else
+#define CH(x) (Suffix((x)*))
+/*-------------------------------------------------------------------------*/
+   /*
+    * !!! FIXME !!!
+    *
+    *
+    * Tune doubleRate(), halfRate() and varRate() for speed
+    * - Frank
+    */
 
-    for(i = length + border - 1; i >= -border; i--)
-    {
-        const short* const inp = i < fsize/2 ?
-                                 &inbuffer[CH(i+fsize)] : &buffer[CH(i)];
-        short* const outp = &buffer[CH(2*(i+border))];
-        int out = 0;
-
-        for( di = 1; di < 1+fsize; di+=2 )
-            out+= filter[di]*( inp[CH(di)/2] + inp[CH(1-di)/2] );
-        outp[CH(1)] = ( 32770*inp[CH(1)] + out) >> 16;
-        outp[CH(0)] = ( 32770*inp[CH(0)] + out) >> 16;
-    }
-    return  2*length + 4*border;
-}
-
-//---------------------------------------------------------------------------
-short Suffix(filterHalfBand)( short* inp )
-{
-    static const int fsize = _fsize;
-    int out = 32770*inp[0];
-    int di;
-    for( di = 1; di < fsize/2; di+=2 )
-    	out+= filter[di]*( inp[CH(di)] + inp[CH(-di)] );
-    return out >> 16;
-}
-
-int Suffix(_halfRate)( short *buffer, int mode, int length )
+/*-------------------------------------------------------------------------*/
+static Sint16* Suffix(doubleRate)( Sint16 *outp, Sint16 *inp, int length,
+                                   VarFilter* filt, int* cpos  )
 {
     static const int fsize = _fsize;
-
-    int i,border;
-
-    short inbuffer[3*_fsize];
-    short *finp, *linp;
+    int i, out;
+    Sint16* to;
 
-    if( mode & SDL_AI_Loop )
-    {
-        if( length & 1 )
-        {
-        // do something meaningful
-        }
-        for( i = 0; i < fsize; i++ )
-        {
-            inbuffer[CH(i)] = buffer[CH(length-fsize+i)];
-            inbuffer[CH(i+fsize)] = buffer[CH(i)];
-        }
-        border = 0;
-        finp = inbuffer + CH( fsize );
-        linp = inbuffer + CH( fsize-length );
-    }
-    else
+    inp += fsize;
+    to = inp + length;
+
+    for(; inp > to; inp -= CH(1) )
     {
-        for( i = 0; i < fsize; i++ )
-        {
-            inbuffer[CH(i)] = buffer[CH(length-fsize+i)];
-            inbuffer[CH(i+fsize)] = 0;
-            inbuffer[CH(i+2*fsize)] = buffer[CH(i)];
-        }
-        border = fsize;
-        finp = inbuffer + CH( (3*fsize)/2 + 2*border );
-        linp = inbuffer + CH( fsize/2 - length );
-    }
-
-    length = ( length + 1 ) / 2;
+        out = 0;
+        for( i = 1; i < 1+fsize; i++ )
+            out+= filter[2*i] * ( inp[CH(i)] + inp[CH(1-i)] );
 
-    for(i = -border; i < fsize; i++)
-    {
-        buffer[CH(i+border)] = Suffix(filterHalfBand)( finp+CH(2*i) );
+        outp[CH(1)] = ( 32770 * inp[CH(1)] + out) >> 16;
+        outp[CH(0)] = ( 32770 * inp[CH(0)] + out) >> 16;
+        outp -= CH(2);
     }
-    for(; i < length-fsize; i++)
-    {
-        buffer[CH(i+border)] = Suffix(filterHalfBand)( buffer+CH(2*i) );
-    }
-    for(; i < length+border; i++)
-    {
-        buffer[CH(i+border)] = Suffix(filterHalfBand)( linp+CH(2*i) );
-    }
-    return length + 2*border;
+    return outp;
 }
 
-//---------------------------------------------------------------------------
-short Suffix(filterVarBand)( VarFilter* filt, short** inpp, char* cpos )
+/*-------------------------------------------------------------------------*/
+static Sint16* Suffix(halfRate)( Sint16 *outp, Sint16 *inp, int length,
+                                 VarFilter* filt, int* cpos  )
 {
-    int di;
-    int out = 0;
-    short *inp = *inpp;
-    int pos = *cpos;
-    short *filter = filt->c[pos];
+    static const int fsize = CH(_fsize/2);
+    int i, out;
+    Sint16* to;
+
+    inp -= fsize;
+    to = inp + length;
 
-    for( di = 0; di < 2*_fsize; di++ )
-    	out+= filter[di] * (int)inp[CH(di)];
+    for(; inp < to; inp+= CH(2) )
+    {
+        out = 32770 * inp[0];
+        for( i = 1; i < fsize/2; i+=2 )
+    	    out+= filter[i]*( (int)inp[CH(i)] + inp[CH(-i)] );
+        outp[0] = out >> 16;
 
-    *inpp += CH(filt->incr[pos]);
-    *cpos = ( pos + 1 ) % filt->pos_mod;
-    return out >> 16;
+        outp += CH(1);
+    }
+    return outp;
 }
 
-int Suffix(_varRateDown)( short* buffer, int mode, VarFilter* filter, int length )
+/*-------------------------------------------------------------------------*/
+static Sint16* Suffix(increaseRate)( Sint16 *outp, Sint16 *inp, int length,
+                                     VarFilter* filt, int* cpos )
 {
-    static const int fsize = _fsize;
-    int i,border;
-    short inbuffer[CH(3*_fsize)];
-    short *finp, *linp, *bufp, *outbuf;
-    char pos = 0;
-    VarFilter* filterp = filter;
+    const static int fsize = 2*_fsize;
+    Sint16 *filter;
+    int out;
+    int i, pos;
+    Sint16* to;
 
-    if( mode & SDL_AI_Loop )
-    {
-        for( i = 0; i < fsize; i++ )
-        {
-            inbuffer[CH(i)] = buffer[CH(length-fsize+i)];
-            inbuffer[CH(i+fsize)] = buffer[CH(i)];
-        }
-        border = 0;
-        finp = inbuffer+CH(fsize);
-        linp = inbuffer+CH(fsize-length);
-    }
-    else
+    inp += fsize;
+    to = inp + length;
+
+    while( inp > to )
     {
-        for( i = 0; i < fsize; i++ )
-        {
-            inbuffer[CH(i)] = buffer[CH(length-fsize+i)];
-            inbuffer[CH(i+fsize)] = 0;
-            inbuffer[CH(i+2*fsize)] = buffer[CH(i)];
-        }
-        border = fsize;
-        finp = inbuffer + CH( 3*fsize/2 );
-        linp = inbuffer + CH( fsize/2 );
-    }
+        pos = *cpos;
+        out = 0;
+        filter = filt->c[pos];
+        for( i = 0; i < 2*_fsize; i++ )
+    	    out+= filter[i] * (int)inp[CH(i)];
+        outp[0] = out >> 16;
 
-    length = ( length + 1 ) / 2;
-    bufp = buffer;
-    outbuf = buffer+CH(border);
-
-    for(i = -border; i < fsize; i++)
-    {
-        outbuf[CH(i)] = Suffix(filterVarBand)( filterp, &finp, &pos );
+        inp -= CH(filt->incr[pos]);
+        outp -= CH(1);
+        *cpos = ( pos + 1 ) % filt->denominator;
     }
-    for(; i < length-fsize; i++)
-    {
-        outbuf[CH(i)] = Suffix(filterVarBand)( filterp, &bufp, &pos );
-    }
-    for(; i < length+border; i++)
-    {
-        outbuf[CH(i)] = Suffix(filterVarBand)( filterp, &linp, &pos );
-    }
-    return length + 2*border;
+    return outp;
 }
 
-int Suffix(_varRateUp)( short* buffer, int mode, VarFilter* filter, int length )
+/*-------------------------------------------------------------------------*/
+static Sint16* Suffix(decreaseRate)( Sint16 *outp, Sint16 *inp, int length,
+                                     VarFilter* filt, int* cpos )
 {
-    static const int fsize = _fsize;
-    int i,border;
-    short inbuffer[CH(3*_fsize)];
-    short *finp, *linp, *bufp, *outbuf;
-    char pos = 0;
-    VarFilter* filterp = filter;
+    const static int fsize = 2*_fsize;
+    Sint16 *filter;
+    int out;
+    int i, pos;
+    Sint16 *to;
 
-    if( mode & SDL_AI_Loop )
-    {
-        for( i = 0; i < fsize; i++ )
-        {
-            inbuffer[CH(i)] = buffer[CH(length-fsize+i)];
-            inbuffer[CH(i+fsize)] = buffer[CH(i)];
-        }
-        border = 0;
-        finp = inbuffer+CH(fsize);
-        linp = inbuffer+CH(fsize-length);
-    }
-    else
+    inp -= fsize;
+    to = inp + length;
+
+    while( inp < to )
     {
-        for( i = 0; i < fsize; i++ )
-        {
-            inbuffer[CH(i)] = buffer[CH(length-fsize+i)];
-            inbuffer[CH(i+fsize)] = 0;
-            inbuffer[CH(i+2*fsize)] = buffer[CH(i)];
-        }
-        border = fsize;
-        finp = inbuffer + CH( 3*fsize/2 );
-        linp = inbuffer + CH( fsize/2 );
-    }
-
-    length = 2 * length;
-    bufp = buffer+length;
-    outbuf = buffer+CH(border);
+        pos = *cpos;
+        out = 0;
+        filter = filt->c[pos];
+        for( i = 0; i < 2*_fsize; i++ )
+    	    out+= filter[i] * (int)inp[CH(i)];
+        outp[0] = out >> 16;
 
-    for(i = length+border-1; i > length-fsize-1; i--)
-    {
-        outbuf[CH(i)] = Suffix(filterVarBand)( filterp, &linp, &pos );
-    }
-    for(; i > fsize-1 ; i--)
-    {
-        outbuf[CH(i)] = Suffix(filterVarBand)( filterp, &bufp, &pos );
+        inp += CH(filt->incr[pos]);
+        outp += CH(1);
+        *cpos = ( pos + 1 ) % filt->denominator;
     }
-    for(; i > -border-1; i--)
-    {
-        outbuf[CH(i)] = Suffix(filterVarBand)( filterp, &finp, &pos );
-    }
-    return length + 2*border;
+    return outp;
 }
-//---------------------------------------------------------------------------
+
+/*-------------------------------------------------------------------------*/
 #undef CH
 #endif /* Suffix */
-
+