src/audio/SDL_audiocvt.c
branchgsoc2008_audio_resampling
changeset 2656 dd74182b3c3c
parent 2655 b8e736c8a5a8
child 2657 29306e52dab8
     1.1 --- a/src/audio/SDL_audiocvt.c	Wed Jun 18 04:51:10 2008 +0000
     1.2 +++ b/src/audio/SDL_audiocvt.c	Wed Jun 18 18:55:50 2008 +0000
     1.3 @@ -27,6 +27,8 @@
     1.4  #include "SDL_audio.h"
     1.5  #include "SDL_audio_c.h"
     1.6  
     1.7 +#define DEBUG_CONVERT
     1.8 +
     1.9  /* Effectively mix right and left channels into a single channel */
    1.10  static void SDLCALL
    1.11  SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    1.12 @@ -1237,7 +1239,7 @@
    1.13      int i, j;
    1.14  
    1.15  #ifdef DEBUG_CONVERT
    1.16 -    fprintf(stderr, "Converting audio rate via proper resampling (mono)\n");
    1.17 +    printf("Converting audio rate via proper resampling (mono)\n");
    1.18  #endif
    1.19  
    1.20  #define zerostuff_mono(type) { \
    1.21 @@ -1256,7 +1258,7 @@
    1.22  #define discard_mono(type) { \
    1.23          const type *src = (const type *) (cvt->buf); \
    1.24          type *dst = (type *) (cvt->buf); \
    1.25 -        for (i = 0; i < cvt->len_cvt / sizeof (type); ++i) { \
    1.26 +        for (i = 0; i < cvt->len_cvt / cvt->len_div / sizeof (type); ++i) { \
    1.27              dst[0] = src[0]; \
    1.28              src += cvt->len_div; \
    1.29              ++dst; \
    1.30 @@ -1264,6 +1266,9 @@
    1.31      }
    1.32  
    1.33  	// Step 1: Zero stuff the conversion buffer
    1.34 +#ifdef DEBUG_CONVERT
    1.35 +	printf("Zero-stuffing by a factor of %u\n", cvt->len_mult);
    1.36 +#endif
    1.37      switch (SDL_AUDIO_BITSIZE(format)) {
    1.38      case 8:
    1.39          zerostuff_mono(Uint8);
    1.40 @@ -1281,6 +1286,9 @@
    1.41  	// Step 2: Use either a windowed sinc FIR filter or IIR lowpass filter to remove all alias frequencies
    1.42  	
    1.43  	// Step 3: Discard unnecessary samples
    1.44 +#ifdef DEBUG_CONVERT
    1.45 +	printf("Discarding samples by a factor of %u\n", cvt->len_div);
    1.46 +#endif
    1.47      switch (SDL_AUDIO_BITSIZE(format)) {
    1.48      case 8:
    1.49          discard_mono(Uint8);
    1.50 @@ -1418,13 +1426,53 @@
    1.51  	coeff[4] = -2.0f * cosw0 * scale;
    1.52  	coeff[5] = (1.0f - alpha) * scale;
    1.53  	
    1.54 -	/* Convert coefficients to fixed point, using the range (-2.0, 2.0) */
    1.55 +	/* Copy the coefficients to the struct. If necessary, convert coefficients to fixed point, using the range (-2.0, 2.0) */
    1.56 +	if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
    1.57 +		float *cvt_coeff = (float *)cvt->coeff;
    1.58 +		int i;
    1.59 +		for(i = 0; i < 6; ++i) {
    1.60 +			cvt_coeff[i] = coeff[i];
    1.61 +		}
    1.62 +	} else {
    1.63 +	}
    1.64  	
    1.65  	/* Initialize the state buffer to all zeroes, and set initial position */
    1.66  	memset(cvt->state_buf, 0, 4 * SDL_AUDIO_BITSIZE(format) / 4);
    1.67  	cvt->state_pos = 0;
    1.68  }
    1.69  
    1.70 +/* Apply the lowpass IIR filter to the given SDL_AudioCVT struct */
    1.71 +int SDL_FilterIIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
    1.72 +	int i, n;
    1.73 +	
    1.74 +	n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4);
    1.75 +	
    1.76 +	if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
    1.77 +		float *coeff = (float *)cvt->coeff;
    1.78 +		float *state = (float *)cvt->state_buf;
    1.79 +		float *buf = (float *)cvt->buf;
    1.80 +		float temp;
    1.81 +
    1.82 +		
    1.83 +		for(i = 0; i < n; ++i) {
    1.84 +			/* y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] - a1 * y[n-1] - a[2] * y[n-2] */
    1.85 +			temp = buf[n];
    1.86 +			if( cvt->state_pos ) {
    1.87 +				buf[n] = coeff[0] * buf[n] + coeff[1] * state[0] + coeff[2] * state[1] - coeff[4] * state[2] - coeff[5] * state[3];
    1.88 +				state[1] = temp;
    1.89 +				state[3] = buf[n];
    1.90 +				cvt->state_pos = 0;
    1.91 +			} else {
    1.92 +				buf[n] = coeff[0] * buf[n] + coeff[1] * state[1] + coeff[2] * state[0] - coeff[4] * state[3] - coeff[5] * state[2];
    1.93 +				state[0] = temp;
    1.94 +				state[2] = buf[n];
    1.95 +				cvt->state_pos = 1;
    1.96 +			}
    1.97 +		}
    1.98 +	} else {
    1.99 +	}
   1.100 +}
   1.101 +
   1.102  /* Apply the windowed sinc FIR filter to the given SDL_AudioCVT struct */
   1.103  int SDL_FilterFIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
   1.104  	int n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4);
   1.105 @@ -1437,7 +1485,7 @@
   1.106  	   significantly fewer multiplications and additions.
   1.107  	*/
   1.108  #define filter_sinc(type, shift_bits) { \
   1.109 -			type *sinc = (type *)cvt->sinc; \
   1.110 +			type *sinc = (type *)cvt->coeff; \
   1.111  			type *state = (type *)cvt->state_buf; \
   1.112  			type *buf = (type *)cvt->buf; \
   1.113  			for(i = 0; i < n; ++i) { \
   1.114 @@ -1449,17 +1497,33 @@
   1.115  				} \
   1.116  			} \
   1.117  		}
   1.118 -			
   1.119 -	switch (SDL_AUDIO_BITSIZE(format)) {
   1.120 -		case 8:
   1.121 -			filter_sinc(Uint8, 4);
   1.122 -			break;
   1.123 -		case 16:
   1.124 -			filter_sinc(Uint16, 8);
   1.125 -			break;
   1.126 -		case 32:
   1.127 -			filter_sinc(Uint32, 16);
   1.128 -			break;
   1.129 +	
   1.130 +	/* If it's floating point, we don't need to do any shifting */
   1.131 +	if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
   1.132 +		float *sinc = (float *)cvt->coeff;
   1.133 +		float *state = (float *)cvt->state_buf;
   1.134 +		float *buf = (float *)cvt->buf;
   1.135 +		
   1.136 +		for(i = 0; i < n; ++i) {
   1.137 +			state[cvt->state_pos++] = buf[i];
   1.138 +			if(cvt->state_pos == m) cvt->state_pos = 0;
   1.139 +			buf[i] = 0.0f;
   1.140 +			for(j = 0; j < m; ++j) {
   1.141 +				buf[i] += state[j] * sinc[j];
   1.142 +			}
   1.143 +		}
   1.144 +	} else {
   1.145 +		switch (SDL_AUDIO_BITSIZE(format)) {
   1.146 +			case 8:
   1.147 +				filter_sinc(Uint8, 4);
   1.148 +				break;
   1.149 +			case 16:
   1.150 +				filter_sinc(Uint16, 8);
   1.151 +				break;
   1.152 +			case 32:
   1.153 +				filter_sinc(Uint32, 16);
   1.154 +				break;
   1.155 +		}
   1.156  	}
   1.157  	
   1.158  #undef filter_sinc
   1.159 @@ -1482,7 +1546,7 @@
   1.160  	unsigned int i;
   1.161  
   1.162  	/* Check that the buffer is allocated */
   1.163 -	if( cvt->sinc == NULL ) {
   1.164 +	if( cvt->coeff == NULL ) {
   1.165  		return -1;
   1.166  	}
   1.167  
   1.168 @@ -1519,7 +1583,7 @@
   1.169  	
   1.170  #define convert_fixed(type, size) { \
   1.171  		norm_fact = size / norm_sum; \
   1.172 -		type *dst = (type *)cvt->sinc; \
   1.173 +		type *dst = (type *)cvt->coeff; \
   1.174  		for( i = 0; i <= m; ++i ) { \
   1.175  			dst[i] = (type)(fSinc[i] * norm_fact); \
   1.176  		} \
   1.177 @@ -1527,7 +1591,7 @@
   1.178  	
   1.179  	/* If we're using floating point, we only need to normalize */
   1.180  	if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
   1.181 -		float *fDest = (float *)cvt->sinc;
   1.182 +		float *fDest = (float *)cvt->coeff;
   1.183  		norm_fact = 1.0f / norm_sum;
   1.184  		for(i = 0; i <= m; ++i) {
   1.185  			fDest[i] = fSinc[i] * norm_fact;
   1.186 @@ -1555,6 +1619,17 @@
   1.187  	free(fSinc);
   1.188  }
   1.189  
   1.190 +/* This is used to reduce the resampling ratio */
   1.191 +inline int SDL_GCD(int a, int b) {
   1.192 +	int temp;
   1.193 +	while(b != 0) {
   1.194 +		temp = a % b;
   1.195 +		a = b;
   1.196 +		b = temp;
   1.197 +	}
   1.198 +	return a;
   1.199 +}
   1.200 +
   1.201  
   1.202  /* Creates a set of audio filters to convert from one format to another.
   1.203     Returns -1 if the format conversion is not supported, 0 if there's
   1.204 @@ -1644,7 +1719,14 @@
   1.205      }
   1.206  
   1.207      /* Do rate conversion */
   1.208 -    cvt->rate_incr = 0.0;
   1.209 +	int rate_gcd;
   1.210 +	rate_gcd = SDL_GCD(src_rate, dst_rate);
   1.211 +	cvt->len_mult = dst_rate / rate_gcd;
   1.212 +	cvt->len_div = src_rate / rate_gcd;
   1.213 +	cvt->len_ratio = (double)cvt->len_mult / (double)cvt->len_div;
   1.214 +	cvt->filters[cvt->filter_index++] = SDL_Resample;
   1.215 +	
   1.216 +    /*cvt->rate_incr = 0.0;
   1.217      if ((src_rate / 100) != (dst_rate / 100)) {
   1.218          Uint32 hi_rate, lo_rate;
   1.219          int len_mult;
   1.220 @@ -1693,16 +1775,16 @@
   1.221              }
   1.222              len_mult = 2;
   1.223              len_ratio = 2.0;
   1.224 -        }
   1.225 +        }*/
   1.226          /* If hi_rate = lo_rate*2^x then conversion is easy */
   1.227 -        while (((lo_rate * 2) / 100) <= (hi_rate / 100)) {
   1.228 +        /*while (((lo_rate * 2) / 100) <= (hi_rate / 100)) {
   1.229              cvt->filters[cvt->filter_index++] = rate_cvt;
   1.230              cvt->len_mult *= len_mult;
   1.231              lo_rate *= 2;
   1.232              cvt->len_ratio *= len_ratio;
   1.233 -        }
   1.234 +        }*/
   1.235          /* We may need a slow conversion here to finish up */
   1.236 -        if ((lo_rate / 100) != (hi_rate / 100)) {
   1.237 +        /*if ((lo_rate / 100) != (hi_rate / 100)) {*/
   1.238  #if 1
   1.239              /* The problem with this is that if the input buffer is
   1.240                 say 1K, and the conversion rate is say 1.1, then the
   1.241 @@ -1722,8 +1804,8 @@
   1.242              }
   1.243              cvt->filters[cvt->filter_index++] = SDL_RateSLOW;
   1.244  #endif
   1.245 -        }
   1.246 -    }
   1.247 +/*        }
   1.248 +    }*/
   1.249  
   1.250      /* Set up the filter information */
   1.251      if (cvt->filter_index != 0) {