diff alt_audio_convert.c @ 360:c984aa6990f7

Fixes and enhancements from Frank Ranostaj.
author Ryan C. Gordon <icculus@icculus.org>
date Wed, 12 Jun 2002 08:35:23 +0000
parents 778cee61e1be
children f61eadea1f44
line wrap: on
line diff
--- a/alt_audio_convert.c	Tue Jun 11 23:33:27 2002 +0000
+++ b/alt_audio_convert.c	Wed Jun 12 08:35:23 2002 +0000
@@ -1,49 +1,50 @@
 /*
-   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
+    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 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.
+    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
+    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
+    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>
 
-/*provisorisch*/
-#define AUDIO_8 (4)
-#define AUDIO_16WRONG (8)
-#define AUDIO_FORMAT (AUDIO_8 | AUDIO_16WRONG)
-#define AUDIO_SIGN (1)
+/* 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_SIGNED(x)  ((x).format & 0x8000)
+#define IS_SYSENDIAN(x) ((AUDIO_U16SYS ^ (x).format) & 0x1000)
 
 
 /*-------------------------------------------------------------------------*/
-/* this filter (Kaiser-window beta=6.8) gives a decent -80dB attentuation */
+/* this filter (Kaiser-window beta=6.8) gives a decent -80dB attentuation  */
 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, 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 };
 
 /* Mono (1 channel ) */
 #define Suffix(x) x##1
@@ -55,633 +56,745 @@
 #include "filter_templates.h"
 #undef Suffix
 
-/* !!! FIXME: Lose all the "short" vars for "Sint16", etc. */
+/*-------------------------------------------------------------------------*/
+static int ConvertAudio( Sound_AudioCVT *Data,
+    Uint8* buffer, int length, int mode )
+{
+    AdapterC Temp;
+    int i;
+
+    /* Make sure there's a converter */
+    if( Data == NULL ) {
+        SDL_SetError("No converter given");
+        return(-1);
+    }
 
-/*-------------------------------------------------------------------------*/
+    /* Make sure there's data to convert */
+    if( buffer == NULL ) {
+        SDL_SetError("No buffer allocated for conversion");
+        return(-1);
+    }
+
+    /* Set up the conversion and go! */
+    Temp.buffer = buffer;
+    Temp.mode = mode;
+    Temp.filter = &Data->filter;
+
+    for( i = 0; Data->adapter[i] != NULL; i++ )
+	length = (*Data->adapter[i])( Temp, length);
+
+    return length;
+}
+
 int Sound_ConvertAudio( Sound_AudioCVT *Data )
 {
-   AdapterC Temp;
-   int i;
-
-   /* !!! FIXME: Try the looping stuff under certain circumstances? --ryan. */
-   int mode = 0;
+    /* !!! FIXME: Try the looping stuff under certain circumstances? --ryan. */
+    return ConvertAudio( Data, Data->buf, Data->len, 0 );
+}
 
-   /* Make sure there's a converter */
-   if( Data == NULL ) {
-       SDL_SetError("No converter given");
-       return(-1);
-   }
 
-   /* Make sure there's data to convert */
-   if( Data->buf == NULL ) {
-       SDL_SetError("No buffer allocated for conversion");
-       return(-1);
-   }
+/*-------------------------------------------------------------------------*/
+static int expand8BitTo16BitSys( AdapterC Data, int length )
+{
+    int i;
+    Uint8* inp = Data.buffer;
+    Uint16* buffer = (Uint16*)Data.buffer;
+    for( i = length; i--; )
+         buffer[i] = inp[i]<<8;
+    return 2*length;
+}
 
-   /* Set up the conversion and go! */
-   Temp.buffer = (short*)Data->buf;
-   Temp.mode = mode;
-   Temp.filter = &Data->filter;
-
-   Data->len_cvt = Data->len;
-   for( i = 0; Data->adapter[i] != NULL; i++ )
-       Data->len_cvt = (*Data->adapter[i])( Temp, Data->len_cvt);
-
-   return(0);
+static int expand8BitTo16BitWrong( AdapterC Data, int length )
+{
+    int i;
+    Uint8* inp = Data.buffer;
+    Uint16* buffer = (Uint16*)Data.buffer;
+    for( i = length; i--; )
+         buffer[i] = inp[i];
+    return 2*length;
 }
 
 /*-------------------------------------------------------------------------*/
-static int expand8BitTo16Bit( AdapterC Data, int length )
+static int expand16BitToFloat( AdapterC Data, int length )
 {
-   int i;
-   char* inp = (char*)Data.buffer-1;
-   short* buffer = Data.buffer-1;
-   for( i = length; i; i-- )
-        buffer[i] = inp[i]<<8;
-   return length*2;
+    int i;
+    Sint16* inp = (Sint16*)Data.buffer;
+    float* buffer = (float*)Data.buffer;
+    for( i = length>>1; i--; )
+         buffer[i] = inp[i]*(1./32767);
+    return 2*length;
 }
 
 /*-------------------------------------------------------------------------*/
 static int swapBytes( AdapterC Data, int length )
 {
-   int i;
-   unsigned short a,b;
-   short* buffer = Data.buffer;
-   for( i = 0; i < length; i++ )
-   {
-        a = b = buffer[i];
-        a <<= 8;
-        b >>= 8;
-        buffer[i] = a | b;
-   }
-   return length;
+   /*
+    * !!! FIXME !!!
+    *
+    *
+    * Use the faster SDL-Macros to swap
+    * - Frank
+    */
+
+    int i;
+    Uint16 a,b;
+    Uint16* buffer = (Uint16*) Data.buffer;
+    for( i = length>>1; i --; )
+    {
+         a = b = buffer[i];
+         buffer[i] = ( a << 8 ) | ( b >> 8 );
+    }
+    return length;
 }
 
 /*-------------------------------------------------------------------------*/
-static int cut16BitTo8Bit( AdapterC Data, int length )
+static int cutFloatTo16Bit( AdapterC Data, int length )
 {
-   int i;
-   short* inp = Data.buffer-1;
-   char* buffer = (char*)Data.buffer-1;
-   for( i = 0; i < length; i++ )
-        buffer[i] = inp[i]>>8;
-   return length/2;
+    int i;
+    float* inp = (float*) Data.buffer;
+    Sint16* buffer = (Sint16*) Data.buffer;
+    length>>=2;
+    for( i = 0; i < length; i++ )
+    {
+         if( inp[i] > 1. )
+             buffer[i] = 32767;
+         else if( inp[i] < -1. )
+             buffer[i] = -32768;
+         else
+             buffer[i] = 32767 * inp[i];
+    }
+    return 2*length;
+}
+
+/*-------------------------------------------------------------------------*/
+static int cut16BitSysTo8Bit( AdapterC Data, int length )
+{
+    int i;
+    Uint16* inp = (Uint16*) Data.buffer;
+    Uint8* buffer = Data.buffer;
+    length >>= 1;
+    for( i = 0; i < length; i++ )
+         buffer[i] = inp[i]>>8;
+    return length;
+}
+
+static int cut16BitWrongTo8Bit( AdapterC Data, int length )
+{
+    int i;
+    Uint16* inp = (Uint16*) Data.buffer;
+    Uint8* buffer = Data.buffer;
+    length >>= 1;
+    for( i = 0; i < length; i++ )
+         buffer[i] = inp[i] & 0xff;
+    return length;
 }
 
 /*-------------------------------------------------------------------------*/
-static int changeSigned( AdapterC Data, int length )
+static int changeSigned( AdapterC Data, int length, int XOR )
 {
-   int i;
-   short* buffer = Data.buffer;
-   for( i = 0; i < length; i++ )
-        buffer[i] ^= 0x8000;
-   return length;
+    int i;
+    Uint32* buffer = (Uint32*) Data.buffer;
+    for( i = length>>2; i--;  )
+         buffer[i] ^= XOR;
+    for( i = 4*(length>>2); i < length; i++)
+         ((Uint8*)buffer)[i] ^= ((Uint8*)&XOR)[i&3];
+    return length;
+}
+
+static int changeSigned16BitSys( AdapterC Data, int length )
+{
+    return changeSigned( Data, length, 0x80008000 );
+}
+
+static int changeSigned16BitWrong( AdapterC Data, int length )
+{
+    return changeSigned( Data, length, 0x00800080 );
+}
+
+static int changeSigned8Bit( AdapterC Data, int length )
+{
+    return changeSigned( Data, length, 0x80808080 );
 }
 
 /*-------------------------------------------------------------------------*/
-static int convertStereoToMono( AdapterC Data, int length )
+static int convertStereoToMonoS16Bit( AdapterC Data, int length )
 {
-   int i;
-   short* buffer = Data.buffer;
+    int i;
+    Sint16* buffer = (Sint16*) Data.buffer;
+    Sint16* src = (Sint16*) Data.buffer;
+    length >>= 2;
+    for( i = 0; i < length;  i++ )
+         buffer[i] = ((int) *(src++) + *(src++) ) >> 1;
+    return 2*length;
+}
 
-    /*
-     * !!! FIXME: Can we avoid the division in this loop and just keep
-     * !!! FIXME:  a second index variable?  --ryan.
-     */
-   for( i = 0; i < length;  i+=2 )
-        buffer[i/2] = ((int)buffer[i] + buffer[i+1] ) >> 1;
-   return length/2;
+static int convertStereoToMonoU16Bit( AdapterC Data, int length )
+{
+    int i;
+    Uint16* buffer = (Uint16*) Data.buffer;
+    Uint16* src = (Uint16*) Data.buffer;
+    length >>= 2;
+    for( i = 0; i < length;  i++ )
+         buffer[i] = ((int) *(src++) + *(src++) ) >> 1;
+    return 2*length;
+}
+
+static int convertStereoToMonoS8Bit( AdapterC Data, int length )
+{
+    int i;
+    Sint8* buffer = (Sint8*) Data.buffer;
+    Sint8* src = (Sint8*) Data.buffer;
+    length >>= 1;
+    for( i = 0; i < length;  i++ )
+         buffer[i] = ((int) *(src++) + *(src++) ) >> 1;
+    return length;
+}
+
+static int convertStereoToMonoU8Bit( AdapterC Data, int length )
+{
+    int i;
+    Uint8* buffer = (Uint8*) Data.buffer;
+    Uint8* src = (Uint8*) Data.buffer;
+    length >>= 1;
+    for( i = 0; i < length;  i++ )
+         buffer[i] = ((int) *(src++) + *(src++) ) >> 1;
+    return length;
 }
 
 /*-------------------------------------------------------------------------*/
-static int convertMonoToStereo( AdapterC Data, int length )
+static int convertMonoToStereo16Bit( AdapterC Data, int length )
 {
-   int i;
-   short* buffer = Data.buffer-1;
-   length *= 2;
+    int i;
+    Uint16* buffer = (Uint16*) Data.buffer;
+    Uint16* dst = (Uint16*)Data.buffer + length;
+    for( i = length>>1; i--; )
+         *(--dst) = *(--dst) = buffer[i];
+    return 2*length;
+}
 
-    /*
-     * !!! FIXME: Can we avoid the division in this loop and just keep
-     * !!! FIXME:  a second index variable?  --ryan.
-     */
-   for( i = length; i;  i-=2 )
-        buffer[i] = buffer [i-1] = buffer[i/2];
-   return length;
+static int convertMonoToStereo8Bit( AdapterC Data, int length )
+{
+    int i;
+    Uint8* buffer = Data.buffer;
+    Uint8* dst = Data.buffer + 2*length;
+    for( i = length; i--; )
+         *(--dst) = *(--dst) = buffer[i];
+    return 2*length;
 }
 
 /*-------------------------------------------------------------------------*/
 static int minus5dB( AdapterC Data, int length )
 {
-   int i;
-   short* buffer = Data.buffer;
-   for(i = length; i >= 0; i--)
-       buffer[i]= 38084 * buffer[i] >> 16;
-   return length;
+    int i;
+    Sint16* buffer = (Sint16*) Data.buffer;
+    for(i = length>>1; i--; )
+        buffer[i]= 38084 * buffer[i] >> 16;
+    return length;
 }
 
 /*-------------------------------------------------------------------------*/
 static int doubleRateStereo( AdapterC Data, int length )
 {
-   _doubleRate2( Data.buffer, Data.mode, length/2 );
-   return 2*_doubleRate2( Data.buffer+1, Data.mode, length/2 );
+    length >>= 2;
+    _doubleRate2( (Sint16*)Data.buffer, Data.mode, length );
+    return 4*_doubleRate2( (Sint16*)Data.buffer+1, Data.mode, length );
 }
 
 static int doubleRateMono( AdapterC Data, int length )
 {
-   return _doubleRate1( Data.buffer, Data.mode, length );
+    return 2*_doubleRate1( (Sint16*)Data.buffer, Data.mode, length>>1 );
 }
 
 /*-------------------------------------------------------------------------*/
 static int halfRateStereo( AdapterC Data, int length )
 {
-   _halfRate2( Data.buffer, Data.mode, length/2 );
-   return 2*_halfRate2( Data.buffer+1, Data.mode, length/2 );
+    length >>= 2;
+    _halfRate2( (Sint16*)Data.buffer, Data.mode, length );
+    return 4*_halfRate2( (Sint16*)Data.buffer+1, Data.mode, length );
 }
 
 static int halfRateMono( AdapterC Data, int length )
 {
-   return _halfRate2( Data.buffer, Data.mode, length );
+    return 2*_halfRate2( (Sint16*)Data.buffer, Data.mode, length>>1 );
 }
 
 /*-------------------------------------------------------------------------*/
-static int varRateStereo( AdapterC Data, int length )
+static int varRateUpStereo( AdapterC Data, int length )
 {
-   _varRate2( Data.buffer, Data.mode, Data.filter, length/2 );
-   return 2*_varRate2( Data.buffer+1, Data.mode, Data.filter, length/2 );
+    length >>= 2;
+    _varRateUp2( (Sint16*)Data.buffer, Data.mode, Data.filter, length );
+    return 4 * _varRateUp2( (Sint16*)Data.buffer+1,
+                            Data.mode, Data.filter, length );
 }
 
-static int varRateMono( AdapterC Data, int length )
+static int varRateUpMono( AdapterC Data, int length )
+{
+    return 2 * _varRateUp1( (Sint16*)Data.buffer,
+                            Data.mode, Data.filter, length>>1 );
+}
+
+static int varRateDownStereo( AdapterC Data, int length )
 {
-   return _varRate1( Data.buffer, Data.mode, Data.filter, length );
+    length >>= 2;
+    _varRateDown2( (Sint16*)Data.buffer, Data.mode, Data.filter, length );
+    return 2 * _varRateDown2( (Sint16*)Data.buffer+1,
+                              Data.mode, Data.filter, length );
+}
+
+static int varRateDownMono( AdapterC Data, int length )
+{
+    return _varRateDown1( (Sint16*)Data.buffer,
+                          Data.mode, Data.filter, length>>1 );
 }
 
 /*-------------------------------------------------------------------------*/
 typedef struct{
-   short denominator;
-   short numerator;
+    Sint16 denominator;
+    Sint16 numerator;
 } Fraction;
 
-/*-------------------------------------------------------------------------*/
 static Fraction findFraction( float Value )
 {
 /* gives a maximal error of 3% and typical less than 0.2% */
-   const char frac[96]={
-     1, 2,                                                  -1, /*  /1 */
-     1,    3,                                               -1, /*  /2 */
-        2,    4, 5,                                         -1, /*  /3 */
-           3,    5,    7,                                   -1, /*  /4 */
-           3, 4,    6, 7, 8, 9,                             -1, /*  /5 */
-                 5,    7,           11,                     -1, /*  /6 */
-              4, 5, 6,    8, 9, 10, 11, 12, 13,             -1, /*  /7 */
-                 5,    7,    9,     11,     13,     15,     -1, /*  /8 */
-                 5,    7, 8,    10, 11,     13, 14,     16, -1, /*  /9 */
-                       7,    9,     11,     13,             -1, /* /10 */
-                    6, 7, 8, 9, 10,     12, 13, 14, 15, 16, -1, /* /11 */
-                       7,           11,     13,             -1, /* /12 */
-                       7, 8, 9, 10, 11, 12,     14, 15, 16, -1, /* /13 */
-                             9,     11,     13,     15,     -1, /* /14 */
-                          8,        11,     13, 14,     16, -1, /* /15 */
-                             9,     11,     13,     15       }; /* /16 */
+    const Uint8 frac[96]={
+      1, 2,                                                  -1, /*  /1 */
+      1,    3,                                               -1, /*  /2 */
+         2,    4, 5,                                         -1, /*  /3 */
+            3,    5,    7,                                   -1, /*  /4 */
+            3, 4,    6, 7, 8, 9,                             -1, /*  /5 */
+                  5,    7,           11,                     -1, /*  /6 */
+               4, 5, 6,    8, 9, 10, 11, 12, 13,             -1, /*  /7 */
+                  5,    7,    9,     11,     13,     15,     -1, /*  /8 */
+                  5,    7, 8,    10, 11,     13, 14,     16, -1, /*  /9 */
+                        7,    9,     11,     13,             -1, /* /10 */
+                     6, 7, 8, 9, 10,     12, 13, 14, 15, 16, -1, /* /11 */
+                        7,           11,     13,             -1, /* /12 */
+                        7, 8, 9, 10, 11, 12,     14, 15, 16, -1, /* /13 */
+                              9,     11,     13,     15,     -1, /* /14 */
+                           8,        11,     13, 14,     16, -1, /* /15 */
+                              9,     11,     13,     15       }; /* /16 */
 
 
-   Fraction Result = {0,0};
-   int n,num,den=2;
+    Fraction Result = {0,0};
+    int n,num,den=1;
 
-   float RelErr, BestErr = 0;
-   if( Value < 31/64. || Value > 64/31. ) return Result;
+    float RelErr, BestErr = 0;
+    if( Value < 31/64. || Value > 64/31. ) return Result;
 
-   for( n = 0; n < sizeof(frac); num=frac[++n] )
-   {
-        if( num < 0 ) den++;
-        RelErr = Value * num / den;
-        RelErr = ( RelErr < (1/RelErr) ? RelErr : 1/RelErr );
-        if( RelErr > BestErr )
-        {
-            BestErr = RelErr;
-            Result.denominator = den;
-            Result.numerator = num;
-        }
-   }
-   return Result;
+    for( n = 0; n < sizeof(frac); num=frac[++n] )
+    {
+         if( num < 0 ) den++;
+         RelErr = Value * num / den;
+         RelErr = min( RelErr, 1/RelErr );
+         if( RelErr > BestErr )
+         {
+             BestErr = RelErr;
+             Result.denominator = den;
+             Result.numerator = num;
+         }
+    }
+    return Result;
 }
 
-
+/*-------------------------------------------------------------------------*/
 static float sinc( float x )
 {
-   if( x > -1e-24 && x < 1e-24 ) return 1.;
-   else return sin(x)/x;
+    if( x > -1e-24 && x < 1e-24 ) return 1.;
+    else return sin(x)/x;
 }
 
-static void calculateVarFilter( short* dst, float Ratio, float phase,
-                                float scale )
+static void calculateVarFilter( Sint16* dst, float Ratio, float phase, float scale )
 {
-   const unsigned short KaiserWindow7[]= {
-       22930, 16292, 14648, 14288, 14470, 14945, 15608, 16404,
-       17304, 18289, 19347, 20467, 21644, 22872, 24145, 25460,
-       26812, 28198, 29612, 31052, 32513, 33991, 35482, 36983,
-       38487, 39993, 41494, 42986, 44466, 45928, 47368, 48782,
-       50165, 51513, 52821, 54086, 55302, 56466, 57575, 58624,
-       59610, 60529, 61379, 62156, 62858, 63483, 64027, 64490,
-       64870, 65165, 65375, 65498, 65535, 65484, 65347, 65124,
-       64815, 64422, 63946, 63389, 62753, 62039, 61251, 60391 };
-   int i;
-   float w;
-   const float fg = -.018 + .5 / Ratio;
-   const float omega = 2 * M_PI * fg;
-   phase -= 63;
-   for( i = 0; i < 64; i++)
-   {
-       w = scale * ( KaiserWindow7[i] * ( i + 1 ));
-       dst[i] = w * sinc( omega * (i+phase) );
-       dst[127-i] = w * sinc( omega * (127-i+phase) );
-   }
+    const Uint16 KaiserWindow7[]= {
+        22930, 16292, 14648, 14288, 14470, 14945, 15608, 16404,
+        17304, 18289, 19347, 20467, 21644, 22872, 24145, 25460,
+        26812, 28198, 29612, 31052, 32513, 33991, 35482, 36983,
+        38487, 39993, 41494, 42986, 44466, 45928, 47368, 48782,
+        50165, 51513, 52821, 54086, 55302, 56466, 57575, 58624,
+        59610, 60529, 61379, 62156, 62858, 63483, 64027, 64490,
+        64870, 65165, 65375, 65498, 65535, 65484, 65347, 65124,
+        64815, 64422, 63946, 63389, 62753, 62039, 61251, 60391 };
+    int i;
+    float w;
+    const float fg = -.018 + .5 * Ratio;
+    const float omega = 2 * M_PI * fg;
+    phase -= 63;
+    for( i = 0; i < 64; i++)
+    {
+        w = scale * ( KaiserWindow7[i] * ( i + 1 ));
+        dst[i] = w * sinc( omega * (i+phase) );
+        dst[127-i] = w * sinc( omega * (127-i+phase) );
+    }
 }
 
 typedef struct{
-   float scale;
-   int incr;
+    float scale;
+    int incr;
 } VarFilterMode;
 
-static const VarFilterMode Up = { 0.0211952, 0 };
-static const VarFilterMode Down = { 0.0364733, 2 };
-
+const VarFilterMode Up = { 0.0211952, -1 };
+const VarFilterMode Down = { 0.0364733, 1 };
 
 static void setupVarFilter( VarFilter* filter,
-                            float Ratio, VarFilterMode Direction )
+                     float Ratio, VarFilterMode Direction )
 {
-   int i,n,d;
-   Fraction IRatio;
-   float phase;
-   IRatio = findFraction( Ratio );
+    int i,n,d;
+    Fraction IRatio;
+    float phase;
+    IRatio = findFraction( Ratio );
+    Ratio = min( Ratio, 1/Ratio );
+
+    n = IRatio.numerator;
+    d = IRatio.denominator;
+    filter->pos_mod = d;
 
-   if ( (1/Ratio) < Ratio )
-       Ratio = 1/Ratio;
+    for( i = 0; i < d; i++ )
+    {
+        if( phase >= n )
+        {
+            phase -= d;
+            filter->incr[i] = Direction.incr;
+        }
+        else
+            filter->incr[i] = 1+Direction.incr;
 
-   n = IRatio.numerator;
-   d = IRatio.denominator;
-   filter->pos_mod = n;
+        calculateVarFilter( filter->c[i], Ratio, phase/(float)n,
+                            Direction.scale );
+        phase += d;
+    }
+}
+
+/*-------------------------------------------------------------------------*/
+static void createRateConverter( Sound_AudioCVT *Data, int* fip,
+                         int SrcRate, int DestRate, int Channel )
+{
+    int filter_index = *fip;
+
+    int VarPos = 0;
+    int Mono = 2 - Channel;
+    float Ratio = DestRate;
+    *fip = -1;
+
 
-   for( i = 0; i < d; i++ )
-   {
-       if( phase >= n )
-       {
-           phase -= d;
-           filter->incr[i] = Direction.incr;
-       }
-       else
-           filter->incr[i] = 1;
+    if( SrcRate < 1 || SrcRate > 1<<18 ||
+        DestRate < 1 || DestRate > 1<<18 ) return;
+    Ratio /= SrcRate;
+
+    if( Ratio > 1.)
+        VarPos = filter_index++;
+    else
+        Data->adapter[filter_index++] = minus5dB;
+
+    while( Ratio > 64./31.)
+    {
+        Data->adapter[filter_index++] =
+            Mono ? doubleRateMono : doubleRateStereo;
+        Ratio /= 2.;
+        Data->len_mult *= 2;
+        Data->add *= 2;
+        Data->add += _fsize;
+    }
 
-       calculateVarFilter( filter->c[i], Ratio, phase/(float)n,
-                           Direction.scale );
-       phase += d;
-   }
+    while( Ratio < 31./64. )
+    {
+        Data->adapter[filter_index++] =
+            Mono ? halfRateMono : halfRateStereo;
+        Ratio *= 2;
+    }
+
+    if( Ratio > 1. )
+    {
+        setupVarFilter( &Data->filter, Ratio, Up );
+        Data->adapter[VarPos] =
+            Mono ? varRateUpMono : varRateUpStereo;
+        Data->len_mult *= 2;
+        Data->add *= 2;
+        Data->add += _fsize;
+    }
+    else
+    {
+        setupVarFilter( &Data->filter, Ratio, Down );
+        Data->adapter[filter_index++] =
+            Mono ? varRateDownMono : varRateDownStereo;
+    }
+    *fip = filter_index;
 }
 
-static int createRateConverter( Sound_AudioCVT *Data, int filter_index,
-                                int SrcRate, int DestRate, int Channel )
+/*-------------------------------------------------------------------------*/
+static void createFormatConverter16Bit(Sound_AudioCVT *Data, int* fip,
+    SDL_AudioSpec src, SDL_AudioSpec dst )
 {
-   int VarPos = 0;
-   int Mono = 2 - Channel;
-   float Ratio = DestRate;
-   if( SrcRate < 1 || SrcRate > 1<<18 ||
-       DestRate < 1 || DestRate > 1<<18 ) return -1;
-   if( SrcRate == DestRate ) return filter_index;
-   Ratio /= SrcRate;
+    int filter_index = *fip;
+
+    if( src.channels == 2 && dst.channels == 1 )
+    {
+        Data->add /= 2;
+        Data->len_mult /= 2;
 
-   if( Ratio > 1.0)
-       VarPos = filter_index++;
-   else
-   {
-       fprintf (stderr, "Filter: minus5dB\n");
-       Data->adapter[filter_index++] = minus5dB;
-   }
+        if( !IS_SYSENDIAN(src) )
+            Data->adapter[filter_index++] = swapBytes;
+
+        if( IS_SIGNED(src) )
+            Data->adapter[filter_index++] = convertStereoToMonoS16Bit;
+        else
+            Data->adapter[filter_index++] = convertStereoToMonoU16Bit;
 
-   while( Ratio > 64.0/31.0)
-   {
-       fprintf (stderr, "Filter: %s\n",
-                Mono ? "doubleRateMono" : "doubleRateStereo");
-       Data->adapter[filter_index++] =
-           Mono ? doubleRateMono : doubleRateStereo;
-       Ratio /= 2;
-       Data->len_mult *= 2;
-       Data->add *= 2;
-       Data->add += _fsize;
-   }
-
-   while( Ratio < 31.0/64.0 )
-   {
-       fprintf (stderr, "Filter: %s\n",
-                Mono ? "halfRateMono" : "halfRateStereo");
-       Data->adapter[filter_index++] =
-           Mono ? halfRateMono : halfRateStereo;
-       Ratio *= 2;
-   }
+        if( !IS_SYSENDIAN(dst) )
+            Data->adapter[filter_index++] = swapBytes;
+    }
+    else if( IS_SYSENDIAN(src) != IS_SYSENDIAN(dst) )
+        Data->adapter[filter_index++] = swapBytes;
 
-   if( Ratio > 1.0 )
-   {
-       fprintf (stderr, "Filter: %s\n",
-                Mono ? "varRateMono" : "varRateStereo");
-       setupVarFilter( &Data->filter, Ratio, Up );
-       Data->adapter[VarPos] =
-           Mono ? varRateMono : varRateStereo;
-       Data->len_mult *= 2;
-       Data->add *= 2;
-       Data->add += _fsize;
-   }
-   else
-   {
-       fprintf (stderr, "Filter: %s\n",
-                Mono ? "varRateMono" : "varRateStereo");
-       setupVarFilter( &Data->filter, Ratio, Down );
-       Data->adapter[filter_index++] =
-           Mono ? varRateMono : varRateStereo;
-   }
-   return filter_index;
+    if( IS_SIGNED(src) != IS_SIGNED(dst) )
+    {
+        if( IS_SYSENDIAN(dst) )
+            Data->adapter[filter_index++] = changeSigned16BitSys;
+        else
+            Data->adapter[filter_index++] = changeSigned16BitSys;
+    }
+
+    if( src.channels == 1 && dst.channels == 2 )
+    {
+        Data->add *= 2;
+        Data->len_mult *= 2;
+        Data->adapter[filter_index++] = convertMonoToStereo16Bit;
+    }
+
+    *fip = filter_index;
 }
 
-static int BuildAudioCVT(Sound_AudioCVT *Data,
-   Uint16 src_format, Uint8 src_channels, int src_rate,
-   Uint16 dst_format, Uint8 dst_channels, int dst_rate)
+/*-------------------------------------------------------------------------*/
+static void createFormatConverter8Bit(Sound_AudioCVT *Data, int *fip,
+    SDL_AudioSpec src, SDL_AudioSpec dst )
 {
-   int filter_index = 0;
+    int filter_index = *fip;
+    if( IS_16BIT(src) )
+    {
+        Data->add /= 2;
+        Data->len_mult /= 2;
 
-   if( Data == NULL ) return -1;
-   Data->len_mult = 1.0;
-   Data->add = 0;
+        if( IS_SYSENDIAN(src) )
+            Data->adapter[filter_index++] = cut16BitSysTo8Bit;
+        else
+            Data->adapter[filter_index++] = cut16BitWrongTo8Bit;
+    }
 
-   /* Check channels */
-   if( src_channels < 1 || src_channels > 2 ||
-       dst_channels < 1 || dst_channels > 2 ) goto error_exit;
+    if( src.channels == 2 && dst.channels == 1 )
+    {
+        Data->add /= 2;
+        Data->len_mult /= 2;
+
+        if( IS_SIGNED(src) )
+            Data->adapter[filter_index++] = convertStereoToMonoS8Bit;
+        else
+            Data->adapter[filter_index++] = convertStereoToMonoU8Bit;
+    }
 
-   /* First filter:  Size/Endian conversion */
-   switch( src_format & AUDIO_FORMAT)
-   {
-   case AUDIO_8:
-       fprintf (stderr, "Filter: expand8BitTo16Bit\n");
-       Data->adapter[filter_index++] = expand8BitTo16Bit;
-       Data->len_mult *= 2;
-       break;
-   case AUDIO_16WRONG:
-       fprintf (stderr, "Filter: swapBytes\n");
-       Data->adapter[filter_index++] = swapBytes;
-       break;
-   }
+    if( IS_SIGNED(src) != IS_SIGNED(dst) )
+        Data->adapter[filter_index++] = changeSigned8Bit;
+
+    if( src.channels == 1 && dst.channels == 2  )
+    {
+        Data->add *= 2;
+        Data->len_mult *= 2;
+        Data->adapter[filter_index++] = convertMonoToStereo8Bit;
+    }
 
-   /* Second adapter: Sign conversion -- unsigned/signed */
-   if( src_format & AUDIO_SIGN )
-   {
-       fprintf (stderr, "Filter: changeSigned\n");
-       Data->adapter[filter_index++] = changeSigned;
-   }
+    if( !IS_8BIT(dst) )
+    {
+        Data->add *= 2;
+        Data->len_mult *= 2;
+        if( IS_SYSENDIAN(dst) )
+            Data->adapter[filter_index++] = expand8BitTo16BitSys;
+        else
+            Data->adapter[filter_index++] = expand8BitTo16BitWrong;
+    }
 
-   /* Third adapter:  Stereo->Mono conversion */
-   if( src_channels == 2 && dst_channels == 1 )
-   {
-       fprintf (stderr, "convertStereoToMono\n");
-       Data->adapter[filter_index++] = convertStereoToMono;
-   }
+    *fip = filter_index;
+}
+
+/*-------------------------------------------------------------------------*/
+static void createFormatConverter(Sound_AudioCVT *Data, int *fip,
+    SDL_AudioSpec src, SDL_AudioSpec dst )
+{
+    int filter_index = *fip;
 
-   /* Do rate conversion */
-   if( src_channels == 2 && dst_channels == 2 )
-       filter_index = createRateConverter( Data, filter_index,
-                                           src_rate, dst_rate, 2 );
-   else
-       filter_index = createRateConverter( Data, filter_index,
-                                           src_rate, dst_rate, 1 );
+    if( IS_FLOAT(src) )
+    {
+        Data->adapter[filter_index++] = cutFloatTo16Bit;
+        Data->len_mult /= 2;
+        Data->add /= 2;
+    }
+
+    if( IS_8BIT(src) || IS_8BIT(dst) )
+         createFormatConverter8Bit( Data, &filter_index, src, dst);
+    else
+         createFormatConverter16Bit( Data, &filter_index, src, dst);
 
-   if( filter_index < 0 ) goto error_exit; /* propagate error */
+    if( IS_FLOAT(dst) )
+    {
+        Data->adapter[filter_index++] = expand16BitToFloat;
+        Data->len_mult *= 2;
+        Data->add *= 2;
+    }
+
+    *fip = filter_index;
+}
+
 
-   /* adapter: Mono->Stereo conversion */
-   if( src_channels == 1 && dst_channels == 2 ){
-       fprintf (stderr, "Filter: convertMonoToStereo\n");
-       Data->adapter[filter_index++] = convertMonoToStereo;
-       Data->add *= 2;
-       Data->len_mult *= 2;
-   }
+/*-------------------------------------------------------------------------*/
+DECLSPEC int BuildAudioCVT(Sound_AudioCVT *Data,
+    SDL_AudioSpec src, SDL_AudioSpec dst )
+{
+    SDL_AudioSpec intrm;
+    int filter_index = 0;
+
+    if( Data == NULL ) return -1;
+    Data->len_mult = 1.;
+    Data->add = 0;
 
-   /* adapter: final Sign conversion -- unsigned/signed */
-   if( dst_format & AUDIO_SIGN )
-   {
-       fprintf (stderr, "Filter: changeSigned\n");
-       Data->adapter[filter_index++] = changeSigned;
-   }
+    /* Check channels */
+    if( src.channels < 1 || src.channels > 2 ||
+        dst.channels < 1 || dst.channels > 2 ) goto error_exit;
+
+    /* If no frequency conversion is needed, go straight to dst format */
+    if( src.freq == dst.freq )
+    {
+        createFormatConverter( Data, &filter_index, src, dst );
+        goto sucess_exit;
+    }
+
+    /* Convert to signed 16Bit System-Endian */
+    intrm.format = AUDIO_S16SYS;
+    intrm.channels = min( src.channels, dst.channels );
+    createFormatConverter( Data, &filter_index, src, intrm );
 
-   /* final adapter: Size/Endian conversion */
-   switch( dst_format & AUDIO_FORMAT)
-   {
-   case AUDIO_8:
-       fprintf (stderr, "Filter: cut16BitTo8Bit\n");
-       Data->adapter[filter_index++] = cut16BitTo8Bit;
-       break;
-   case AUDIO_16WRONG:
-       fprintf (stderr, "Filter: swapBytes\n");
-       Data->adapter[filter_index++] = swapBytes;
-       break;
-   }
-   /* Set up the filter information */
-   Data->adapter[filter_index] = NULL;
-   Data->needed = (filter_index > 0);
-   return 0;
+    /* Do rate conversion */
+    if( src.channels == 2 && dst.channels == 2 )
+        createRateConverter( Data, &filter_index, src.freq, dst.freq, 2 );
+    else
+        createRateConverter( Data, &filter_index, src.freq, dst.freq, 1 );
+    /* propagate error */
+    if( filter_index < 0 ) goto error_exit;
+
+    /* Convert to final format */
+    createFormatConverter( Data, &filter_index, intrm, dst );
+
+    /* Set up the filter information */
+sucess_exit:
+/* !!! FIXME: Is it okay to assign NULL to a function pointer?
+              Borland says no. -frank */
+    Data->adapter[filter_index] = NULL;
+    return 0;
 
 error_exit:
-   Data->adapter[0] = NULL;
-   return -1;
+/* !!! FIXME: Is it okay to assign NULL to a function pointer?
+              Borland says no. -frank    */
+    Data->adapter[0] = NULL;
+    return -1;
 }
 
-/*
- * Frank's audio converter has its own ideas about how to represent audio
- * format, so at least for a transition period we use this to glue his code
- * to our's.
- *
- * + The expand8BitTo16Bit filter will only convert to system byte order.
- * + The cut16BitTo8Bit filter will only convert from system byte order.
- * + The changeSigned filter only works on 16-bit samples, system byte order.
- */
-
+/*-------------------------------------------------------------------------*/
 static char *fmt_to_str(Uint16 fmt)
 {
     switch (fmt)
     {
-        case AUDIO_U8:     return "    U8"; break;
-        case AUDIO_S8:     return "    S8"; break;
-        case AUDIO_U16MSB: return "U16MSB"; break;
-        case AUDIO_S16MSB: return "S16MSB"; break;
-        case AUDIO_U16LSB: return "U16LSB"; break;
-        case AUDIO_S16LSB: return "S16LSB"; break;
+        case AUDIO_U8:     return "    U8";
+        case AUDIO_S8:     return "    S8";
+        case AUDIO_U16MSB: return "U16MSB";
+        case AUDIO_S16MSB: return "S16MSB";
+        case AUDIO_U16LSB: return "U16LSB";
+        case AUDIO_S16LSB: return "S16LSB";
     }
     return "??????";
 }
 
-#define IS_8BIT(x)    ((x) & 0x0008)
-#define IS_16BIT(x)   ((x) & 0x0010)
-#define ENDIAN(x)     ((x) & 0x1000)
-#define SIGNED(x)     ((x) & 0x8000)
+#define AdapterDesc(x) { x, #x }
+
+static void show_AudioCVT( Sound_AudioCVT *Data )
+{
+    int i,j;
+    const struct{ int (*adapter) ( AdapterC, int); Sint8 *name; }
+    AdapterDescription[] = {
+        AdapterDesc(expand8BitTo16BitSys),
+        AdapterDesc(expand8BitTo16BitWrong),
+        AdapterDesc(expand16BitToFloat),
+        AdapterDesc(swapBytes),
+        AdapterDesc(cut16BitSysTo8Bit),
+        AdapterDesc(cut16BitWrongTo8Bit),
+        AdapterDesc(cutFloatTo16Bit),
+        AdapterDesc(changeSigned16BitSys),
+        AdapterDesc(changeSigned16BitWrong),
+        AdapterDesc(changeSigned8Bit),
+        AdapterDesc(convertStereoToMonoS16Bit),
+        AdapterDesc(convertStereoToMonoU16Bit),
+        AdapterDesc(convertStereoToMonoS8Bit),
+        AdapterDesc(convertStereoToMonoU8Bit),
+        AdapterDesc(convertMonoToStereo16Bit),
+        AdapterDesc(convertMonoToStereo8Bit),
+        AdapterDesc(minus5dB),
+        AdapterDesc(doubleRateStereo),
+        AdapterDesc(doubleRateMono),
+        AdapterDesc(halfRateStereo),
+        AdapterDesc(halfRateMono),
+        AdapterDesc(varRateUpStereo),
+        AdapterDesc(varRateUpMono),
+        AdapterDesc(varRateDownStereo),
+        AdapterDesc(varRateDownMono),
+        { NULL,    "----------NULL-----------" }
+    };
+    const int AdapterDescMax = sizeof(AdapterDescription)
+                             / sizeof(*AdapterDescription);
+
+    fprintf( stderr, "\nAdapter List:    \n" );
+    for( i = 0; i < 32; i++ )
+    {
+        for( j = 0; j < AdapterDescMax; j++ )
+        {
+            if( Data->adapter[i] == AdapterDescription[j].adapter )
+            {
+                fprintf( stderr, "    %s\n", AdapterDescription[j].name );
+                if( Data->adapter[i] == NULL ) return;
+                goto cont;
+            }
+        }
+        fprintf( stderr, "    Error: unknown adapter\n" );
+        cont:
+    }
+    fprintf( stderr, "    Error: NULL adapter missing\n" );
+}
+
 
 int Sound_BuildAudioCVT(Sound_AudioCVT *Data,
-   Uint16 src_in_format, Uint8 src_channels, int src_rate,
-   Uint16 dst_in_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)
 {
-    Uint16 src_format = 0;
-    Uint16 dst_format = 0;
+    SDL_AudioSpec src, dst;
+    int ret;
 
     fprintf (stderr,
+             "Sound_BuildAudioCVT() :\n"
+             "-----------------------\n"
              "format:   %s -> %s\n"
              "channels: %6d -> %6d\n"
              "rate:     %6d -> %6d\n",
-             fmt_to_str (src_in_format), fmt_to_str (dst_in_format),
+             fmt_to_str (src_format), fmt_to_str (dst_format),
              src_channels, dst_channels,
              src_rate, dst_rate);
 
-    if ( IS_8BIT(src_in_format) && IS_16BIT(dst_in_format) )
-    {
-        src_format |= AUDIO_8;
-
-            /*
-             * Signedness and byte-order changes must wait until the data
-             * has been converted to 16-bit samples.
-             */
-        if ( SIGNED(src_in_format) != SIGNED(dst_in_format) )
-        {
-            dst_format |= AUDIO_SIGN;
-        } /* if */
-
-        if ( ENDIAN(dst_in_format) != ENDIAN(AUDIO_U16SYS) )
-        {
-            dst_format |= AUDIO_16WRONG;
-        } /* if */
-    } /* if */
-    else if ( IS_16BIT(src_in_format) && IS_8BIT(dst_in_format) )
-    {
-        dst_format |= AUDIO_8;
+    src.format = src_format;
+    src.channels = src_channels;
+    src.freq = src_rate;
 
-            /*
-             * Byte-order and signedness changes must be made before the data
-             * has been converted to 8-bit samples.
-             */
-        if ( ENDIAN(src_in_format) != ENDIAN(AUDIO_U16SYS) )
-        {
-            src_format |= AUDIO_16WRONG;
-        } /* if */
-
-        if ( SIGNED(src_in_format) != SIGNED(dst_in_format) )
-        {
-            src_format |= AUDIO_SIGN;
-        } /* if */
-    } /* else if */
-    else if ( IS_16BIT(src_in_format) && IS_16BIT(dst_in_format) )
-    {
-        if ( ENDIAN(src_in_format) != ENDIAN(dst_in_format) )
-        {
-            if ( ENDIAN(src_in_format) == ENDIAN(AUDIO_U16SYS) )
-            {
-                dst_format |= AUDIO_16WRONG;
-
-                    /*
-                     * The data is already is system byte order, so any
-                     * signedness change has to be made before changing byte
-                     * order.
-                     */
-                if ( SIGNED(src_in_format) != SIGNED(dst_in_format) )
-                {
-                    src_format |= AUDIO_SIGN;
-                } /* if */
-            } /* if */
-            else
-            {
-                src_format |= AUDIO_16WRONG;
+    dst.format = dst_format;
+    dst.channels = dst_channels;
+    dst.freq = dst_rate;
 
-                    /*
-                     * The data is not in system byte order, so any signedness
-                     * change has to be made after changing byte order.
-                     */
-                if ( SIGNED(src_in_format) != SIGNED(dst_in_format) )
-                {
-                    dst_format |= AUDIO_SIGN;
-                } /* if */
-            } /* else */
-        } /* if */
-        else if ( ENDIAN(src_in_format) != SIGNED(AUDIO_U16SYS) )
-        {
-            if ( SIGNED(src_in_format) != SIGNED(dst_in_format) )
-            {
-                    /*
-                     * !!! FIXME !!!
-                     *
-                     * The changeSigned filter only works on system byte
-                     * order. In this case, both source and destination is
-                     * in opposite byte order, but the sign has to changed
-                     * so we need to convert to system byte order, change
-                     * sign, and then convert back to the original byte
-                     * order again. This is not an optimal solution.
-                     */
-                src_format |= ( AUDIO_16WRONG | AUDIO_SIGN );
-                dst_format |= AUDIO_16WRONG;
-            } /* if */
+    ret = BuildAudioCVT( Data, src, dst );
 
-            if ( src_rate != dst_rate )
-            {
-                    /*
-                     * !!! FIXME !!!
-                     *
-                     * The audio conversion filter probably only works if the
-                     * data is in system byte order. So we need to convert to
-                     * system byte order, and then back to original byte
-                     * order. This is not an optimal solution.
-                     */
-                src_format |= AUDIO_16WRONG;
-                dst_format |= AUDIO_16WRONG;
-            }
-        } /* else if */
-        else if ( SIGNED(src_in_format) != SIGNED(dst_in_format) )
-        {
-            src_format |= AUDIO_SIGN;
-        } /* else if */
-    } /* else if */
-    else if ( IS_8BIT(src_in_format) && IS_8BIT(dst_in_format) )
-    {
-            /*
-             * !!! FIXME !!!
-             *
-             * The changeSigned filter only works on 16-bit samples, so if
-             * the signedness differs we have to convert from 8 to 16 bits,
-             * change the sign and then convert back to 8 bits again. This
-             * is not an optimal solution.
-             */
-        if ( SIGNED(src_in_format) != SIGNED(dst_in_format) )
-        {
-            src_format |= ( AUDIO_8 | AUDIO_SIGN );
-            dst_format |= AUDIO_8;
-        } /* if */
+    show_AudioCVT( Data );
+    fprintf (stderr, "\n"
+                     "return value: %d \n", ret );
 
-            /*
-             * !!! FIXME !!!
-             *
-             * The convertMonoToStereo and convertStereoToMono filters only
-             * work with 16-bit samples. So if those are to be applied, we
-             * need to convert to 16-bit samples, and then back again.
-             */
-        if ( src_channels != dst_channels )
-        {
-            src_format |= AUDIO_8;
-            dst_format |= AUDIO_8;
-        } /* if */
-
-            /*
-             * !!! FIXME !!!
-             *
-             * The rate conversion filters almost certainly only work with
-             * 16-bit samples. Yadda, yadda, yadda.
-             */
-        if ( src_rate != dst_rate )
-        {
-            src_format |= AUDIO_8;
-            dst_format |= AUDIO_8;
-        } /* if */
-    } /* else if */
-
-    return BuildAudioCVT(Data, src_format, src_channels, src_rate,
-                         dst_format, dst_channels, dst_rate);
+    return ret;
 }
-
-/*-------------------------------------------------------------------------*/
-