src/audio/SDL_audiocvt.c
branchgsoc2008_audio_resampling
changeset 2657 29306e52dab8
parent 2656 dd74182b3c3c
child 2658 de29a03cb108
     1.1 --- a/src/audio/SDL_audiocvt.c	Wed Jun 18 18:55:50 2008 +0000
     1.2 +++ b/src/audio/SDL_audiocvt.c	Wed Jun 18 22:42:27 2008 +0000
     1.3 @@ -29,6 +29,35 @@
     1.4  
     1.5  #define DEBUG_CONVERT
     1.6  
     1.7 +/* Perform fractional multiplication of two 32-bit integers to produce a 32-bit result. Assumes sizeof(long) = 4 */
     1.8 +/*#define SDL_FixMpy32(v1, v2, dest) { \
     1.9 +			long a, b, c, d; \
    1.10 +			long x, y; \
    1.11 +			a = (v1 >> 16) & 0xffff; \
    1.12 +			b = v1 & 0xffff; \
    1.13 +			c = (v2 >> 16); \
    1.14 +			d = v2 & 0xffff; \
    1.15 +			x = a * d + c * b; \
    1.16 +			y = (((b*d) >> 16) & 0xffff) + x; \
    1.17 +			dest = ((y >> 16) & 0xffff) + (a * c); \
    1.18 +		}*/
    1.19 +/* TODO: Check if 64-bit type exists. If not, see http://www.8052.com/mul16.phtml or http://www.cs.uaf.edu/~cs301/notes/Chapter5/node5.html */
    1.20 +		
    1.21 +#define SDL_FixMpy32(a, b) ((((long long)a * (long long)b) >> 32) & 0xffffffff)
    1.22 +#ifdef DEBUG_CONVERT
    1.23 +#define SDL_FixMpy16(a, b) ((((long)a * (long)b) >> 16) & 0xffff); printf("%f * %f = %f\n", (float)a / 16384.0f, (float)b / 16384.0f, (float)((((long)a * (long)b) >> 16) & 0xffff) / 16384.0f);
    1.24 +#else
    1.25 +#define SDL_FixMpy16(a, b) ((((long)a * (long)b) >> 16) & 0xffff)
    1.26 +#endif
    1.27 +#define SDL_FixMpy8(a, b) ((((short)a * (short)b) >> 8) & 0xff)
    1.28 +
    1.29 +#define SDL_Make_1_7(a) (Uint8)(a * 128.0f)
    1.30 +#define SDL_Make_1_15(a) (Uint16)(a * 32768.0f)
    1.31 +#define SDL_Make_1_31(a) (Uint32)(a * 2147483648.0f)
    1.32 +#define SDL_Make_2_6(a) (Uint8)(a * 64.0f)
    1.33 +#define SDL_Make_2_14(a) (Uint16)(a * 16384.0f)
    1.34 +#define SDL_Make_2_30(a) (Uint32)(a * 1073741824.0f)
    1.35 +
    1.36  /* Effectively mix right and left channels into a single channel */
    1.37  static void SDLCALL
    1.38  SDL_ConvertMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    1.39 @@ -1232,85 +1261,6 @@
    1.40      }
    1.41  }
    1.42  
    1.43 -/* Perform proper resampling */
    1.44 -static void SDLCALL
    1.45 -SDL_Resample(SDL_AudioCVT * cvt, SDL_AudioFormat format)
    1.46 -{
    1.47 -    int i, j;
    1.48 -
    1.49 -#ifdef DEBUG_CONVERT
    1.50 -    printf("Converting audio rate via proper resampling (mono)\n");
    1.51 -#endif
    1.52 -
    1.53 -#define zerostuff_mono(type) { \
    1.54 -        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
    1.55 -        type *dst = (type *) (cvt->buf + (cvt->len_cvt * cvt->len_mult)); \
    1.56 -        for (i = cvt->len_cvt / sizeof (type); i; --i) { \
    1.57 -            src--; \
    1.58 -            dst[-1] = src[0]; \
    1.59 -			for( j = -cvt->len_mult; j < -1; ++j ) { \
    1.60 -				dst[j] = 0; \
    1.61 -			} \
    1.62 -            dst -= cvt->len_mult; \
    1.63 -        } \
    1.64 -    }
    1.65 -	
    1.66 -#define discard_mono(type) { \
    1.67 -        const type *src = (const type *) (cvt->buf); \
    1.68 -        type *dst = (type *) (cvt->buf); \
    1.69 -        for (i = 0; i < cvt->len_cvt / cvt->len_div / sizeof (type); ++i) { \
    1.70 -            dst[0] = src[0]; \
    1.71 -            src += cvt->len_div; \
    1.72 -            ++dst; \
    1.73 -        } \
    1.74 -    }
    1.75 -
    1.76 -	// Step 1: Zero stuff the conversion buffer
    1.77 -#ifdef DEBUG_CONVERT
    1.78 -	printf("Zero-stuffing by a factor of %u\n", cvt->len_mult);
    1.79 -#endif
    1.80 -    switch (SDL_AUDIO_BITSIZE(format)) {
    1.81 -    case 8:
    1.82 -        zerostuff_mono(Uint8);
    1.83 -        break;
    1.84 -    case 16:
    1.85 -        zerostuff_mono(Uint16);
    1.86 -        break;
    1.87 -    case 32:
    1.88 -        zerostuff_mono(Uint32);
    1.89 -        break;
    1.90 -    }
    1.91 -	
    1.92 -	cvt->len_cvt *= cvt->len_mult;
    1.93 -
    1.94 -	// Step 2: Use either a windowed sinc FIR filter or IIR lowpass filter to remove all alias frequencies
    1.95 -	
    1.96 -	// Step 3: Discard unnecessary samples
    1.97 -#ifdef DEBUG_CONVERT
    1.98 -	printf("Discarding samples by a factor of %u\n", cvt->len_div);
    1.99 -#endif
   1.100 -    switch (SDL_AUDIO_BITSIZE(format)) {
   1.101 -    case 8:
   1.102 -        discard_mono(Uint8);
   1.103 -        break;
   1.104 -    case 16:
   1.105 -        discard_mono(Uint16);
   1.106 -        break;
   1.107 -    case 32:
   1.108 -        discard_mono(Uint32);
   1.109 -        break;
   1.110 -    }
   1.111 -	
   1.112 -#undef zerostuff_mono
   1.113 -#undef discard_mono
   1.114 -
   1.115 -    cvt->len_cvt /= cvt->len_div;
   1.116 -	
   1.117 -    if (cvt->filters[++cvt->filter_index]) {
   1.118 -        cvt->filters[cvt->filter_index] (cvt, format);
   1.119 -    }
   1.120 -}
   1.121 -
   1.122  int
   1.123  SDL_ConvertAudio(SDL_AudioCVT * cvt)
   1.124  {
   1.125 @@ -1404,6 +1354,7 @@
   1.126  	float coeff[6];		/* floating point iir coefficients b0, b1, b2, a0, a1, a2 */
   1.127  	float scale;
   1.128  	float w0, alpha, cosw0;
   1.129 +	int i;
   1.130  	
   1.131  	/* The higher Q is, the higher CUTOFF can be. Need to find a good balance to avoid aliasing */
   1.132  	static const float Q = 5.0f;
   1.133 @@ -1427,37 +1378,104 @@
   1.134  	coeff[5] = (1.0f - alpha) * scale;
   1.135  	
   1.136  	/* Copy the coefficients to the struct. If necessary, convert coefficients to fixed point, using the range (-2.0, 2.0) */
   1.137 +#define convert_fixed(type, fix) { \
   1.138 +			type *cvt_coeff = (type *)cvt->coeff; \
   1.139 +			for(i = 0; i < 6; ++i) { \
   1.140 +				cvt_coeff[i] = fix(coeff[i]); \
   1.141 +			} \
   1.142 +		}
   1.143 +		
   1.144  	if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
   1.145  		float *cvt_coeff = (float *)cvt->coeff;
   1.146 -		int i;
   1.147  		for(i = 0; i < 6; ++i) {
   1.148  			cvt_coeff[i] = coeff[i];
   1.149  		}
   1.150  	} else {
   1.151 +		switch(SDL_AUDIO_BITSIZE(format)) {
   1.152 +			case 8:
   1.153 +				convert_fixed(Uint8, SDL_Make_2_6);
   1.154 +				break;
   1.155 +			case 16:
   1.156 +				convert_fixed(Uint16, SDL_Make_2_14);
   1.157 +				break;
   1.158 +			case 32:
   1.159 +				convert_fixed(Uint32, SDL_Make_2_30);
   1.160 +				break;
   1.161 +		}
   1.162  	}
   1.163  	
   1.164 +#ifdef DEBUG_CONVERT
   1.165 +#define debug_iir(type) { \
   1.166 +			type *cvt_coeff = (type *)cvt->coeff; \
   1.167 +			for(i = 0; i < 6; ++i) { \
   1.168 +				printf("coeff[%u] = %f = 0x%x\n", i, coeff[i], cvt_coeff[i]); \
   1.169 +			} \
   1.170 +		}
   1.171 +		if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
   1.172 +			float *cvt_coeff = (float *)cvt->coeff;
   1.173 +			for(i = 0; i < 6; ++i) { \
   1.174 +				printf("coeff[%u] = %f = %f\n", i, coeff[i], cvt_coeff[i]); \
   1.175 +			}
   1.176 +		} else {
   1.177 +			switch(SDL_AUDIO_BITSIZE(format)) {
   1.178 +				case 8:
   1.179 +					debug_iir(Uint8);
   1.180 +					break;
   1.181 +				case 16:
   1.182 +					debug_iir(Uint16);
   1.183 +					break;
   1.184 +				case 32:
   1.185 +					debug_iir(Uint32);
   1.186 +					break;
   1.187 +			}
   1.188 +		}
   1.189 +#undef debug_iir
   1.190 +#endif
   1.191 +	
   1.192  	/* Initialize the state buffer to all zeroes, and set initial position */
   1.193  	memset(cvt->state_buf, 0, 4 * SDL_AUDIO_BITSIZE(format) / 4);
   1.194  	cvt->state_pos = 0;
   1.195 +#undef convert_fixed
   1.196  }
   1.197  
   1.198  /* Apply the lowpass IIR filter to the given SDL_AudioCVT struct */
   1.199 -int SDL_FilterIIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
   1.200 +static void SDL_FilterIIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
   1.201  	int i, n;
   1.202  	
   1.203  	n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4);
   1.204 -	
   1.205 +
   1.206 +	/* Note that the coefficients are 2_x and the input is 1_x. Do we need to shift left at the end here? */
   1.207 +#define iir_fix(type, mult) {\
   1.208 +			type *coeff = (type *)cvt->coeff; \
   1.209 +			type *state = (type *)cvt->state_buf; \
   1.210 +			type *buf = (type *)cvt->buf; \
   1.211 +			type temp; \
   1.212 +			for(i = 0; i < n; ++i) { \
   1.213 +					temp = buf[n] >> 1; \
   1.214 +					if(cvt->state_pos) { \
   1.215 +						buf[n] = mult(coeff[0], temp) + mult(coeff[1], state[0]) + mult(coeff[2], state[1]) - mult(coeff[4], state[2]) - mult(coeff[5], state[3]); \
   1.216 +						state[1] = temp; \
   1.217 +						state[3] = buf[n]; \
   1.218 +						cvt->state_pos = 0; \
   1.219 +					} else { \
   1.220 +						buf[n] = mult(coeff[0], temp) + mult(coeff[1], state[1]) +mult(coeff[2], state[0]) - mult(coeff[4], state[3]) - mult(coeff[5], state[2]); \
   1.221 +						state[0] = temp; \
   1.222 +						state[2] = buf[n]; \
   1.223 +						cvt->state_pos = 0; \
   1.224 +					} \
   1.225 +				} \
   1.226 +		}
   1.227 +
   1.228  	if(SDL_AUDIO_ISFLOAT(format) && SDL_AUDIO_BITSIZE(format) == 32) {
   1.229  		float *coeff = (float *)cvt->coeff;
   1.230  		float *state = (float *)cvt->state_buf;
   1.231  		float *buf = (float *)cvt->buf;
   1.232  		float temp;
   1.233  
   1.234 -		
   1.235  		for(i = 0; i < n; ++i) {
   1.236  			/* y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] - a1 * y[n-1] - a[2] * y[n-2] */
   1.237  			temp = buf[n];
   1.238 -			if( cvt->state_pos ) {
   1.239 +			if(cvt->state_pos) {
   1.240  				buf[n] = coeff[0] * buf[n] + coeff[1] * state[0] + coeff[2] * state[1] - coeff[4] * state[2] - coeff[5] * state[3];
   1.241  				state[1] = temp;
   1.242  				state[3] = buf[n];
   1.243 @@ -1470,11 +1488,23 @@
   1.244  			}
   1.245  		}
   1.246  	} else {
   1.247 +		switch(SDL_AUDIO_BITSIZE(format)) {
   1.248 +			case 8:
   1.249 +				iir_fix(Uint8, SDL_FixMpy8);
   1.250 +				break;
   1.251 +			case 16:
   1.252 +				iir_fix(Uint16, SDL_FixMpy16);
   1.253 +				break;
   1.254 +			case 32:
   1.255 +				iir_fix(Uint32, SDL_FixMpy32);
   1.256 +				break;
   1.257 +		}
   1.258  	}
   1.259 +#undef iir_fix
   1.260  }
   1.261  
   1.262  /* Apply the windowed sinc FIR filter to the given SDL_AudioCVT struct */
   1.263 -int SDL_FilterFIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
   1.264 +static void SDL_FilterFIR(SDL_AudioCVT * cvt, SDL_AudioFormat format) {
   1.265  	int n = cvt->len_cvt / (SDL_AUDIO_BITSIZE(format) / 4);
   1.266  	int m = cvt->len_sinc;
   1.267  	int i, j;
   1.268 @@ -1484,16 +1514,15 @@
   1.269  	   of the fact that the signal is zero stuffed, so we can do
   1.270  	   significantly fewer multiplications and additions.
   1.271  	*/
   1.272 -#define filter_sinc(type, shift_bits) { \
   1.273 +#define filter_sinc(type, mult) { \
   1.274  			type *sinc = (type *)cvt->coeff; \
   1.275  			type *state = (type *)cvt->state_buf; \
   1.276  			type *buf = (type *)cvt->buf; \
   1.277  			for(i = 0; i < n; ++i) { \
   1.278 -				state[cvt->state_pos++] = buf[i] >> shift_bits; \
   1.279  				if(cvt->state_pos == m) cvt->state_pos = 0; \
   1.280  				buf[i] = 0; \
   1.281  				for(j = 0; j < m;  ++j) { \
   1.282 -					buf[i] += state[j] * sinc[j]; \
   1.283 +					buf[i] += mult(state[j], sinc[j]); \
   1.284  				} \
   1.285  			} \
   1.286  		}
   1.287 @@ -1515,13 +1544,13 @@
   1.288  	} else {
   1.289  		switch (SDL_AUDIO_BITSIZE(format)) {
   1.290  			case 8:
   1.291 -				filter_sinc(Uint8, 4);
   1.292 +				filter_sinc(Uint8, SDL_FixMpy8);
   1.293  				break;
   1.294  			case 16:
   1.295 -				filter_sinc(Uint16, 8);
   1.296 +				filter_sinc(Uint16, SDL_FixMpy16);
   1.297  				break;
   1.298  			case 32:
   1.299 -				filter_sinc(Uint32, 16);
   1.300 +				filter_sinc(Uint32, SDL_FixMpy32);
   1.301  				break;
   1.302  		}
   1.303  	}
   1.304 @@ -1581,11 +1610,11 @@
   1.305  	/* Now normalize and convert to fixed point. We scale everything to half the precision
   1.306  	   of whatever datatype we're using, for example, 16 bit data means we use 8 bits */
   1.307  	
   1.308 -#define convert_fixed(type, size) { \
   1.309 -		norm_fact = size / norm_sum; \
   1.310 +#define convert_fixed(type, fix) { \
   1.311 +		norm_fact = 1.0f / norm_sum; \
   1.312  		type *dst = (type *)cvt->coeff; \
   1.313  		for( i = 0; i <= m; ++i ) { \
   1.314 -			dst[i] = (type)(fSinc[i] * norm_fact); \
   1.315 +			dst[i] = fix(fSinc[i] * norm_fact); \
   1.316  		} \
   1.317  	}
   1.318  	
   1.319 @@ -1599,13 +1628,13 @@
   1.320  	} else {
   1.321  		switch (SDL_AUDIO_BITSIZE(format)) {
   1.322  			case 8:
   1.323 -				convert_fixed(Uint8, 0x0e);
   1.324 +				convert_fixed(Uint8, SDL_Make_1_7);
   1.325  				break;
   1.326  			case 16:
   1.327 -				convert_fixed(Uint16, 0xfe);
   1.328 +				convert_fixed(Uint16, SDL_Make_1_15);
   1.329  				break;
   1.330  			case 32:
   1.331 -				convert_fixed(Uint32, 0xfffe);
   1.332 +				convert_fixed(Uint32, SDL_Make_1_31);
   1.333  				break;
   1.334  		}
   1.335  	}
   1.336 @@ -1630,6 +1659,86 @@
   1.337  	return a;
   1.338  }
   1.339  
   1.340 +/* Perform proper resampling */
   1.341 +static void SDLCALL
   1.342 +SDL_Resample(SDL_AudioCVT * cvt, SDL_AudioFormat format)
   1.343 +{
   1.344 +    int i, j;
   1.345 +
   1.346 +#ifdef DEBUG_CONVERT
   1.347 +    printf("Converting audio rate via proper resampling (mono)\n");
   1.348 +#endif
   1.349 +
   1.350 +#define zerostuff_mono(type) { \
   1.351 +        const type *src = (const type *) (cvt->buf + cvt->len_cvt); \
   1.352 +        type *dst = (type *) (cvt->buf + (cvt->len_cvt * cvt->len_mult)); \
   1.353 +        for (i = cvt->len_cvt / sizeof (type); i; --i) { \
   1.354 +            src--; \
   1.355 +            dst[-1] = src[0]; \
   1.356 +			for( j = -cvt->len_mult; j < -1; ++j ) { \
   1.357 +				dst[j] = 0; \
   1.358 +			} \
   1.359 +            dst -= cvt->len_mult; \
   1.360 +        } \
   1.361 +    }
   1.362 +	
   1.363 +#define discard_mono(type) { \
   1.364 +        const type *src = (const type *) (cvt->buf); \
   1.365 +        type *dst = (type *) (cvt->buf); \
   1.366 +        for (i = 0; i < cvt->len_cvt / cvt->len_div / sizeof (type); ++i) { \
   1.367 +            dst[0] = src[0]; \
   1.368 +            src += cvt->len_div; \
   1.369 +            ++dst; \
   1.370 +        } \
   1.371 +    }
   1.372 +
   1.373 +	// Step 1: Zero stuff the conversion buffer
   1.374 +#ifdef DEBUG_CONVERT
   1.375 +	printf("Zero-stuffing by a factor of %u\n", cvt->len_mult);
   1.376 +#endif
   1.377 +    switch (SDL_AUDIO_BITSIZE(format)) {
   1.378 +    case 8:
   1.379 +        zerostuff_mono(Uint8);
   1.380 +        break;
   1.381 +    case 16:
   1.382 +        zerostuff_mono(Uint16);
   1.383 +        break;
   1.384 +    case 32:
   1.385 +        zerostuff_mono(Uint32);
   1.386 +        break;
   1.387 +    }
   1.388 +	
   1.389 +	cvt->len_cvt *= cvt->len_mult;
   1.390 +
   1.391 +	// Step 2: Use either a windowed sinc FIR filter or IIR lowpass filter to remove all alias frequencies
   1.392 +	SDL_FilterIIR( cvt, format );
   1.393 +	
   1.394 +	// Step 3: Discard unnecessary samples
   1.395 +#ifdef DEBUG_CONVERT
   1.396 +	printf("Discarding samples by a factor of %u\n", cvt->len_div);
   1.397 +#endif
   1.398 +    switch (SDL_AUDIO_BITSIZE(format)) {
   1.399 +    case 8:
   1.400 +        discard_mono(Uint8);
   1.401 +        break;
   1.402 +    case 16:
   1.403 +        discard_mono(Uint16);
   1.404 +        break;
   1.405 +    case 32:
   1.406 +        discard_mono(Uint32);
   1.407 +        break;
   1.408 +    }
   1.409 +	
   1.410 +#undef zerostuff_mono
   1.411 +#undef discard_mono
   1.412 +
   1.413 +    cvt->len_cvt /= cvt->len_div;
   1.414 +	
   1.415 +    if (cvt->filters[++cvt->filter_index]) {
   1.416 +        cvt->filters[cvt->filter_index] (cvt, format);
   1.417 +    }
   1.418 +}
   1.419 +
   1.420  
   1.421  /* Creates a set of audio filters to convert from one format to another.
   1.422     Returns -1 if the format conversion is not supported, 0 if there's
   1.423 @@ -1721,10 +1830,11 @@
   1.424      /* Do rate conversion */
   1.425  	int rate_gcd;
   1.426  	rate_gcd = SDL_GCD(src_rate, dst_rate);
   1.427 -	cvt->len_mult = dst_rate / rate_gcd;
   1.428 -	cvt->len_div = src_rate / rate_gcd;
   1.429 +	cvt->len_mult = 2 * dst_rate / rate_gcd;
   1.430 +	cvt->len_div = 2 * src_rate / rate_gcd;
   1.431  	cvt->len_ratio = (double)cvt->len_mult / (double)cvt->len_div;
   1.432  	cvt->filters[cvt->filter_index++] = SDL_Resample;
   1.433 +	SDL_BuildIIRLowpass(cvt, dst_fmt);
   1.434  	
   1.435      /*cvt->rate_incr = 0.0;
   1.436      if ((src_rate / 100) != (dst_rate / 100)) {
   1.437 @@ -1819,4 +1929,14 @@
   1.438      return (cvt->needed);
   1.439  }
   1.440  
   1.441 +#undef SDL_FixMpy8
   1.442 +#undef SDL_FixMpy16
   1.443 +#undef SDL_FixMpy32
   1.444 +#undef SDL_Make_1_7
   1.445 +#undef SDL_Make_1_15
   1.446 +#undef SDL_Make_1_31
   1.447 +#undef SDL_Make_2_6
   1.448 +#undef SDL_Make_2_14
   1.449 +#undef SDL_Make_2_30
   1.450 +
   1.451  /* vi: set ts=4 sw=4 expandtab: */