Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
9561 turbocat 1
/*
2
    SDL - Simple DirectMedia Layer
3
    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
4
 
5
    This library is free software; you can redistribute it and/or
6
    modify it under the terms of the GNU Library General Public
7
    License as published by the Free Software Foundation; either
8
    version 2 of the License, or (at your option) any later version.
9
 
10
    This library is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
    Library General Public License for more details.
14
 
15
    You should have received a copy of the GNU Library General Public
16
    License along with this library; if not, write to the Free
17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
19
    Sam Lantinga
20
    slouken@devolution.com
21
*/
22
 
23
#ifdef SAVE_RCSID
24
static char rcsid =
25
 "@(#) $Id: SDL_audiocvt.c,v 1.2 2001/04/26 16:50:17 hercules Exp $";
26
#endif
27
 
28
/* Functions for audio drivers to perform runtime conversion of audio format */
29
 
30
#include 
31
 
32
#include "SDL_error.h"
33
#include "SDL_audio.h"
34
 
35
 
36
/* Effectively mix right and left channels into a single channel */
37
void SDL_ConvertMono(SDL_AudioCVT *cvt, Uint16 format)
38
{
39
	int i;
40
	Sint32 sample;
41
 
42
#ifdef DEBUG_CONVERT
43
	fprintf(stderr, "Converting to mono\n");
44
#endif
45
	switch (format&0x8018) {
46
 
47
		case AUDIO_U8: {
48
			Uint8 *src, *dst;
49
 
50
			src = cvt->buf;
51
			dst = cvt->buf;
52
			for ( i=cvt->len_cvt/2; i; --i ) {
53
				sample = src[0] + src[1];
54
				if ( sample > 255 ) {
55
					*dst = 255;
56
				} else {
57
					*dst = sample;
58
				}
59
				src += 2;
60
				dst += 1;
61
			}
62
		}
63
		break;
64
 
65
		case AUDIO_S8: {
66
			Sint8 *src, *dst;
67
 
68
			src = (Sint8 *)cvt->buf;
69
			dst = (Sint8 *)cvt->buf;
70
			for ( i=cvt->len_cvt/2; i; --i ) {
71
				sample = src[0] + src[1];
72
				if ( sample > 127 ) {
73
					*dst = 127;
74
				} else
75
				if ( sample < -128 ) {
76
					*dst = -128;
77
				} else {
78
					*dst = sample;
79
				}
80
				src += 2;
81
				dst += 1;
82
			}
83
		}
84
		break;
85
 
86
		case AUDIO_U16: {
87
			Uint8 *src, *dst;
88
 
89
			src = cvt->buf;
90
			dst = cvt->buf;
91
			if ( (format & 0x1000) == 0x1000 ) {
92
				for ( i=cvt->len_cvt/4; i; --i ) {
93
					sample = (Uint16)((src[0]<<8)|src[1])+
94
					         (Uint16)((src[2]<<8)|src[3]);
95
					if ( sample > 65535 ) {
96
						dst[0] = 0xFF;
97
						dst[1] = 0xFF;
98
					} else {
99
						dst[1] = (sample&0xFF);
100
						sample >>= 8;
101
						dst[0] = (sample&0xFF);
102
					}
103
					src += 4;
104
					dst += 2;
105
				}
106
			} else {
107
				for ( i=cvt->len_cvt/4; i; --i ) {
108
					sample = (Uint16)((src[1]<<8)|src[0])+
109
					         (Uint16)((src[3]<<8)|src[2]);
110
					if ( sample > 65535 ) {
111
						dst[0] = 0xFF;
112
						dst[1] = 0xFF;
113
					} else {
114
						dst[0] = (sample&0xFF);
115
						sample >>= 8;
116
						dst[1] = (sample&0xFF);
117
					}
118
					src += 4;
119
					dst += 2;
120
				}
121
			}
122
		}
123
		break;
124
 
125
		case AUDIO_S16: {
126
			Uint8 *src, *dst;
127
 
128
			src = cvt->buf;
129
			dst = cvt->buf;
130
			if ( (format & 0x1000) == 0x1000 ) {
131
				for ( i=cvt->len_cvt/4; i; --i ) {
132
					sample = (Sint16)((src[0]<<8)|src[1])+
133
					         (Sint16)((src[2]<<8)|src[3]);
134
					if ( sample > 32767 ) {
135
						dst[0] = 0x7F;
136
						dst[1] = 0xFF;
137
					} else
138
					if ( sample < -32768 ) {
139
						dst[0] = 0x80;
140
						dst[1] = 0x00;
141
					} else {
142
						dst[1] = (sample&0xFF);
143
						sample >>= 8;
144
						dst[0] = (sample&0xFF);
145
					}
146
					src += 4;
147
					dst += 2;
148
				}
149
			} else {
150
				for ( i=cvt->len_cvt/4; i; --i ) {
151
					sample = (Sint16)((src[1]<<8)|src[0])+
152
					         (Sint16)((src[3]<<8)|src[2]);
153
					if ( sample > 32767 ) {
154
						dst[1] = 0x7F;
155
						dst[0] = 0xFF;
156
					} else
157
					if ( sample < -32768 ) {
158
						dst[1] = 0x80;
159
						dst[0] = 0x00;
160
					} else {
161
						dst[0] = (sample&0xFF);
162
						sample >>= 8;
163
						dst[1] = (sample&0xFF);
164
					}
165
					src += 4;
166
					dst += 2;
167
				}
168
			}
169
		}
170
		break;
171
	}
172
	cvt->len_cvt /= 2;
173
	if ( cvt->filters[++cvt->filter_index] ) {
174
		cvt->filters[cvt->filter_index](cvt, format);
175
	}
176
}
177
 
178
 
179
/* Duplicate a mono channel to both stereo channels */
180
void SDL_ConvertStereo(SDL_AudioCVT *cvt, Uint16 format)
181
{
182
	int i;
183
 
184
#ifdef DEBUG_CONVERT
185
	fprintf(stderr, "Converting to stereo\n");
186
#endif
187
	if ( (format & 0xFF) == 16 ) {
188
		Uint16 *src, *dst;
189
 
190
		src = (Uint16 *)(cvt->buf+cvt->len_cvt);
191
		dst = (Uint16 *)(cvt->buf+cvt->len_cvt*2);
192
		for ( i=cvt->len_cvt/2; i; --i ) {
193
			dst -= 2;
194
			src -= 1;
195
			dst[0] = src[0];
196
			dst[1] = src[0];
197
		}
198
	} else {
199
		Uint8 *src, *dst;
200
 
201
		src = cvt->buf+cvt->len_cvt;
202
		dst = cvt->buf+cvt->len_cvt*2;
203
		for ( i=cvt->len_cvt; i; --i ) {
204
			dst -= 2;
205
			src -= 1;
206
			dst[0] = src[0];
207
			dst[1] = src[0];
208
		}
209
	}
210
	cvt->len_cvt *= 2;
211
	if ( cvt->filters[++cvt->filter_index] ) {
212
		cvt->filters[cvt->filter_index](cvt, format);
213
	}
214
}
215
 
216
/* Convert 8-bit to 16-bit - LSB */
217
void SDL_Convert16LSB(SDL_AudioCVT *cvt, Uint16 format)
218
{
219
	int i;
220
	Uint8 *src, *dst;
221
 
222
#ifdef DEBUG_CONVERT
223
	fprintf(stderr, "Converting to 16-bit LSB\n");
224
#endif
225
	src = cvt->buf+cvt->len_cvt;
226
	dst = cvt->buf+cvt->len_cvt*2;
227
	for ( i=cvt->len_cvt; i; --i ) {
228
		src -= 1;
229
		dst -= 2;
230
		dst[1] = *src;
231
		dst[0] = 0;
232
	}
233
	format = ((format & ~0x0008) | AUDIO_U16LSB);
234
	cvt->len_cvt *= 2;
235
	if ( cvt->filters[++cvt->filter_index] ) {
236
		cvt->filters[cvt->filter_index](cvt, format);
237
	}
238
}
239
/* Convert 8-bit to 16-bit - MSB */
240
void SDL_Convert16MSB(SDL_AudioCVT *cvt, Uint16 format)
241
{
242
	int i;
243
	Uint8 *src, *dst;
244
 
245
#ifdef DEBUG_CONVERT
246
	fprintf(stderr, "Converting to 16-bit MSB\n");
247
#endif
248
	src = cvt->buf+cvt->len_cvt;
249
	dst = cvt->buf+cvt->len_cvt*2;
250
	for ( i=cvt->len_cvt; i; --i ) {
251
		src -= 1;
252
		dst -= 2;
253
		dst[0] = *src;
254
		dst[1] = 0;
255
	}
256
	format = ((format & ~0x0008) | AUDIO_U16MSB);
257
	cvt->len_cvt *= 2;
258
	if ( cvt->filters[++cvt->filter_index] ) {
259
		cvt->filters[cvt->filter_index](cvt, format);
260
	}
261
}
262
 
263
/* Convert 16-bit to 8-bit */
264
void SDL_Convert8(SDL_AudioCVT *cvt, Uint16 format)
265
{
266
	int i;
267
	Uint8 *src, *dst;
268
 
269
#ifdef DEBUG_CONVERT
270
	fprintf(stderr, "Converting to 8-bit\n");
271
#endif
272
	src = cvt->buf;
273
	dst = cvt->buf;
274
	if ( (format & 0x1000) != 0x1000 ) { /* Little endian */
275
		++src;
276
	}
277
	for ( i=cvt->len_cvt/2; i; --i ) {
278
		*dst = *src;
279
		src += 2;
280
		dst += 1;
281
	}
282
	format = ((format & ~0x9010) | AUDIO_U8);
283
	cvt->len_cvt /= 2;
284
	if ( cvt->filters[++cvt->filter_index] ) {
285
		cvt->filters[cvt->filter_index](cvt, format);
286
	}
287
}
288
 
289
/* Toggle signed/unsigned */
290
void SDL_ConvertSign(SDL_AudioCVT *cvt, Uint16 format)
291
{
292
	int i;
293
	Uint8 *data;
294
 
295
#ifdef DEBUG_CONVERT
296
	fprintf(stderr, "Converting audio signedness\n");
297
#endif
298
	data = cvt->buf;
299
	if ( (format & 0xFF) == 16 ) {
300
		if ( (format & 0x1000) != 0x1000 ) { /* Little endian */
301
			++data;
302
		}
303
		for ( i=cvt->len_cvt/2; i; --i ) {
304
			*data ^= 0x80;
305
			data += 2;
306
		}
307
	} else {
308
		for ( i=cvt->len_cvt; i; --i ) {
309
			*data++ ^= 0x80;
310
		}
311
	}
312
	format = (format ^ 0x8000);
313
	if ( cvt->filters[++cvt->filter_index] ) {
314
		cvt->filters[cvt->filter_index](cvt, format);
315
	}
316
}
317
 
318
/* Toggle endianness */
319
void SDL_ConvertEndian(SDL_AudioCVT *cvt, Uint16 format)
320
{
321
	int i;
322
	Uint8 *data, tmp;
323
 
324
#ifdef DEBUG_CONVERT
325
	fprintf(stderr, "Converting audio endianness\n");
326
#endif
327
	data = cvt->buf;
328
	for ( i=cvt->len_cvt/2; i; --i ) {
329
		tmp = data[0];
330
		data[0] = data[1];
331
		data[1] = tmp;
332
		data += 2;
333
	}
334
	format = (format ^ 0x1000);
335
	if ( cvt->filters[++cvt->filter_index] ) {
336
		cvt->filters[cvt->filter_index](cvt, format);
337
	}
338
}
339
 
340
/* Convert rate up by multiple of 2 */
341
void SDL_RateMUL2(SDL_AudioCVT *cvt, Uint16 format)
342
{
343
	int i;
344
	Uint8 *src, *dst;
345
 
346
#ifdef DEBUG_CONVERT
347
	fprintf(stderr, "Converting audio rate * 2\n");
348
#endif
349
	src = cvt->buf+cvt->len_cvt;
350
	dst = cvt->buf+cvt->len_cvt*2;
351
	switch (format & 0xFF) {
352
		case 8:
353
			for ( i=cvt->len_cvt; i; --i ) {
354
				src -= 1;
355
				dst -= 2;
356
				dst[0] = src[0];
357
				dst[1] = src[0];
358
			}
359
			break;
360
		case 16:
361
			for ( i=cvt->len_cvt/2; i; --i ) {
362
				src -= 2;
363
				dst -= 4;
364
				dst[0] = src[0];
365
				dst[1] = src[1];
366
				dst[2] = src[0];
367
				dst[3] = src[1];
368
			}
369
			break;
370
	}
371
	cvt->len_cvt *= 2;
372
	if ( cvt->filters[++cvt->filter_index] ) {
373
		cvt->filters[cvt->filter_index](cvt, format);
374
	}
375
}
376
 
377
/* Convert rate down by multiple of 2 */
378
void SDL_RateDIV2(SDL_AudioCVT *cvt, Uint16 format)
379
{
380
	int i;
381
	Uint8 *src, *dst;
382
 
383
#ifdef DEBUG_CONVERT
384
	fprintf(stderr, "Converting audio rate / 2\n");
385
#endif
386
	src = cvt->buf;
387
	dst = cvt->buf;
388
	switch (format & 0xFF) {
389
		case 8:
390
			for ( i=cvt->len_cvt/2; i; --i ) {
391
				dst[0] = src[0];
392
				src += 2;
393
				dst += 1;
394
			}
395
			break;
396
		case 16:
397
			for ( i=cvt->len_cvt/4; i; --i ) {
398
				dst[0] = src[0];
399
				dst[1] = src[1];
400
				src += 4;
401
				dst += 2;
402
			}
403
			break;
404
	}
405
	cvt->len_cvt /= 2;
406
	if ( cvt->filters[++cvt->filter_index] ) {
407
		cvt->filters[cvt->filter_index](cvt, format);
408
	}
409
}
410
 
411
/* Very slow rate conversion routine */
412
void SDL_RateSLOW(SDL_AudioCVT *cvt, Uint16 format)
413
{
414
	double ipos;
415
	int i, clen;
416
 
417
#ifdef DEBUG_CONVERT
418
	fprintf(stderr, "Converting audio rate * %4.4f\n", 1.0/cvt->rate_incr);
419
#endif
420
	clen = (int)((double)cvt->len_cvt / cvt->rate_incr);
421
	if ( cvt->rate_incr > 1.0 ) {
422
		switch (format & 0xFF) {
423
			case 8: {
424
				Uint8 *output;
425
 
426
				output = cvt->buf;
427
				ipos = 0.0;
428
				for ( i=clen; i; --i ) {
429
					*output = cvt->buf[(int)ipos];
430
					ipos += cvt->rate_incr;
431
					output += 1;
432
				}
433
			}
434
			break;
435
 
436
			case 16: {
437
				Uint16 *output;
438
 
439
				clen &= ~1;
440
				output = (Uint16 *)cvt->buf;
441
				ipos = 0.0;
442
				for ( i=clen/2; i; --i ) {
443
					*output=((Uint16 *)cvt->buf)[(int)ipos];
444
					ipos += cvt->rate_incr;
445
					output += 1;
446
				}
447
			}
448
			break;
449
		}
450
	} else {
451
		switch (format & 0xFF) {
452
			case 8: {
453
				Uint8 *output;
454
 
455
				output = cvt->buf+clen;
456
				ipos = (double)cvt->len_cvt;
457
				for ( i=clen; i; --i ) {
458
					ipos -= cvt->rate_incr;
459
					output -= 1;
460
					*output = cvt->buf[(int)ipos];
461
				}
462
			}
463
			break;
464
 
465
			case 16: {
466
				Uint16 *output;
467
 
468
				clen &= ~1;
469
				output = (Uint16 *)(cvt->buf+clen);
470
				ipos = (double)cvt->len_cvt/2;
471
				for ( i=clen/2; i; --i ) {
472
					ipos -= cvt->rate_incr;
473
					output -= 1;
474
					*output=((Uint16 *)cvt->buf)[(int)ipos];
475
				}
476
			}
477
			break;
478
		}
479
	}
480
	cvt->len_cvt = clen;
481
	if ( cvt->filters[++cvt->filter_index] ) {
482
		cvt->filters[cvt->filter_index](cvt, format);
483
	}
484
}
485
 
486
int SDL_ConvertAudio(SDL_AudioCVT *cvt)
487
{
488
	/* Make sure there's data to convert */
489
	if ( cvt->buf == NULL ) {
490
		SDL_SetError("No buffer allocated for conversion");
491
		return(-1);
492
	}
493
	/* Return okay if no conversion is necessary */
494
	cvt->len_cvt = cvt->len;
495
	if ( cvt->filters[0] == NULL ) {
496
		return(0);
497
	}
498
 
499
	/* Set up the conversion and go! */
500
	cvt->filter_index = 0;
501
	cvt->filters[0](cvt, cvt->src_format);
502
	return(0);
503
}
504
 
505
/* Creates a set of audio filters to convert from one format to another.
506
   Returns -1 if the format conversion is not supported, or 1 if the
507
   audio filter is set up.
508
*/
509
 
510
int SDL_BuildAudioCVT(SDL_AudioCVT *cvt,
511
	Uint16 src_format, Uint8 src_channels, int src_rate,
512
	Uint16 dst_format, Uint8 dst_channels, int dst_rate)
513
{
514
	/* Start off with no conversion necessary */
515
	cvt->needed = 0;
516
	cvt->filter_index = 0;
517
	cvt->filters[0] = NULL;
518
	cvt->len_mult = 1;
519
	cvt->len_ratio = 1.0;
520
 
521
	/* First filter:  Endian conversion from src to dst */
522
	if ( (src_format & 0x1000) != (dst_format & 0x1000)
523
	     && ((src_format & 0xff) != 8) ) {
524
		cvt->filters[cvt->filter_index++] = SDL_ConvertEndian;
525
	}
526
 
527
	/* Second filter: Sign conversion -- signed/unsigned */
528
	if ( (src_format & 0x8000) != (dst_format & 0x8000) ) {
529
		cvt->filters[cvt->filter_index++] = SDL_ConvertSign;
530
	}
531
 
532
	/* Next filter:  Convert 16 bit <--> 8 bit PCM */
533
	if ( (src_format & 0xFF) != (dst_format & 0xFF) ) {
534
		switch (dst_format&0x10FF) {
535
			case AUDIO_U8:
536
				cvt->filters[cvt->filter_index++] =
537
							 SDL_Convert8;
538
				cvt->len_ratio /= 2;
539
				break;
540
			case AUDIO_U16LSB:
541
				cvt->filters[cvt->filter_index++] =
542
							SDL_Convert16LSB;
543
				cvt->len_mult *= 2;
544
				cvt->len_ratio *= 2;
545
				break;
546
			case AUDIO_U16MSB:
547
				cvt->filters[cvt->filter_index++] =
548
							SDL_Convert16MSB;
549
				cvt->len_mult *= 2;
550
				cvt->len_ratio *= 2;
551
				break;
552
		}
553
	}
554
 
555
	/* Last filter:  Mono/Stereo conversion */
556
	if ( src_channels != dst_channels ) {
557
		while ( (src_channels*2) <= dst_channels ) {
558
			cvt->filters[cvt->filter_index++] =
559
						SDL_ConvertStereo;
560
			cvt->len_mult *= 2;
561
			src_channels *= 2;
562
			cvt->len_ratio *= 2;
563
		}
564
		/* This assumes that 4 channel audio is in the format:
565
		     Left {front/back} + Right {front/back}
566
		   so converting to L/R stereo works properly.
567
		 */
568
		while ( ((src_channels%2) == 0) &&
569
				((src_channels/2) >= dst_channels) ) {
570
			cvt->filters[cvt->filter_index++] =
571
						 SDL_ConvertMono;
572
			src_channels /= 2;
573
			cvt->len_ratio /= 2;
574
		}
575
		if ( src_channels != dst_channels ) {
576
			/* Uh oh.. */;
577
		}
578
	}
579
 
580
	/* Do rate conversion */
581
	cvt->rate_incr = 0.0;
582
	if ( (src_rate/100) != (dst_rate/100) ) {
583
		Uint32 hi_rate, lo_rate;
584
		int len_mult;
585
		double len_ratio;
586
		void (*rate_cvt)(SDL_AudioCVT *cvt, Uint16 format);
587
 
588
		if ( src_rate > dst_rate ) {
589
			hi_rate = src_rate;
590
			lo_rate = dst_rate;
591
			rate_cvt = SDL_RateDIV2;
592
			len_mult = 1;
593
			len_ratio = 0.5;
594
		} else {
595
			hi_rate = dst_rate;
596
			lo_rate = src_rate;
597
			rate_cvt = SDL_RateMUL2;
598
			len_mult = 2;
599
			len_ratio = 2.0;
600
		}
601
		/* If hi_rate = lo_rate*2^x then conversion is easy */
602
		while ( ((lo_rate*2)/100) <= (hi_rate/100) ) {
603
			cvt->filters[cvt->filter_index++] = rate_cvt;
604
			cvt->len_mult *= len_mult;
605
			lo_rate *= 2;
606
			cvt->len_ratio *= len_ratio;
607
		}
608
		/* We may need a slow conversion here to finish up */
609
		if ( (lo_rate/100) != (hi_rate/100) ) {
610
#if 1
611
			/* The problem with this is that if the input buffer is
612
			   say 1K, and the conversion rate is say 1.1, then the
613
			   output buffer is 1.1K, which may not be an acceptable
614
			   buffer size for the audio driver (not a power of 2)
615
			*/
616
			/* For now, punt and hope the rate distortion isn't great.
617
			*/
618
#else
619
			if ( src_rate < dst_rate ) {
620
				cvt->rate_incr = (double)lo_rate/hi_rate;
621
				cvt->len_mult *= 2;
622
				cvt->len_ratio /= cvt->rate_incr;
623
			} else {
624
				cvt->rate_incr = (double)hi_rate/lo_rate;
625
				cvt->len_ratio *= cvt->rate_incr;
626
			}
627
			cvt->filters[cvt->filter_index++] = SDL_RateSLOW;
628
#endif
629
		}
630
	}
631
 
632
	/* Set up the filter information */
633
	if ( cvt->filter_index != 0 ) {
634
		cvt->needed = 1;
635
		cvt->src_format = src_format;
636
		cvt->dst_format = dst_format;
637
		cvt->len = 0;
638
		cvt->buf = NULL;
639
		cvt->filters[cvt->filter_index] = NULL;
640
	}
641
	return(cvt->needed);
642
}