comparison alt_audio_convert.c @ 338:7b9a0f3f030e

Initial add.
author Ryan C. Gordon <icculus@icculus.org>
date Mon, 20 May 2002 16:18:09 +0000
parents
children fbbb1f25b944
comparison
equal deleted inserted replaced
337:83233d8a5929 338:7b9a0f3f030e
1 /*
2 Extended Audio Converter for SDL (Simple DirectMedia Layer)
3 Copyright (C) 2002 Frank Ranostaj
4 Institute of Applied Physik
5 Johann Wolfgang Goethe-Universität
6 Frankfurt am Main, Germany
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public
19 License along with this library; if not, write to the Free
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
22 Frank Ranostaj
23 ranostaj@stud.uni-frankfurt.de
24
25 (This code blatantly abducted for SDL_sound. Thanks, Frank! --ryan.)
26 */
27
28 #include "alt_audio_convert.h"
29
30 #include <stdlib.h>
31 #include <math.h>
32
33 /*provisorisch*/
34 #define AUDIO_8 (4)
35 #define AUDIO_16WRONG (8)
36 #define AUDIO_FORMAT (AUDIO_8 | AUDIO_16WRONG)
37 #define AUDIO_SIGN (1)
38
39
40 /*-------------------------------------------------------------------------*/
41 /* this filter (Kaiser-window beta=6.8) gives a decent -80dB attentuation */
42 static const int filter[_fsize/2] = {
43 0, 20798, 0, -6764, 0, 3863, 0, -2560, 0, 1800, 0, -1295, 0, 936, 0,
44 -671,
45 0, 474, 0, -326, 0, 217, 0, -138, 0, 83, 0, -46, 0, 23, 0, -9
46 };
47
48 /* Mono (1 channel ) */
49 #define Suffix(x) x##1
50 #include "filter_templates.h"
51 #undef Suffix
52
53 /* Stereo (2 channel ) */
54 #define Suffix(x) x##2
55 #include "filter_templates.h"
56 #undef Suffix
57
58 /* !!! FIXME: Lose all the "short" vars for "Sint16", etc. */
59
60 /*-------------------------------------------------------------------------*/
61 int DECLSPEC Sound_ConvertAudio( Sound_AudioCVT *Data )
62 {
63 AdapterC Temp;
64 int i;
65
66 /* !!! FIXME: Try the looping stuff under certain circumstances? --ryan. */
67 int mode = 0;
68
69 /* Make sure there's a converter */
70 if( Data == NULL ) {
71 SDL_SetError("No converter given");
72 return(-1);
73 }
74
75 /* Make sure there's data to convert */
76 if( Data->buf == NULL ) {
77 SDL_SetError("No buffer allocated for conversion");
78 return(-1);
79 }
80
81 /* Set up the conversion and go! */
82 Temp.buffer = (short*)Data->buf;
83 Temp.mode = mode;
84 Temp.filter = &Data->filter;
85
86 Data->len_cvt = Data->len;
87 for( i = 0; Data->adapter[i] != NULL; i++ )
88 Data->len_cvt = (*Data->adapter[i])( Temp, Data->len_cvt);
89
90 return(0);
91 }
92
93 /*-------------------------------------------------------------------------*/
94 int expand8BitTo16Bit( AdapterC Data, int length )
95 {
96 int i;
97 char* inp = (char*)Data.buffer-1;
98 short* buffer = Data.buffer-1;
99 for( i = length; i; i-- )
100 buffer[i] = inp[i]<<8;
101 return length*2;
102 }
103
104 /*-------------------------------------------------------------------------*/
105 int swapBytes( AdapterC Data, int length )
106 {
107 int i;
108 unsigned short a,b;
109 short* buffer = Data.buffer;
110 for( i = 0; i < length; i++ )
111 {
112 a = b = buffer[i];
113 a <<= 8;
114 b >>= 8;
115 buffer[i] = a | b;
116 }
117 return length;
118 }
119
120 /*-------------------------------------------------------------------------*/
121 int cut16BitTo8Bit( AdapterC Data, int length )
122 {
123 int i;
124 short* inp = Data.buffer-1;
125 char* buffer = (char*)Data.buffer-1;
126 for( i = 0; i < length; i++ )
127 buffer[i] = inp[i]>>8;
128 return length/2;
129 }
130
131 /*-------------------------------------------------------------------------*/
132 int changeSigned( AdapterC Data, int length )
133 {
134 int i;
135 short* buffer = Data.buffer;
136 for( i = 0; i < length; i++ )
137 buffer[i] ^= 0x8000;
138 return length;
139 }
140
141 /*-------------------------------------------------------------------------*/
142 int convertStereoToMono( AdapterC Data, int length )
143 {
144 int i;
145 short* buffer = Data.buffer;
146
147 /*
148 * !!! FIXME: Can we avoid the division in this loop and just keep
149 * !!! FIXME: a second index variable? --ryan.
150 */
151 for( i = 0; i < length; i+=2 )
152 buffer[i/2] = ((int)buffer[i] + buffer[i+1] ) >> 1;
153 return length/2;
154 }
155
156 /*-------------------------------------------------------------------------*/
157 int convertMonoToStereo( AdapterC Data, int length )
158 {
159 int i;
160 short* buffer = Data.buffer-2;
161 length *= 2;
162
163 /*
164 * !!! FIXME: Can we avoid the division in this loop and just keep
165 * !!! FIXME: a second index variable? --ryan.
166 */
167 for( i = length; i; i-=2 )
168 buffer[i] = buffer [i+1] = buffer[i/2];
169 return length*2;
170 }
171
172 /*-------------------------------------------------------------------------*/
173 int minus5dB( AdapterC Data, int length )
174 {
175 int i;
176 short* buffer = Data.buffer;
177 for(i = length; i >= 0; i--)
178 buffer[i]= 38084 * buffer[i] >> 16;
179 return length;
180 }
181
182 /*-------------------------------------------------------------------------*/
183 int doubleRateStereo( AdapterC Data, int length )
184 {
185 _doubleRate2( Data.buffer, Data.mode, length/2 );
186 return 2*_doubleRate2( Data.buffer+1, Data.mode, length/2 );
187 }
188
189 int doubleRateMono( AdapterC Data, int length )
190 {
191 return _doubleRate1( Data.buffer, Data.mode, length );
192 }
193
194 /*-------------------------------------------------------------------------*/
195 int halfRateStereo( AdapterC Data, int length )
196 {
197 _halfRate2( Data.buffer, Data.mode, length/2 );
198 return 2*_halfRate2( Data.buffer+1, Data.mode, length/2 );
199 }
200
201 int halfRateMono( AdapterC Data, int length )
202 {
203 return _halfRate2( Data.buffer, Data.mode, length );
204 }
205
206 /*-------------------------------------------------------------------------*/
207 int varRateStereo( AdapterC Data, int length )
208 {
209 _varRate2( Data.buffer, Data.mode, Data.filter, length/2 );
210 return 2*_varRate2( Data.buffer+1, Data.mode, Data.filter, length/2 );
211 }
212
213 int varRateMono( AdapterC Data, int length )
214 {
215 return _varRate1( Data.buffer, Data.mode, Data.filter, length );
216 }
217
218 /*-------------------------------------------------------------------------*/
219 typedef struct{
220 short denominator;
221 short numerator;
222 } Fraction;
223
224 /*-------------------------------------------------------------------------*/
225 Fraction findFraction( float Value )
226 {
227 /* gives a maximal error of 3% and typical less than 0.2% */
228 const char frac[96]={
229 1, 2, -1, /* /1 */
230 1, 3, -1, /* /2 */
231 2, 4, 5, -1, /* /3 */
232 3, 5, 7, -1, /* /4 */
233 3, 4, 6, 7, 8, 9, -1, /* /5 */
234 5, 7, 11, -1, /* /6 */
235 4, 5, 6, 8, 9, 10, 11, 12, 13, -1, /* /7 */
236 5, 7, 9, 11, 13, 15, -1, /* /8 */
237 5, 7, 8, 10, 11, 13, 14, 16, -1, /* /9 */
238 7, 9, 11, 13, -1, /* /10 */
239 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, -1, /* /11 */
240 7, 11, 13, -1, /* /12 */
241 7, 8, 9, 10, 11, 12, 14, 15, 16, -1, /* /13 */
242 9, 11, 13, 15, -1, /* /14 */
243 8, 11, 13, 14, 16, -1, /* /15 */
244 9, 11, 13, 15 }; /* /16 */
245
246
247 Fraction Result = {0,0};
248 int n,num,den=2;
249
250 float RelErr, BestErr = 0;
251 if( Value < 31/64. || Value > 64/31. ) return Result;
252
253 for( n = 0; n < sizeof(frac); num=frac[++n] )
254 {
255 if( num < 0 ) den++;
256 RelErr = Value * num / den;
257 RelErr = ( RelErr < (1/RelErr) ? RelErr : 1/RelErr );
258 if( RelErr > BestErr )
259 {
260 BestErr = RelErr;
261 Result.denominator = den;
262 Result.numerator = num;
263 }
264 }
265 return Result;
266 }
267
268
269 float sinc( float x )
270 {
271 if( x > -1e-24 && x < 1e-24 ) return 1.;
272 else return sin(x)/x;
273 }
274
275 void calculateVarFilter( short* dst, float Ratio, float phase, float scale )
276 {
277 const unsigned short KaiserWindow7[]= {
278 22930, 16292, 14648, 14288, 14470, 14945, 15608, 16404,
279 17304, 18289, 19347, 20467, 21644, 22872, 24145, 25460,
280 26812, 28198, 29612, 31052, 32513, 33991, 35482, 36983,
281 38487, 39993, 41494, 42986, 44466, 45928, 47368, 48782,
282 50165, 51513, 52821, 54086, 55302, 56466, 57575, 58624,
283 59610, 60529, 61379, 62156, 62858, 63483, 64027, 64490,
284 64870, 65165, 65375, 65498, 65535, 65484, 65347, 65124,
285 64815, 64422, 63946, 63389, 62753, 62039, 61251, 60391 };
286 int i;
287 float w;
288 const float fg = -.018 + .5 / Ratio;
289 const float omega = 2 * M_PI * fg;
290 phase -= 63;
291 for( i = 0; i < 64; i++)
292 {
293 w = scale * ( KaiserWindow7[i] * ( i + 1 ));
294 dst[i] = w * sinc( omega * (i+phase) );
295 dst[127-i] = w * sinc( omega * (127-i+phase) );
296 }
297 }
298
299 typedef struct{
300 float scale;
301 int incr;
302 } VarFilterMode;
303
304 const VarFilterMode Up = { 0.0211952, 0 };
305 const VarFilterMode Down = { 0.0364733, 2 };
306
307
308 void setupVarFilter( VarFilter* filter,
309 float Ratio, VarFilterMode Direction )
310 {
311 int i,n,d;
312 Fraction IRatio;
313 float phase;
314 IRatio = findFraction( Ratio );
315
316 if ( (1/Ratio) < Ratio )
317 Ratio = 1/Ratio;
318
319 n = IRatio.numerator;
320 d = IRatio.denominator;
321 filter->pos_mod = n;
322
323 for( i = 0; i < d; i++ )
324 {
325 if( phase >= n )
326 {
327 phase -= d;
328 filter->incr[i] = Direction.incr;
329 }
330 else
331 filter->incr[i] = 1;
332
333 calculateVarFilter( filter->c[i], Ratio, phase/(float)n,
334 Direction.scale );
335 phase += d;
336 }
337 }
338
339 int createRateConverter( Sound_AudioCVT *Data, int filter_index,
340 int SrcRate, int DestRate, int Channel )
341 {
342 int VarPos = 0;
343 int Mono = 2 - Channel;
344 float Ratio = DestRate;
345 if( SrcRate < 1 || SrcRate > 1<<18 ||
346 DestRate < 1 || DestRate > 1<<18 ) return -1;
347 if( SrcRate == DestRate ) return filter_index;
348 Ratio /= SrcRate;
349
350 if( Ratio > 1.0)
351 VarPos = filter_index++;
352 else
353 Data->adapter[filter_index++] = minus5dB;
354
355 while( Ratio > 64.0/31.0)
356 {
357 Data->adapter[filter_index++] =
358 Mono ? doubleRateMono : doubleRateStereo;
359 Ratio /= 2;
360 Data->len_mult *= 2;
361 Data->add *= 2;
362 Data->add += _fsize;
363 }
364
365 while( Ratio < 31.0/64.0 )
366 {
367 Data->adapter[filter_index++] =
368 Mono ? halfRateMono : halfRateStereo;
369 Ratio *= 2;
370 }
371
372 if( Ratio > 1.0 )
373 {
374 setupVarFilter( &Data->filter, Ratio, Up );
375 Data->adapter[VarPos] =
376 Mono ? varRateMono : varRateStereo;
377 Data->len_mult *= 2;
378 Data->add *= 2;
379 Data->add += _fsize;
380 }
381 else
382 {
383 setupVarFilter( &Data->filter, Ratio, Down );
384 Data->adapter[filter_index++] =
385 Mono ? varRateMono : varRateStereo;
386 }
387 return 0;
388 }
389
390 int DECLSPEC Sound_BuildAudioCVT(Sound_AudioCVT *Data,
391 Uint16 src_format, Uint8 src_channels, int src_rate,
392 Uint16 dst_format, Uint8 dst_channels, int dst_rate)
393 {
394 int filter_index = 0;
395
396 if( Data == NULL ) return -1;
397 Data->len_mult = 1.0;
398 Data->add = 0;
399
400 /* Check channels */
401 if( src_channels < 1 || src_channels > 2 ||
402 dst_channels < 1 || dst_channels > 2 ) goto error_exit;
403
404 /* First filter: Size/Endian conversion */
405 switch( src_format & AUDIO_FORMAT)
406 {
407 case AUDIO_8:
408 Data->adapter[filter_index++] = expand8BitTo16Bit;
409 Data->len_mult *= 2;
410 break;
411 case AUDIO_16WRONG:
412 Data->adapter[filter_index++] = swapBytes;
413 }
414
415 /* Second adapter: Sign conversion -- unsigned/signed */
416 if( src_format & AUDIO_SIGN )
417 Data->adapter[filter_index++] = changeSigned;
418
419 /* Third adapter: Stereo->Mono conversion */
420 if( src_channels == 2 && dst_channels == 1 )
421 Data->adapter[filter_index++] = convertStereoToMono;
422
423 /* Do rate conversion */
424 if( src_channels == 2 && dst_channels == 2 )
425 filter_index = createRateConverter( Data, filter_index,
426 src_rate, dst_rate, 2 );
427 else
428 filter_index = createRateConverter( Data, filter_index,
429 src_rate, dst_rate, 1 );
430
431 if( filter_index < 0 ) goto error_exit; /* propagate error */
432
433 /* adapter: Mono->Stereo conversion */
434 if( src_channels == 1 && dst_channels == 2 ){
435 Data->adapter[filter_index++] = convertMonoToStereo;
436 Data->add *= 2;
437 Data->len_mult *= 2;
438 }
439
440 /* adapter: final Sign conversion -- unsigned/signed */
441 if( dst_format & AUDIO_SIGN )
442 Data->adapter[filter_index++] = changeSigned;
443
444 /* final adapter: Size/Endian conversion */
445 switch( dst_format & AUDIO_FORMAT)
446 {
447 case AUDIO_8:
448 Data->adapter[filter_index++] = cut16BitTo8Bit;
449 break;
450 case AUDIO_16WRONG:
451 Data->adapter[filter_index++] = swapBytes;
452 }
453 /* Set up the filter information */
454 Data->adapter[filter_index] = NULL;
455 Data->needed = (filter_index > 0);
456 return 0;
457
458 error_exit:
459 Data->adapter[0] = NULL;
460 return -1;
461 }
462 /*-------------------------------------------------------------------------*/
463