src/audio/SDL_audiocvt.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 21 Aug 2004 12:27:02 +0000
changeset 942 41a59de7f2ed
parent 769 b8d311d90021
child 1011 4095d9ca23f2
permissions -rw-r--r--
Here are patches for SDL12 and SDL_mixer for 4 or 6 channel
surround sound on Linux using the Alsa driver. To use them, naturally
you need a sound card that will do 4 or 6 channels and probably also a
recent version of the Alsa drivers and library. Since the only SDL
output driver that knows about surround sound is the Alsa driver,
you���ll want to choose it, using:

export SDL_AUDIODRIVER=alsa

There are no syntactic changes to the programming API. No new
library calls, no differences in arguments.

There are two semantic changes:

(1) For library calls with number of channels as an argument, formerly
you could use only 1 or 2 for the number of channels. Now you
can also use 4 or 6.

(2) The two "left" and "right" arguments to Mix_SetPanning, for the
case of 4 or 6 channels, no longer simply control the volumes of
the left and right channels. Now the "left" argument is converted
to an angle and Mix_SetPosition is called, and the "right" argu-
ment is ignored.

With two exceptions, so far as I know, the modified SDL12 and
SDL_mixer work the same way as the original versions, when opened for
1 or 2 channel output. The two exceptions are bugs which I fixed.
Well, the first, anyway, is a bug for sure. When rate conversions up
or down by a factor of two are applied (in src/audio/SDL_audiocvt.c),
streams with different numbers of channels (that is, mono and stereo)
are treated the same way: either each sample is copied or every other
sample is omitted. This is ok for mono, but for stereo, it is frames
that should be copied or omitted, where by "frame" I mean a portion of
the stream containing one sample for each channel. (In the SDL source,
confusingly, sometimes frames are called "samples".) So for these
rate conversions, stereo streams have to be treated differently, and
they are, in my modified version.

The other problem that might be characterized as a bug arises
when SDL_mixer is passed a multichannel chunk which does not have an
integral number of frames. Due to the way the effect_position code
loops over frames, when the chunk ends with a partial frame, memory
outside the chunk buffer will be accessed. In the case of stereo,
it���s possible that because malloc may give more memory than requested,
this potential problem never actually causes a segment fault. I don���t
know. For 6 channel chunks, I do know, and it does cause segment
faults.


If SDL_mixer is passed defective chunks and this causes a segment
fault, arguably, that���s not a bug in SDL_mixer. Still, whether or not
it counts as a bug, it���s easy to protect against, so why not? I added
code in mixer.c to discard any partial frame at the end of a chunk.

Then what about when SDL or SDL_mixer is opened for 4 or 6 chan-
nel output? What happens with the parts of the current library
designed for stereo? I don���t know whether I���ve covered all the bases,
but I���ve tried:

(1) For playing 2 channel waves, or other cases where SDL knows it has
to match up a 2 channel source with a 4 or 6 channel output, I���ve
added code in SDL_audiocvt.c to make the necessary conversions.

(2) For playing midis using timidity, I���ve converted timidity to do 4
or 6 channel output, upon request.

(3) For playing mods using mikmod, I put ad hoc code in music.c to
convert the stereo output that mikmod produces to 4 or 6 chan-
nels. Obviously it would be better to change the mikmod code to
mix down into 4 or 6 channels, but I have a hard time following
the code in mikmod, so I didn���t do that.

(4) For playing mp3s, I put ad hoc code in smpeg to copy channels in
the case when 4 or 6 channel output is needed.

(5) There seems to be no problem with .ogg files - stereo .oggs can be
up converted as .wavs are.

(6) The effect_position code in SDL_mixer is now generalized to in-
clude the cases of 4 and 6 channel streams.

I���ve done a very limited amount of compatibility testing for some
of the games using SDL I happen to have. For details, see the file
TESTS.

I���ve put into a separate archive, Surround-SDL-testfiles.tgz, a
couple of 6 channel wave files for testing and a 6 channel ogg file.
If you have the right hardware and version of Alsa, you should be able
to play the wave files with the Alsa utility aplay (and hear all
channels, except maybe lfe, for chan-id.wav, since it���s rather faint).
Don���t expect aplay to give good sound, though. There���s something
wrong with the current version of aplay.

The canyon.ogg file is to test loading of 6 channel oggs. After
patching and compiling, you can play it with playmus. (My version of
ogg123 will not play it, and I had to patch mplayer to get it to play
6 channel oggs.)

Greg Lee <greg@ling.lll.hawaii.edu>
Thus, July 1, 2004
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@769
     3
    Copyright (C) 1997-2004 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@0
     6
    modify it under the terms of the GNU Library General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@0
     8
    version 2 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@0
    13
    Library General Public License for more details.
slouken@0
    14
slouken@0
    15
    You should have received a copy of the GNU Library General Public
slouken@0
    16
    License along with this library; if not, write to the Free
slouken@0
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@0
    22
slouken@0
    23
#ifdef SAVE_RCSID
slouken@0
    24
static char rcsid =
slouken@0
    25
 "@(#) $Id$";
slouken@0
    26
#endif
slouken@0
    27
slouken@0
    28
/* Functions for audio drivers to perform runtime conversion of audio format */
slouken@0
    29
slouken@0
    30
#include <stdio.h>
slouken@0
    31
slouken@0
    32
#include "SDL_error.h"
slouken@0
    33
#include "SDL_audio.h"
slouken@0
    34
slouken@0
    35
slouken@0
    36
/* Effectively mix right and left channels into a single channel */
slouken@0
    37
void SDL_ConvertMono(SDL_AudioCVT *cvt, Uint16 format)
slouken@0
    38
{
slouken@0
    39
	int i;
slouken@0
    40
	Sint32 sample;
slouken@0
    41
slouken@0
    42
#ifdef DEBUG_CONVERT
slouken@0
    43
	fprintf(stderr, "Converting to mono\n");
slouken@0
    44
#endif
slouken@0
    45
	switch (format&0x8018) {
slouken@0
    46
slouken@0
    47
		case AUDIO_U8: {
slouken@0
    48
			Uint8 *src, *dst;
slouken@0
    49
slouken@0
    50
			src = cvt->buf;
slouken@0
    51
			dst = cvt->buf;
slouken@0
    52
			for ( i=cvt->len_cvt/2; i; --i ) {
slouken@0
    53
				sample = src[0] + src[1];
slouken@0
    54
				if ( sample > 255 ) {
slouken@0
    55
					*dst = 255;
slouken@0
    56
				} else {
slouken@0
    57
					*dst = sample;
slouken@0
    58
				}
slouken@0
    59
				src += 2;
slouken@0
    60
				dst += 1;
slouken@0
    61
			}
slouken@0
    62
		}
slouken@0
    63
		break;
slouken@0
    64
slouken@0
    65
		case AUDIO_S8: {
slouken@0
    66
			Sint8 *src, *dst;
slouken@0
    67
slouken@0
    68
			src = (Sint8 *)cvt->buf;
slouken@0
    69
			dst = (Sint8 *)cvt->buf;
slouken@0
    70
			for ( i=cvt->len_cvt/2; i; --i ) {
slouken@0
    71
				sample = src[0] + src[1];
slouken@0
    72
				if ( sample > 127 ) {
slouken@0
    73
					*dst = 127;
slouken@0
    74
				} else
slouken@0
    75
				if ( sample < -128 ) {
slouken@0
    76
					*dst = -128;
slouken@0
    77
				} else {
slouken@0
    78
					*dst = sample;
slouken@0
    79
				}
slouken@0
    80
				src += 2;
slouken@0
    81
				dst += 1;
slouken@0
    82
			}
slouken@0
    83
		}
slouken@0
    84
		break;
slouken@0
    85
slouken@0
    86
		case AUDIO_U16: {
slouken@0
    87
			Uint8 *src, *dst;
slouken@0
    88
slouken@0
    89
			src = cvt->buf;
slouken@0
    90
			dst = cvt->buf;
slouken@0
    91
			if ( (format & 0x1000) == 0x1000 ) {
slouken@0
    92
				for ( i=cvt->len_cvt/4; i; --i ) {
slouken@0
    93
					sample = (Uint16)((src[0]<<8)|src[1])+
slouken@0
    94
					         (Uint16)((src[2]<<8)|src[3]);
slouken@0
    95
					if ( sample > 65535 ) {
slouken@0
    96
						dst[0] = 0xFF;
slouken@0
    97
						dst[1] = 0xFF;
slouken@0
    98
					} else {
slouken@0
    99
						dst[1] = (sample&0xFF);
slouken@0
   100
						sample >>= 8;
slouken@0
   101
						dst[0] = (sample&0xFF);
slouken@0
   102
					}
slouken@0
   103
					src += 4;
slouken@0
   104
					dst += 2;
slouken@0
   105
				}
slouken@0
   106
			} else {
slouken@0
   107
				for ( i=cvt->len_cvt/4; i; --i ) {
slouken@0
   108
					sample = (Uint16)((src[1]<<8)|src[0])+
slouken@0
   109
					         (Uint16)((src[3]<<8)|src[2]);
slouken@0
   110
					if ( sample > 65535 ) {
slouken@0
   111
						dst[0] = 0xFF;
slouken@0
   112
						dst[1] = 0xFF;
slouken@0
   113
					} else {
slouken@0
   114
						dst[0] = (sample&0xFF);
slouken@0
   115
						sample >>= 8;
slouken@0
   116
						dst[1] = (sample&0xFF);
slouken@0
   117
					}
slouken@0
   118
					src += 4;
slouken@0
   119
					dst += 2;
slouken@0
   120
				}
slouken@0
   121
			}
slouken@0
   122
		}
slouken@0
   123
		break;
slouken@0
   124
slouken@0
   125
		case AUDIO_S16: {
slouken@0
   126
			Uint8 *src, *dst;
slouken@0
   127
slouken@0
   128
			src = cvt->buf;
slouken@0
   129
			dst = cvt->buf;
slouken@0
   130
			if ( (format & 0x1000) == 0x1000 ) {
slouken@0
   131
				for ( i=cvt->len_cvt/4; i; --i ) {
slouken@0
   132
					sample = (Sint16)((src[0]<<8)|src[1])+
slouken@0
   133
					         (Sint16)((src[2]<<8)|src[3]);
slouken@0
   134
					if ( sample > 32767 ) {
slouken@0
   135
						dst[0] = 0x7F;
slouken@0
   136
						dst[1] = 0xFF;
slouken@0
   137
					} else
slouken@0
   138
					if ( sample < -32768 ) {
slouken@0
   139
						dst[0] = 0x80;
slouken@0
   140
						dst[1] = 0x00;
slouken@0
   141
					} else {
slouken@0
   142
						dst[1] = (sample&0xFF);
slouken@0
   143
						sample >>= 8;
slouken@0
   144
						dst[0] = (sample&0xFF);
slouken@0
   145
					}
slouken@0
   146
					src += 4;
slouken@0
   147
					dst += 2;
slouken@0
   148
				}
slouken@0
   149
			} else {
slouken@0
   150
				for ( i=cvt->len_cvt/4; i; --i ) {
slouken@0
   151
					sample = (Sint16)((src[1]<<8)|src[0])+
slouken@0
   152
					         (Sint16)((src[3]<<8)|src[2]);
slouken@0
   153
					if ( sample > 32767 ) {
slouken@0
   154
						dst[1] = 0x7F;
slouken@0
   155
						dst[0] = 0xFF;
slouken@0
   156
					} else
slouken@0
   157
					if ( sample < -32768 ) {
slouken@0
   158
						dst[1] = 0x80;
slouken@0
   159
						dst[0] = 0x00;
slouken@0
   160
					} else {
slouken@0
   161
						dst[0] = (sample&0xFF);
slouken@0
   162
						sample >>= 8;
slouken@0
   163
						dst[1] = (sample&0xFF);
slouken@0
   164
					}
slouken@0
   165
					src += 4;
slouken@0
   166
					dst += 2;
slouken@0
   167
				}
slouken@0
   168
			}
slouken@0
   169
		}
slouken@0
   170
		break;
slouken@0
   171
	}
slouken@0
   172
	cvt->len_cvt /= 2;
slouken@0
   173
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@0
   174
		cvt->filters[cvt->filter_index](cvt, format);
slouken@0
   175
	}
slouken@0
   176
}
slouken@0
   177
slouken@942
   178
/* Discard top 4 channels */
slouken@942
   179
void SDL_ConvertStrip(SDL_AudioCVT *cvt, Uint16 format)
slouken@942
   180
{
slouken@942
   181
	int i;
slouken@942
   182
	Sint32 lsample, rsample;
slouken@942
   183
slouken@942
   184
#ifdef DEBUG_CONVERT
slouken@942
   185
	fprintf(stderr, "Converting down to stereo\n");
slouken@942
   186
#endif
slouken@942
   187
	switch (format&0x8018) {
slouken@942
   188
slouken@942
   189
		case AUDIO_U8: {
slouken@942
   190
			Uint8 *src, *dst;
slouken@942
   191
slouken@942
   192
			src = cvt->buf;
slouken@942
   193
			dst = cvt->buf;
slouken@942
   194
			for ( i=cvt->len_cvt/6; i; --i ) {
slouken@942
   195
				lsample = src[0];
slouken@942
   196
				rsample = src[1];
slouken@942
   197
				dst[0] = lsample;
slouken@942
   198
				dst[1] = rsample;
slouken@942
   199
				src += 6;
slouken@942
   200
				dst += 2;
slouken@942
   201
			}
slouken@942
   202
		}
slouken@942
   203
		break;
slouken@942
   204
slouken@942
   205
		case AUDIO_S8: {
slouken@942
   206
			Sint8 *src, *dst;
slouken@942
   207
slouken@942
   208
			src = (Sint8 *)cvt->buf;
slouken@942
   209
			dst = (Sint8 *)cvt->buf;
slouken@942
   210
			for ( i=cvt->len_cvt/6; i; --i ) {
slouken@942
   211
				lsample = src[0];
slouken@942
   212
				rsample = src[1];
slouken@942
   213
				dst[0] = lsample;
slouken@942
   214
				dst[1] = rsample;
slouken@942
   215
				src += 6;
slouken@942
   216
				dst += 2;
slouken@942
   217
			}
slouken@942
   218
		}
slouken@942
   219
		break;
slouken@942
   220
slouken@942
   221
		case AUDIO_U16: {
slouken@942
   222
			Uint8 *src, *dst;
slouken@942
   223
slouken@942
   224
			src = cvt->buf;
slouken@942
   225
			dst = cvt->buf;
slouken@942
   226
			if ( (format & 0x1000) == 0x1000 ) {
slouken@942
   227
				for ( i=cvt->len_cvt/12; i; --i ) {
slouken@942
   228
					lsample = (Uint16)((src[0]<<8)|src[1]);
slouken@942
   229
					rsample = (Uint16)((src[2]<<8)|src[3]);
slouken@942
   230
						dst[1] = (lsample&0xFF);
slouken@942
   231
						lsample >>= 8;
slouken@942
   232
						dst[0] = (lsample&0xFF);
slouken@942
   233
						dst[3] = (rsample&0xFF);
slouken@942
   234
						rsample >>= 8;
slouken@942
   235
						dst[2] = (rsample&0xFF);
slouken@942
   236
					src += 12;
slouken@942
   237
					dst += 4;
slouken@942
   238
				}
slouken@942
   239
			} else {
slouken@942
   240
				for ( i=cvt->len_cvt/12; i; --i ) {
slouken@942
   241
					lsample = (Uint16)((src[1]<<8)|src[0]);
slouken@942
   242
					rsample = (Uint16)((src[3]<<8)|src[2]);
slouken@942
   243
						dst[0] = (lsample&0xFF);
slouken@942
   244
						lsample >>= 8;
slouken@942
   245
						dst[1] = (lsample&0xFF);
slouken@942
   246
						dst[2] = (rsample&0xFF);
slouken@942
   247
						rsample >>= 8;
slouken@942
   248
						dst[3] = (rsample&0xFF);
slouken@942
   249
					src += 12;
slouken@942
   250
					dst += 4;
slouken@942
   251
				}
slouken@942
   252
			}
slouken@942
   253
		}
slouken@942
   254
		break;
slouken@942
   255
slouken@942
   256
		case AUDIO_S16: {
slouken@942
   257
			Uint8 *src, *dst;
slouken@942
   258
slouken@942
   259
			src = cvt->buf;
slouken@942
   260
			dst = cvt->buf;
slouken@942
   261
			if ( (format & 0x1000) == 0x1000 ) {
slouken@942
   262
				for ( i=cvt->len_cvt/12; i; --i ) {
slouken@942
   263
					lsample = (Sint16)((src[0]<<8)|src[1]);
slouken@942
   264
					rsample = (Sint16)((src[2]<<8)|src[3]);
slouken@942
   265
						dst[1] = (lsample&0xFF);
slouken@942
   266
						lsample >>= 8;
slouken@942
   267
						dst[0] = (lsample&0xFF);
slouken@942
   268
						dst[3] = (rsample&0xFF);
slouken@942
   269
						rsample >>= 8;
slouken@942
   270
						dst[2] = (rsample&0xFF);
slouken@942
   271
					src += 12;
slouken@942
   272
					dst += 4;
slouken@942
   273
				}
slouken@942
   274
			} else {
slouken@942
   275
				for ( i=cvt->len_cvt/12; i; --i ) {
slouken@942
   276
					lsample = (Sint16)((src[1]<<8)|src[0]);
slouken@942
   277
					rsample = (Sint16)((src[3]<<8)|src[2]);
slouken@942
   278
						dst[0] = (lsample&0xFF);
slouken@942
   279
						lsample >>= 8;
slouken@942
   280
						dst[1] = (lsample&0xFF);
slouken@942
   281
						dst[2] = (rsample&0xFF);
slouken@942
   282
						rsample >>= 8;
slouken@942
   283
						dst[3] = (rsample&0xFF);
slouken@942
   284
					src += 12;
slouken@942
   285
					dst += 4;
slouken@942
   286
				}
slouken@942
   287
			}
slouken@942
   288
		}
slouken@942
   289
		break;
slouken@942
   290
	}
slouken@942
   291
	cvt->len_cvt /= 3;
slouken@942
   292
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@942
   293
		cvt->filters[cvt->filter_index](cvt, format);
slouken@942
   294
	}
slouken@942
   295
}
slouken@942
   296
slouken@942
   297
slouken@942
   298
/* Discard top 2 channels of 6 */
slouken@942
   299
void SDL_ConvertStrip_2(SDL_AudioCVT *cvt, Uint16 format)
slouken@942
   300
{
slouken@942
   301
	int i;
slouken@942
   302
	Sint32 lsample, rsample;
slouken@942
   303
slouken@942
   304
#ifdef DEBUG_CONVERT
slouken@942
   305
	fprintf(stderr, "Converting 6 down to quad\n");
slouken@942
   306
#endif
slouken@942
   307
	switch (format&0x8018) {
slouken@942
   308
slouken@942
   309
		case AUDIO_U8: {
slouken@942
   310
			Uint8 *src, *dst;
slouken@942
   311
slouken@942
   312
			src = cvt->buf;
slouken@942
   313
			dst = cvt->buf;
slouken@942
   314
			for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
   315
				lsample = src[0];
slouken@942
   316
				rsample = src[1];
slouken@942
   317
				dst[0] = lsample;
slouken@942
   318
				dst[1] = rsample;
slouken@942
   319
				src += 4;
slouken@942
   320
				dst += 2;
slouken@942
   321
			}
slouken@942
   322
		}
slouken@942
   323
		break;
slouken@942
   324
slouken@942
   325
		case AUDIO_S8: {
slouken@942
   326
			Sint8 *src, *dst;
slouken@942
   327
slouken@942
   328
			src = (Sint8 *)cvt->buf;
slouken@942
   329
			dst = (Sint8 *)cvt->buf;
slouken@942
   330
			for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
   331
				lsample = src[0];
slouken@942
   332
				rsample = src[1];
slouken@942
   333
				dst[0] = lsample;
slouken@942
   334
				dst[1] = rsample;
slouken@942
   335
				src += 4;
slouken@942
   336
				dst += 2;
slouken@942
   337
			}
slouken@942
   338
		}
slouken@942
   339
		break;
slouken@942
   340
slouken@942
   341
		case AUDIO_U16: {
slouken@942
   342
			Uint8 *src, *dst;
slouken@942
   343
slouken@942
   344
			src = cvt->buf;
slouken@942
   345
			dst = cvt->buf;
slouken@942
   346
			if ( (format & 0x1000) == 0x1000 ) {
slouken@942
   347
				for ( i=cvt->len_cvt/8; i; --i ) {
slouken@942
   348
					lsample = (Uint16)((src[0]<<8)|src[1]);
slouken@942
   349
					rsample = (Uint16)((src[2]<<8)|src[3]);
slouken@942
   350
						dst[1] = (lsample&0xFF);
slouken@942
   351
						lsample >>= 8;
slouken@942
   352
						dst[0] = (lsample&0xFF);
slouken@942
   353
						dst[3] = (rsample&0xFF);
slouken@942
   354
						rsample >>= 8;
slouken@942
   355
						dst[2] = (rsample&0xFF);
slouken@942
   356
					src += 8;
slouken@942
   357
					dst += 4;
slouken@942
   358
				}
slouken@942
   359
			} else {
slouken@942
   360
				for ( i=cvt->len_cvt/8; i; --i ) {
slouken@942
   361
					lsample = (Uint16)((src[1]<<8)|src[0]);
slouken@942
   362
					rsample = (Uint16)((src[3]<<8)|src[2]);
slouken@942
   363
						dst[0] = (lsample&0xFF);
slouken@942
   364
						lsample >>= 8;
slouken@942
   365
						dst[1] = (lsample&0xFF);
slouken@942
   366
						dst[2] = (rsample&0xFF);
slouken@942
   367
						rsample >>= 8;
slouken@942
   368
						dst[3] = (rsample&0xFF);
slouken@942
   369
					src += 8;
slouken@942
   370
					dst += 4;
slouken@942
   371
				}
slouken@942
   372
			}
slouken@942
   373
		}
slouken@942
   374
		break;
slouken@942
   375
slouken@942
   376
		case AUDIO_S16: {
slouken@942
   377
			Uint8 *src, *dst;
slouken@942
   378
slouken@942
   379
			src = cvt->buf;
slouken@942
   380
			dst = cvt->buf;
slouken@942
   381
			if ( (format & 0x1000) == 0x1000 ) {
slouken@942
   382
				for ( i=cvt->len_cvt/8; i; --i ) {
slouken@942
   383
					lsample = (Sint16)((src[0]<<8)|src[1]);
slouken@942
   384
					rsample = (Sint16)((src[2]<<8)|src[3]);
slouken@942
   385
						dst[1] = (lsample&0xFF);
slouken@942
   386
						lsample >>= 8;
slouken@942
   387
						dst[0] = (lsample&0xFF);
slouken@942
   388
						dst[3] = (rsample&0xFF);
slouken@942
   389
						rsample >>= 8;
slouken@942
   390
						dst[2] = (rsample&0xFF);
slouken@942
   391
					src += 8;
slouken@942
   392
					dst += 4;
slouken@942
   393
				}
slouken@942
   394
			} else {
slouken@942
   395
				for ( i=cvt->len_cvt/8; i; --i ) {
slouken@942
   396
					lsample = (Sint16)((src[1]<<8)|src[0]);
slouken@942
   397
					rsample = (Sint16)((src[3]<<8)|src[2]);
slouken@942
   398
						dst[0] = (lsample&0xFF);
slouken@942
   399
						lsample >>= 8;
slouken@942
   400
						dst[1] = (lsample&0xFF);
slouken@942
   401
						dst[2] = (rsample&0xFF);
slouken@942
   402
						rsample >>= 8;
slouken@942
   403
						dst[3] = (rsample&0xFF);
slouken@942
   404
					src += 8;
slouken@942
   405
					dst += 4;
slouken@942
   406
				}
slouken@942
   407
			}
slouken@942
   408
		}
slouken@942
   409
		break;
slouken@942
   410
	}
slouken@942
   411
	cvt->len_cvt /= 2;
slouken@942
   412
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@942
   413
		cvt->filters[cvt->filter_index](cvt, format);
slouken@942
   414
	}
slouken@942
   415
}
slouken@0
   416
slouken@0
   417
/* Duplicate a mono channel to both stereo channels */
slouken@0
   418
void SDL_ConvertStereo(SDL_AudioCVT *cvt, Uint16 format)
slouken@0
   419
{
slouken@0
   420
	int i;
slouken@0
   421
slouken@0
   422
#ifdef DEBUG_CONVERT
slouken@0
   423
	fprintf(stderr, "Converting to stereo\n");
slouken@0
   424
#endif
slouken@0
   425
	if ( (format & 0xFF) == 16 ) {
slouken@0
   426
		Uint16 *src, *dst;
slouken@0
   427
slouken@0
   428
		src = (Uint16 *)(cvt->buf+cvt->len_cvt);
slouken@0
   429
		dst = (Uint16 *)(cvt->buf+cvt->len_cvt*2);
slouken@0
   430
		for ( i=cvt->len_cvt/2; i; --i ) {
slouken@0
   431
			dst -= 2;
slouken@0
   432
			src -= 1;
slouken@0
   433
			dst[0] = src[0];
slouken@0
   434
			dst[1] = src[0];
slouken@0
   435
		}
slouken@0
   436
	} else {
slouken@0
   437
		Uint8 *src, *dst;
slouken@0
   438
slouken@0
   439
		src = cvt->buf+cvt->len_cvt;
slouken@0
   440
		dst = cvt->buf+cvt->len_cvt*2;
slouken@0
   441
		for ( i=cvt->len_cvt; i; --i ) {
slouken@0
   442
			dst -= 2;
slouken@0
   443
			src -= 1;
slouken@0
   444
			dst[0] = src[0];
slouken@0
   445
			dst[1] = src[0];
slouken@0
   446
		}
slouken@0
   447
	}
slouken@0
   448
	cvt->len_cvt *= 2;
slouken@0
   449
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@0
   450
		cvt->filters[cvt->filter_index](cvt, format);
slouken@0
   451
	}
slouken@0
   452
}
slouken@0
   453
slouken@942
   454
slouken@942
   455
/* Duplicate a stereo channel to a pseudo-5.1 stream */
slouken@942
   456
void SDL_ConvertSurround(SDL_AudioCVT *cvt, Uint16 format)
slouken@942
   457
{
slouken@942
   458
	int i;
slouken@942
   459
slouken@942
   460
#ifdef DEBUG_CONVERT
slouken@942
   461
	fprintf(stderr, "Converting stereo to surround\n");
slouken@942
   462
#endif
slouken@942
   463
	switch (format&0x8018) {
slouken@942
   464
slouken@942
   465
		case AUDIO_U8: {
slouken@942
   466
			Uint8 *src, *dst, lf, rf, ce;
slouken@942
   467
slouken@942
   468
			src = (Uint8 *)(cvt->buf+cvt->len_cvt);
slouken@942
   469
			dst = (Uint8 *)(cvt->buf+cvt->len_cvt*3);
slouken@942
   470
			for ( i=cvt->len_cvt; i; --i ) {
slouken@942
   471
				dst -= 6;
slouken@942
   472
				src -= 2;
slouken@942
   473
				lf = src[0];
slouken@942
   474
				rf = src[1];
slouken@942
   475
				ce = (lf/2) + (rf/2);
slouken@942
   476
				dst[0] = lf;
slouken@942
   477
				dst[1] = rf;
slouken@942
   478
				dst[2] = lf - ce;
slouken@942
   479
				dst[3] = rf - ce;
slouken@942
   480
				dst[4] = ce;
slouken@942
   481
				dst[5] = ce;
slouken@942
   482
			}
slouken@942
   483
		}
slouken@942
   484
		break;
slouken@942
   485
slouken@942
   486
		case AUDIO_S8: {
slouken@942
   487
			Sint8 *src, *dst, lf, rf, ce;
slouken@942
   488
slouken@942
   489
			src = cvt->buf+cvt->len_cvt;
slouken@942
   490
			dst = cvt->buf+cvt->len_cvt*3;
slouken@942
   491
			for ( i=cvt->len_cvt; i; --i ) {
slouken@942
   492
				dst -= 6;
slouken@942
   493
				src -= 2;
slouken@942
   494
				lf = src[0];
slouken@942
   495
				rf = src[1];
slouken@942
   496
				ce = (lf/2) + (rf/2);
slouken@942
   497
				dst[0] = lf;
slouken@942
   498
				dst[1] = rf;
slouken@942
   499
				dst[2] = lf - ce;
slouken@942
   500
				dst[3] = rf - ce;
slouken@942
   501
				dst[4] = ce;
slouken@942
   502
				dst[5] = ce;
slouken@942
   503
			}
slouken@942
   504
		}
slouken@942
   505
		break;
slouken@942
   506
slouken@942
   507
		case AUDIO_U16: {
slouken@942
   508
			Uint8 *src, *dst;
slouken@942
   509
			Uint16 lf, rf, ce, lr, rr;
slouken@942
   510
slouken@942
   511
			src = cvt->buf+cvt->len_cvt;
slouken@942
   512
			dst = cvt->buf+cvt->len_cvt*3;
slouken@942
   513
slouken@942
   514
			if ( (format & 0x1000) == 0x1000 ) {
slouken@942
   515
				for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
   516
					dst -= 12;
slouken@942
   517
					src -= 4;
slouken@942
   518
					lf = (Uint16)((src[0]<<8)|src[1]);
slouken@942
   519
					rf = (Uint16)((src[2]<<8)|src[3]);
slouken@942
   520
					ce = (lf/2) + (rf/2);
slouken@942
   521
					rr = lf - ce;
slouken@942
   522
					lr = rf - ce;
slouken@942
   523
						dst[1] = (lf&0xFF);
slouken@942
   524
						dst[0] = ((lf>>8)&0xFF);
slouken@942
   525
						dst[3] = (rf&0xFF);
slouken@942
   526
						dst[2] = ((rf>>8)&0xFF);
slouken@942
   527
slouken@942
   528
						dst[1+4] = (lr&0xFF);
slouken@942
   529
						dst[0+4] = ((lr>>8)&0xFF);
slouken@942
   530
						dst[3+4] = (rr&0xFF);
slouken@942
   531
						dst[2+4] = ((rr>>8)&0xFF);
slouken@942
   532
slouken@942
   533
						dst[1+8] = (ce&0xFF);
slouken@942
   534
						dst[0+8] = ((ce>>8)&0xFF);
slouken@942
   535
						dst[3+8] = (ce&0xFF);
slouken@942
   536
						dst[2+8] = ((ce>>8)&0xFF);
slouken@942
   537
				}
slouken@942
   538
			} else {
slouken@942
   539
				for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
   540
					dst -= 12;
slouken@942
   541
					src -= 4;
slouken@942
   542
					lf = (Uint16)((src[1]<<8)|src[0]);
slouken@942
   543
					rf = (Uint16)((src[3]<<8)|src[2]);
slouken@942
   544
					ce = (lf/2) + (rf/2);
slouken@942
   545
					rr = lf - ce;
slouken@942
   546
					lr = rf - ce;
slouken@942
   547
						dst[0] = (lf&0xFF);
slouken@942
   548
						dst[1] = ((lf>>8)&0xFF);
slouken@942
   549
						dst[2] = (rf&0xFF);
slouken@942
   550
						dst[3] = ((rf>>8)&0xFF);
slouken@942
   551
slouken@942
   552
						dst[0+4] = (lr&0xFF);
slouken@942
   553
						dst[1+4] = ((lr>>8)&0xFF);
slouken@942
   554
						dst[2+4] = (rr&0xFF);
slouken@942
   555
						dst[3+4] = ((rr>>8)&0xFF);
slouken@942
   556
slouken@942
   557
						dst[0+8] = (ce&0xFF);
slouken@942
   558
						dst[1+8] = ((ce>>8)&0xFF);
slouken@942
   559
						dst[2+8] = (ce&0xFF);
slouken@942
   560
						dst[3+8] = ((ce>>8)&0xFF);
slouken@942
   561
				}
slouken@942
   562
			}
slouken@942
   563
		}
slouken@942
   564
		break;
slouken@942
   565
slouken@942
   566
		case AUDIO_S16: {
slouken@942
   567
			Uint8 *src, *dst;
slouken@942
   568
			Sint16 lf, rf, ce, lr, rr;
slouken@942
   569
slouken@942
   570
			src = cvt->buf+cvt->len_cvt;
slouken@942
   571
			dst = cvt->buf+cvt->len_cvt*3;
slouken@942
   572
slouken@942
   573
			if ( (format & 0x1000) == 0x1000 ) {
slouken@942
   574
				for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
   575
					dst -= 12;
slouken@942
   576
					src -= 4;
slouken@942
   577
					lf = (Sint16)((src[0]<<8)|src[1]);
slouken@942
   578
					rf = (Sint16)((src[2]<<8)|src[3]);
slouken@942
   579
					ce = (lf/2) + (rf/2);
slouken@942
   580
					rr = lf - ce;
slouken@942
   581
					lr = rf - ce;
slouken@942
   582
						dst[1] = (lf&0xFF);
slouken@942
   583
						dst[0] = ((lf>>8)&0xFF);
slouken@942
   584
						dst[3] = (rf&0xFF);
slouken@942
   585
						dst[2] = ((rf>>8)&0xFF);
slouken@942
   586
slouken@942
   587
						dst[1+4] = (lr&0xFF);
slouken@942
   588
						dst[0+4] = ((lr>>8)&0xFF);
slouken@942
   589
						dst[3+4] = (rr&0xFF);
slouken@942
   590
						dst[2+4] = ((rr>>8)&0xFF);
slouken@942
   591
slouken@942
   592
						dst[1+8] = (ce&0xFF);
slouken@942
   593
						dst[0+8] = ((ce>>8)&0xFF);
slouken@942
   594
						dst[3+8] = (ce&0xFF);
slouken@942
   595
						dst[2+8] = ((ce>>8)&0xFF);
slouken@942
   596
				}
slouken@942
   597
			} else {
slouken@942
   598
				for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
   599
					dst -= 12;
slouken@942
   600
					src -= 4;
slouken@942
   601
					lf = (Sint16)((src[1]<<8)|src[0]);
slouken@942
   602
					rf = (Sint16)((src[3]<<8)|src[2]);
slouken@942
   603
					ce = (lf/2) + (rf/2);
slouken@942
   604
					rr = lf - ce;
slouken@942
   605
					lr = rf - ce;
slouken@942
   606
						dst[0] = (lf&0xFF);
slouken@942
   607
						dst[1] = ((lf>>8)&0xFF);
slouken@942
   608
						dst[2] = (rf&0xFF);
slouken@942
   609
						dst[3] = ((rf>>8)&0xFF);
slouken@942
   610
slouken@942
   611
						dst[0+4] = (lr&0xFF);
slouken@942
   612
						dst[1+4] = ((lr>>8)&0xFF);
slouken@942
   613
						dst[2+4] = (rr&0xFF);
slouken@942
   614
						dst[3+4] = ((rr>>8)&0xFF);
slouken@942
   615
slouken@942
   616
						dst[0+8] = (ce&0xFF);
slouken@942
   617
						dst[1+8] = ((ce>>8)&0xFF);
slouken@942
   618
						dst[2+8] = (ce&0xFF);
slouken@942
   619
						dst[3+8] = ((ce>>8)&0xFF);
slouken@942
   620
				}
slouken@942
   621
			}
slouken@942
   622
		}
slouken@942
   623
		break;
slouken@942
   624
	}
slouken@942
   625
	cvt->len_cvt *= 3;
slouken@942
   626
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@942
   627
		cvt->filters[cvt->filter_index](cvt, format);
slouken@942
   628
	}
slouken@942
   629
}
slouken@942
   630
slouken@942
   631
slouken@942
   632
/* Duplicate a stereo channel to a pseudo-4.0 stream */
slouken@942
   633
void SDL_ConvertSurround_4(SDL_AudioCVT *cvt, Uint16 format)
slouken@942
   634
{
slouken@942
   635
	int i;
slouken@942
   636
slouken@942
   637
#ifdef DEBUG_CONVERT
slouken@942
   638
	fprintf(stderr, "Converting stereo to quad\n");
slouken@942
   639
#endif
slouken@942
   640
	switch (format&0x8018) {
slouken@942
   641
slouken@942
   642
		case AUDIO_U8: {
slouken@942
   643
			Uint8 *src, *dst, lf, rf, ce;
slouken@942
   644
slouken@942
   645
			src = (Uint8 *)(cvt->buf+cvt->len_cvt);
slouken@942
   646
			dst = (Uint8 *)(cvt->buf+cvt->len_cvt*2);
slouken@942
   647
			for ( i=cvt->len_cvt; i; --i ) {
slouken@942
   648
				dst -= 4;
slouken@942
   649
				src -= 2;
slouken@942
   650
				lf = src[0];
slouken@942
   651
				rf = src[1];
slouken@942
   652
				ce = (lf/2) + (rf/2);
slouken@942
   653
				dst[0] = lf;
slouken@942
   654
				dst[1] = rf;
slouken@942
   655
				dst[2] = lf - ce;
slouken@942
   656
				dst[3] = rf - ce;
slouken@942
   657
			}
slouken@942
   658
		}
slouken@942
   659
		break;
slouken@942
   660
slouken@942
   661
		case AUDIO_S8: {
slouken@942
   662
			Sint8 *src, *dst, lf, rf, ce;
slouken@942
   663
slouken@942
   664
			src = cvt->buf+cvt->len_cvt;
slouken@942
   665
			dst = cvt->buf+cvt->len_cvt*2;
slouken@942
   666
			for ( i=cvt->len_cvt; i; --i ) {
slouken@942
   667
				dst -= 4;
slouken@942
   668
				src -= 2;
slouken@942
   669
				lf = src[0];
slouken@942
   670
				rf = src[1];
slouken@942
   671
				ce = (lf/2) + (rf/2);
slouken@942
   672
				dst[0] = lf;
slouken@942
   673
				dst[1] = rf;
slouken@942
   674
				dst[2] = lf - ce;
slouken@942
   675
				dst[3] = rf - ce;
slouken@942
   676
			}
slouken@942
   677
		}
slouken@942
   678
		break;
slouken@942
   679
slouken@942
   680
		case AUDIO_U16: {
slouken@942
   681
			Uint8 *src, *dst;
slouken@942
   682
			Uint16 lf, rf, ce, lr, rr;
slouken@942
   683
slouken@942
   684
			src = cvt->buf+cvt->len_cvt;
slouken@942
   685
			dst = cvt->buf+cvt->len_cvt*2;
slouken@942
   686
slouken@942
   687
			if ( (format & 0x1000) == 0x1000 ) {
slouken@942
   688
				for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
   689
					dst -= 8;
slouken@942
   690
					src -= 4;
slouken@942
   691
					lf = (Uint16)((src[0]<<8)|src[1]);
slouken@942
   692
					rf = (Uint16)((src[2]<<8)|src[3]);
slouken@942
   693
					ce = (lf/2) + (rf/2);
slouken@942
   694
					rr = lf - ce;
slouken@942
   695
					lr = rf - ce;
slouken@942
   696
						dst[1] = (lf&0xFF);
slouken@942
   697
						dst[0] = ((lf>>8)&0xFF);
slouken@942
   698
						dst[3] = (rf&0xFF);
slouken@942
   699
						dst[2] = ((rf>>8)&0xFF);
slouken@942
   700
slouken@942
   701
						dst[1+4] = (lr&0xFF);
slouken@942
   702
						dst[0+4] = ((lr>>8)&0xFF);
slouken@942
   703
						dst[3+4] = (rr&0xFF);
slouken@942
   704
						dst[2+4] = ((rr>>8)&0xFF);
slouken@942
   705
				}
slouken@942
   706
			} else {
slouken@942
   707
				for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
   708
					dst -= 8;
slouken@942
   709
					src -= 4;
slouken@942
   710
					lf = (Uint16)((src[1]<<8)|src[0]);
slouken@942
   711
					rf = (Uint16)((src[3]<<8)|src[2]);
slouken@942
   712
					ce = (lf/2) + (rf/2);
slouken@942
   713
					rr = lf - ce;
slouken@942
   714
					lr = rf - ce;
slouken@942
   715
						dst[0] = (lf&0xFF);
slouken@942
   716
						dst[1] = ((lf>>8)&0xFF);
slouken@942
   717
						dst[2] = (rf&0xFF);
slouken@942
   718
						dst[3] = ((rf>>8)&0xFF);
slouken@942
   719
slouken@942
   720
						dst[0+4] = (lr&0xFF);
slouken@942
   721
						dst[1+4] = ((lr>>8)&0xFF);
slouken@942
   722
						dst[2+4] = (rr&0xFF);
slouken@942
   723
						dst[3+4] = ((rr>>8)&0xFF);
slouken@942
   724
				}
slouken@942
   725
			}
slouken@942
   726
		}
slouken@942
   727
		break;
slouken@942
   728
slouken@942
   729
		case AUDIO_S16: {
slouken@942
   730
			Uint8 *src, *dst;
slouken@942
   731
			Sint16 lf, rf, ce, lr, rr;
slouken@942
   732
slouken@942
   733
			src = cvt->buf+cvt->len_cvt;
slouken@942
   734
			dst = cvt->buf+cvt->len_cvt*2;
slouken@942
   735
slouken@942
   736
			if ( (format & 0x1000) == 0x1000 ) {
slouken@942
   737
				for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
   738
					dst -= 8;
slouken@942
   739
					src -= 4;
slouken@942
   740
					lf = (Sint16)((src[0]<<8)|src[1]);
slouken@942
   741
					rf = (Sint16)((src[2]<<8)|src[3]);
slouken@942
   742
					ce = (lf/2) + (rf/2);
slouken@942
   743
					rr = lf - ce;
slouken@942
   744
					lr = rf - ce;
slouken@942
   745
						dst[1] = (lf&0xFF);
slouken@942
   746
						dst[0] = ((lf>>8)&0xFF);
slouken@942
   747
						dst[3] = (rf&0xFF);
slouken@942
   748
						dst[2] = ((rf>>8)&0xFF);
slouken@942
   749
slouken@942
   750
						dst[1+4] = (lr&0xFF);
slouken@942
   751
						dst[0+4] = ((lr>>8)&0xFF);
slouken@942
   752
						dst[3+4] = (rr&0xFF);
slouken@942
   753
						dst[2+4] = ((rr>>8)&0xFF);
slouken@942
   754
				}
slouken@942
   755
			} else {
slouken@942
   756
				for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
   757
					dst -= 8;
slouken@942
   758
					src -= 4;
slouken@942
   759
					lf = (Sint16)((src[1]<<8)|src[0]);
slouken@942
   760
					rf = (Sint16)((src[3]<<8)|src[2]);
slouken@942
   761
					ce = (lf/2) + (rf/2);
slouken@942
   762
					rr = lf - ce;
slouken@942
   763
					lr = rf - ce;
slouken@942
   764
						dst[0] = (lf&0xFF);
slouken@942
   765
						dst[1] = ((lf>>8)&0xFF);
slouken@942
   766
						dst[2] = (rf&0xFF);
slouken@942
   767
						dst[3] = ((rf>>8)&0xFF);
slouken@942
   768
slouken@942
   769
						dst[0+4] = (lr&0xFF);
slouken@942
   770
						dst[1+4] = ((lr>>8)&0xFF);
slouken@942
   771
						dst[2+4] = (rr&0xFF);
slouken@942
   772
						dst[3+4] = ((rr>>8)&0xFF);
slouken@942
   773
				}
slouken@942
   774
			}
slouken@942
   775
		}
slouken@942
   776
		break;
slouken@942
   777
	}
slouken@942
   778
	cvt->len_cvt *= 2;
slouken@942
   779
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@942
   780
		cvt->filters[cvt->filter_index](cvt, format);
slouken@942
   781
	}
slouken@942
   782
}
slouken@942
   783
slouken@942
   784
slouken@0
   785
/* Convert 8-bit to 16-bit - LSB */
slouken@0
   786
void SDL_Convert16LSB(SDL_AudioCVT *cvt, Uint16 format)
slouken@0
   787
{
slouken@0
   788
	int i;
slouken@0
   789
	Uint8 *src, *dst;
slouken@0
   790
slouken@0
   791
#ifdef DEBUG_CONVERT
slouken@0
   792
	fprintf(stderr, "Converting to 16-bit LSB\n");
slouken@0
   793
#endif
slouken@0
   794
	src = cvt->buf+cvt->len_cvt;
slouken@0
   795
	dst = cvt->buf+cvt->len_cvt*2;
slouken@0
   796
	for ( i=cvt->len_cvt; i; --i ) {
slouken@0
   797
		src -= 1;
slouken@0
   798
		dst -= 2;
slouken@0
   799
		dst[1] = *src;
slouken@0
   800
		dst[0] = 0;
slouken@0
   801
	}
slouken@0
   802
	format = ((format & ~0x0008) | AUDIO_U16LSB);
slouken@0
   803
	cvt->len_cvt *= 2;
slouken@0
   804
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@0
   805
		cvt->filters[cvt->filter_index](cvt, format);
slouken@0
   806
	}
slouken@0
   807
}
slouken@0
   808
/* Convert 8-bit to 16-bit - MSB */
slouken@0
   809
void SDL_Convert16MSB(SDL_AudioCVT *cvt, Uint16 format)
slouken@0
   810
{
slouken@0
   811
	int i;
slouken@0
   812
	Uint8 *src, *dst;
slouken@0
   813
slouken@0
   814
#ifdef DEBUG_CONVERT
slouken@0
   815
	fprintf(stderr, "Converting to 16-bit MSB\n");
slouken@0
   816
#endif
slouken@0
   817
	src = cvt->buf+cvt->len_cvt;
slouken@0
   818
	dst = cvt->buf+cvt->len_cvt*2;
slouken@0
   819
	for ( i=cvt->len_cvt; i; --i ) {
slouken@0
   820
		src -= 1;
slouken@0
   821
		dst -= 2;
slouken@0
   822
		dst[0] = *src;
slouken@0
   823
		dst[1] = 0;
slouken@0
   824
	}
slouken@0
   825
	format = ((format & ~0x0008) | AUDIO_U16MSB);
slouken@0
   826
	cvt->len_cvt *= 2;
slouken@0
   827
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@0
   828
		cvt->filters[cvt->filter_index](cvt, format);
slouken@0
   829
	}
slouken@0
   830
}
slouken@0
   831
slouken@0
   832
/* Convert 16-bit to 8-bit */
slouken@0
   833
void SDL_Convert8(SDL_AudioCVT *cvt, Uint16 format)
slouken@0
   834
{
slouken@0
   835
	int i;
slouken@0
   836
	Uint8 *src, *dst;
slouken@0
   837
slouken@0
   838
#ifdef DEBUG_CONVERT
slouken@0
   839
	fprintf(stderr, "Converting to 8-bit\n");
slouken@0
   840
#endif
slouken@0
   841
	src = cvt->buf;
slouken@0
   842
	dst = cvt->buf;
slouken@0
   843
	if ( (format & 0x1000) != 0x1000 ) { /* Little endian */
slouken@0
   844
		++src;
slouken@0
   845
	}
slouken@0
   846
	for ( i=cvt->len_cvt/2; i; --i ) {
slouken@0
   847
		*dst = *src;
slouken@0
   848
		src += 2;
slouken@0
   849
		dst += 1;
slouken@0
   850
	}
slouken@0
   851
	format = ((format & ~0x9010) | AUDIO_U8);
slouken@0
   852
	cvt->len_cvt /= 2;
slouken@0
   853
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@0
   854
		cvt->filters[cvt->filter_index](cvt, format);
slouken@0
   855
	}
slouken@0
   856
}
slouken@0
   857
slouken@0
   858
/* Toggle signed/unsigned */
slouken@0
   859
void SDL_ConvertSign(SDL_AudioCVT *cvt, Uint16 format)
slouken@0
   860
{
slouken@0
   861
	int i;
slouken@0
   862
	Uint8 *data;
slouken@0
   863
slouken@0
   864
#ifdef DEBUG_CONVERT
slouken@0
   865
	fprintf(stderr, "Converting audio signedness\n");
slouken@0
   866
#endif
slouken@0
   867
	data = cvt->buf;
slouken@0
   868
	if ( (format & 0xFF) == 16 ) {
slouken@0
   869
		if ( (format & 0x1000) != 0x1000 ) { /* Little endian */
slouken@0
   870
			++data;
slouken@0
   871
		}
slouken@0
   872
		for ( i=cvt->len_cvt/2; i; --i ) {
slouken@0
   873
			*data ^= 0x80;
slouken@0
   874
			data += 2;
slouken@0
   875
		}
slouken@0
   876
	} else {
slouken@0
   877
		for ( i=cvt->len_cvt; i; --i ) {
slouken@0
   878
			*data++ ^= 0x80;
slouken@0
   879
		}
slouken@0
   880
	}
slouken@0
   881
	format = (format ^ 0x8000);
slouken@0
   882
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@0
   883
		cvt->filters[cvt->filter_index](cvt, format);
slouken@0
   884
	}
slouken@0
   885
}
slouken@0
   886
slouken@0
   887
/* Toggle endianness */
slouken@0
   888
void SDL_ConvertEndian(SDL_AudioCVT *cvt, Uint16 format)
slouken@0
   889
{
slouken@0
   890
	int i;
slouken@0
   891
	Uint8 *data, tmp;
slouken@0
   892
slouken@0
   893
#ifdef DEBUG_CONVERT
slouken@0
   894
	fprintf(stderr, "Converting audio endianness\n");
slouken@0
   895
#endif
slouken@0
   896
	data = cvt->buf;
slouken@0
   897
	for ( i=cvt->len_cvt/2; i; --i ) {
slouken@0
   898
		tmp = data[0];
slouken@0
   899
		data[0] = data[1];
slouken@0
   900
		data[1] = tmp;
slouken@0
   901
		data += 2;
slouken@0
   902
	}
slouken@0
   903
	format = (format ^ 0x1000);
slouken@0
   904
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@0
   905
		cvt->filters[cvt->filter_index](cvt, format);
slouken@0
   906
	}
slouken@0
   907
}
slouken@0
   908
slouken@0
   909
/* Convert rate up by multiple of 2 */
slouken@0
   910
void SDL_RateMUL2(SDL_AudioCVT *cvt, Uint16 format)
slouken@0
   911
{
slouken@0
   912
	int i;
slouken@0
   913
	Uint8 *src, *dst;
slouken@0
   914
slouken@0
   915
#ifdef DEBUG_CONVERT
slouken@0
   916
	fprintf(stderr, "Converting audio rate * 2\n");
slouken@0
   917
#endif
slouken@0
   918
	src = cvt->buf+cvt->len_cvt;
slouken@0
   919
	dst = cvt->buf+cvt->len_cvt*2;
slouken@0
   920
	switch (format & 0xFF) {
slouken@0
   921
		case 8:
slouken@0
   922
			for ( i=cvt->len_cvt; i; --i ) {
slouken@0
   923
				src -= 1;
slouken@0
   924
				dst -= 2;
slouken@0
   925
				dst[0] = src[0];
slouken@0
   926
				dst[1] = src[0];
slouken@0
   927
			}
slouken@0
   928
			break;
slouken@0
   929
		case 16:
slouken@0
   930
			for ( i=cvt->len_cvt/2; i; --i ) {
slouken@0
   931
				src -= 2;
slouken@0
   932
				dst -= 4;
slouken@0
   933
				dst[0] = src[0];
slouken@0
   934
				dst[1] = src[1];
slouken@0
   935
				dst[2] = src[0];
slouken@0
   936
				dst[3] = src[1];
slouken@0
   937
			}
slouken@0
   938
			break;
slouken@0
   939
	}
slouken@0
   940
	cvt->len_cvt *= 2;
slouken@0
   941
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@0
   942
		cvt->filters[cvt->filter_index](cvt, format);
slouken@0
   943
	}
slouken@0
   944
}
slouken@0
   945
slouken@942
   946
slouken@942
   947
/* Convert rate up by multiple of 2, for stereo */
slouken@942
   948
void SDL_RateMUL2_c2(SDL_AudioCVT *cvt, Uint16 format)
slouken@942
   949
{
slouken@942
   950
	int i;
slouken@942
   951
	Uint8 *src, *dst;
slouken@942
   952
slouken@942
   953
#ifdef DEBUG_CONVERT
slouken@942
   954
	fprintf(stderr, "Converting audio rate * 2\n");
slouken@942
   955
#endif
slouken@942
   956
	src = cvt->buf+cvt->len_cvt;
slouken@942
   957
	dst = cvt->buf+cvt->len_cvt*2;
slouken@942
   958
	switch (format & 0xFF) {
slouken@942
   959
		case 8:
slouken@942
   960
			for ( i=cvt->len_cvt/2; i; --i ) {
slouken@942
   961
				src -= 2;
slouken@942
   962
				dst -= 4;
slouken@942
   963
				dst[0] = src[0];
slouken@942
   964
				dst[1] = src[1];
slouken@942
   965
				dst[2] = src[0];
slouken@942
   966
				dst[3] = src[1];
slouken@942
   967
			}
slouken@942
   968
			break;
slouken@942
   969
		case 16:
slouken@942
   970
			for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
   971
				src -= 4;
slouken@942
   972
				dst -= 8;
slouken@942
   973
				dst[0] = src[0];
slouken@942
   974
				dst[1] = src[1];
slouken@942
   975
				dst[2] = src[2];
slouken@942
   976
				dst[3] = src[3];
slouken@942
   977
				dst[4] = src[0];
slouken@942
   978
				dst[5] = src[1];
slouken@942
   979
				dst[6] = src[2];
slouken@942
   980
				dst[7] = src[3];
slouken@942
   981
			}
slouken@942
   982
			break;
slouken@942
   983
	}
slouken@942
   984
	cvt->len_cvt *= 2;
slouken@942
   985
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@942
   986
		cvt->filters[cvt->filter_index](cvt, format);
slouken@942
   987
	}
slouken@942
   988
}
slouken@942
   989
slouken@942
   990
/* Convert rate up by multiple of 2, for quad */
slouken@942
   991
void SDL_RateMUL2_c4(SDL_AudioCVT *cvt, Uint16 format)
slouken@942
   992
{
slouken@942
   993
	int i;
slouken@942
   994
	Uint8 *src, *dst;
slouken@942
   995
slouken@942
   996
#ifdef DEBUG_CONVERT
slouken@942
   997
	fprintf(stderr, "Converting audio rate * 2\n");
slouken@942
   998
#endif
slouken@942
   999
	src = cvt->buf+cvt->len_cvt;
slouken@942
  1000
	dst = cvt->buf+cvt->len_cvt*2;
slouken@942
  1001
	switch (format & 0xFF) {
slouken@942
  1002
		case 8:
slouken@942
  1003
			for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
  1004
				src -= 4;
slouken@942
  1005
				dst -= 8;
slouken@942
  1006
				dst[0] = src[0];
slouken@942
  1007
				dst[1] = src[1];
slouken@942
  1008
				dst[2] = src[2];
slouken@942
  1009
				dst[3] = src[3];
slouken@942
  1010
				dst[4] = src[0];
slouken@942
  1011
				dst[5] = src[1];
slouken@942
  1012
				dst[6] = src[2];
slouken@942
  1013
				dst[7] = src[3];
slouken@942
  1014
			}
slouken@942
  1015
			break;
slouken@942
  1016
		case 16:
slouken@942
  1017
			for ( i=cvt->len_cvt/8; i; --i ) {
slouken@942
  1018
				src -= 8;
slouken@942
  1019
				dst -= 16;
slouken@942
  1020
				dst[0] = src[0];
slouken@942
  1021
				dst[1] = src[1];
slouken@942
  1022
				dst[2] = src[2];
slouken@942
  1023
				dst[3] = src[3];
slouken@942
  1024
				dst[4] = src[4];
slouken@942
  1025
				dst[5] = src[5];
slouken@942
  1026
				dst[6] = src[6];
slouken@942
  1027
				dst[7] = src[7];
slouken@942
  1028
				dst[8] = src[0];
slouken@942
  1029
				dst[9] = src[1];
slouken@942
  1030
				dst[10] = src[2];
slouken@942
  1031
				dst[11] = src[3];
slouken@942
  1032
				dst[12] = src[4];
slouken@942
  1033
				dst[13] = src[5];
slouken@942
  1034
				dst[14] = src[6];
slouken@942
  1035
				dst[15] = src[7];
slouken@942
  1036
			}
slouken@942
  1037
			break;
slouken@942
  1038
	}
slouken@942
  1039
	cvt->len_cvt *= 2;
slouken@942
  1040
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@942
  1041
		cvt->filters[cvt->filter_index](cvt, format);
slouken@942
  1042
	}
slouken@942
  1043
}
slouken@942
  1044
slouken@942
  1045
slouken@942
  1046
/* Convert rate up by multiple of 2, for 5.1 */
slouken@942
  1047
void SDL_RateMUL2_c6(SDL_AudioCVT *cvt, Uint16 format)
slouken@942
  1048
{
slouken@942
  1049
	int i;
slouken@942
  1050
	Uint8 *src, *dst;
slouken@942
  1051
slouken@942
  1052
#ifdef DEBUG_CONVERT
slouken@942
  1053
	fprintf(stderr, "Converting audio rate * 2\n");
slouken@942
  1054
#endif
slouken@942
  1055
	src = cvt->buf+cvt->len_cvt;
slouken@942
  1056
	dst = cvt->buf+cvt->len_cvt*2;
slouken@942
  1057
	switch (format & 0xFF) {
slouken@942
  1058
		case 8:
slouken@942
  1059
			for ( i=cvt->len_cvt/6; i; --i ) {
slouken@942
  1060
				src -= 6;
slouken@942
  1061
				dst -= 12;
slouken@942
  1062
				dst[0] = src[0];
slouken@942
  1063
				dst[1] = src[1];
slouken@942
  1064
				dst[2] = src[2];
slouken@942
  1065
				dst[3] = src[3];
slouken@942
  1066
				dst[4] = src[4];
slouken@942
  1067
				dst[5] = src[5];
slouken@942
  1068
				dst[6] = src[0];
slouken@942
  1069
				dst[7] = src[1];
slouken@942
  1070
				dst[8] = src[2];
slouken@942
  1071
				dst[9] = src[3];
slouken@942
  1072
				dst[10] = src[4];
slouken@942
  1073
				dst[11] = src[5];
slouken@942
  1074
			}
slouken@942
  1075
			break;
slouken@942
  1076
		case 16:
slouken@942
  1077
			for ( i=cvt->len_cvt/12; i; --i ) {
slouken@942
  1078
				src -= 12;
slouken@942
  1079
				dst -= 24;
slouken@942
  1080
				dst[0] = src[0];
slouken@942
  1081
				dst[1] = src[1];
slouken@942
  1082
				dst[2] = src[2];
slouken@942
  1083
				dst[3] = src[3];
slouken@942
  1084
				dst[4] = src[4];
slouken@942
  1085
				dst[5] = src[5];
slouken@942
  1086
				dst[6] = src[6];
slouken@942
  1087
				dst[7] = src[7];
slouken@942
  1088
				dst[8] = src[8];
slouken@942
  1089
				dst[9] = src[9];
slouken@942
  1090
				dst[10] = src[10];
slouken@942
  1091
				dst[11] = src[11];
slouken@942
  1092
				dst[12] = src[0];
slouken@942
  1093
				dst[13] = src[1];
slouken@942
  1094
				dst[14] = src[2];
slouken@942
  1095
				dst[15] = src[3];
slouken@942
  1096
				dst[16] = src[4];
slouken@942
  1097
				dst[17] = src[5];
slouken@942
  1098
				dst[18] = src[6];
slouken@942
  1099
				dst[19] = src[7];
slouken@942
  1100
				dst[20] = src[8];
slouken@942
  1101
				dst[21] = src[9];
slouken@942
  1102
				dst[22] = src[10];
slouken@942
  1103
				dst[23] = src[11];
slouken@942
  1104
			}
slouken@942
  1105
			break;
slouken@942
  1106
	}
slouken@942
  1107
	cvt->len_cvt *= 2;
slouken@942
  1108
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@942
  1109
		cvt->filters[cvt->filter_index](cvt, format);
slouken@942
  1110
	}
slouken@942
  1111
}
slouken@942
  1112
slouken@0
  1113
/* Convert rate down by multiple of 2 */
slouken@0
  1114
void SDL_RateDIV2(SDL_AudioCVT *cvt, Uint16 format)
slouken@0
  1115
{
slouken@0
  1116
	int i;
slouken@0
  1117
	Uint8 *src, *dst;
slouken@0
  1118
slouken@0
  1119
#ifdef DEBUG_CONVERT
slouken@0
  1120
	fprintf(stderr, "Converting audio rate / 2\n");
slouken@0
  1121
#endif
slouken@0
  1122
	src = cvt->buf;
slouken@0
  1123
	dst = cvt->buf;
slouken@0
  1124
	switch (format & 0xFF) {
slouken@0
  1125
		case 8:
slouken@0
  1126
			for ( i=cvt->len_cvt/2; i; --i ) {
slouken@0
  1127
				dst[0] = src[0];
slouken@0
  1128
				src += 2;
slouken@0
  1129
				dst += 1;
slouken@0
  1130
			}
slouken@0
  1131
			break;
slouken@0
  1132
		case 16:
slouken@0
  1133
			for ( i=cvt->len_cvt/4; i; --i ) {
slouken@0
  1134
				dst[0] = src[0];
slouken@0
  1135
				dst[1] = src[1];
slouken@0
  1136
				src += 4;
slouken@0
  1137
				dst += 2;
slouken@0
  1138
			}
slouken@0
  1139
			break;
slouken@0
  1140
	}
slouken@0
  1141
	cvt->len_cvt /= 2;
slouken@0
  1142
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@0
  1143
		cvt->filters[cvt->filter_index](cvt, format);
slouken@0
  1144
	}
slouken@0
  1145
}
slouken@0
  1146
slouken@942
  1147
slouken@942
  1148
/* Convert rate down by multiple of 2, for stereo */
slouken@942
  1149
void SDL_RateDIV2_c2(SDL_AudioCVT *cvt, Uint16 format)
slouken@942
  1150
{
slouken@942
  1151
	int i;
slouken@942
  1152
	Uint8 *src, *dst;
slouken@942
  1153
slouken@942
  1154
#ifdef DEBUG_CONVERT
slouken@942
  1155
	fprintf(stderr, "Converting audio rate / 2\n");
slouken@942
  1156
#endif
slouken@942
  1157
	src = cvt->buf;
slouken@942
  1158
	dst = cvt->buf;
slouken@942
  1159
	switch (format & 0xFF) {
slouken@942
  1160
		case 8:
slouken@942
  1161
			for ( i=cvt->len_cvt/4; i; --i ) {
slouken@942
  1162
				dst[0] = src[0];
slouken@942
  1163
				dst[1] = src[1];
slouken@942
  1164
				src += 4;
slouken@942
  1165
				dst += 2;
slouken@942
  1166
			}
slouken@942
  1167
			break;
slouken@942
  1168
		case 16:
slouken@942
  1169
			for ( i=cvt->len_cvt/8; i; --i ) {
slouken@942
  1170
				dst[0] = src[0];
slouken@942
  1171
				dst[1] = src[1];
slouken@942
  1172
				dst[2] = src[2];
slouken@942
  1173
				dst[3] = src[3];
slouken@942
  1174
				src += 8;
slouken@942
  1175
				dst += 4;
slouken@942
  1176
			}
slouken@942
  1177
			break;
slouken@942
  1178
	}
slouken@942
  1179
	cvt->len_cvt /= 2;
slouken@942
  1180
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@942
  1181
		cvt->filters[cvt->filter_index](cvt, format);
slouken@942
  1182
	}
slouken@942
  1183
}
slouken@942
  1184
slouken@942
  1185
slouken@942
  1186
/* Convert rate down by multiple of 2, for quad */
slouken@942
  1187
void SDL_RateDIV2_c4(SDL_AudioCVT *cvt, Uint16 format)
slouken@942
  1188
{
slouken@942
  1189
	int i;
slouken@942
  1190
	Uint8 *src, *dst;
slouken@942
  1191
slouken@942
  1192
#ifdef DEBUG_CONVERT
slouken@942
  1193
	fprintf(stderr, "Converting audio rate / 2\n");
slouken@942
  1194
#endif
slouken@942
  1195
	src = cvt->buf;
slouken@942
  1196
	dst = cvt->buf;
slouken@942
  1197
	switch (format & 0xFF) {
slouken@942
  1198
		case 8:
slouken@942
  1199
			for ( i=cvt->len_cvt/8; i; --i ) {
slouken@942
  1200
				dst[0] = src[0];
slouken@942
  1201
				dst[1] = src[1];
slouken@942
  1202
				dst[2] = src[2];
slouken@942
  1203
				dst[3] = src[3];
slouken@942
  1204
				src += 8;
slouken@942
  1205
				dst += 4;
slouken@942
  1206
			}
slouken@942
  1207
			break;
slouken@942
  1208
		case 16:
slouken@942
  1209
			for ( i=cvt->len_cvt/16; i; --i ) {
slouken@942
  1210
				dst[0] = src[0];
slouken@942
  1211
				dst[1] = src[1];
slouken@942
  1212
				dst[2] = src[2];
slouken@942
  1213
				dst[3] = src[3];
slouken@942
  1214
				dst[4] = src[4];
slouken@942
  1215
				dst[5] = src[5];
slouken@942
  1216
				dst[6] = src[6];
slouken@942
  1217
				dst[7] = src[7];
slouken@942
  1218
				src += 16;
slouken@942
  1219
				dst += 8;
slouken@942
  1220
			}
slouken@942
  1221
			break;
slouken@942
  1222
	}
slouken@942
  1223
	cvt->len_cvt /= 2;
slouken@942
  1224
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@942
  1225
		cvt->filters[cvt->filter_index](cvt, format);
slouken@942
  1226
	}
slouken@942
  1227
}
slouken@942
  1228
slouken@942
  1229
/* Convert rate down by multiple of 2, for 5.1 */
slouken@942
  1230
void SDL_RateDIV2_c6(SDL_AudioCVT *cvt, Uint16 format)
slouken@942
  1231
{
slouken@942
  1232
	int i;
slouken@942
  1233
	Uint8 *src, *dst;
slouken@942
  1234
slouken@942
  1235
#ifdef DEBUG_CONVERT
slouken@942
  1236
	fprintf(stderr, "Converting audio rate / 2\n");
slouken@942
  1237
#endif
slouken@942
  1238
	src = cvt->buf;
slouken@942
  1239
	dst = cvt->buf;
slouken@942
  1240
	switch (format & 0xFF) {
slouken@942
  1241
		case 8:
slouken@942
  1242
			for ( i=cvt->len_cvt/12; i; --i ) {
slouken@942
  1243
				dst[0] = src[0];
slouken@942
  1244
				dst[1] = src[1];
slouken@942
  1245
				dst[2] = src[2];
slouken@942
  1246
				dst[3] = src[3];
slouken@942
  1247
				dst[4] = src[4];
slouken@942
  1248
				dst[5] = src[5];
slouken@942
  1249
				src += 12;
slouken@942
  1250
				dst += 6;
slouken@942
  1251
			}
slouken@942
  1252
			break;
slouken@942
  1253
		case 16:
slouken@942
  1254
			for ( i=cvt->len_cvt/24; i; --i ) {
slouken@942
  1255
				dst[0] = src[0];
slouken@942
  1256
				dst[1] = src[1];
slouken@942
  1257
				dst[2] = src[2];
slouken@942
  1258
				dst[3] = src[3];
slouken@942
  1259
				dst[4] = src[4];
slouken@942
  1260
				dst[5] = src[5];
slouken@942
  1261
				dst[6] = src[6];
slouken@942
  1262
				dst[7] = src[7];
slouken@942
  1263
				dst[8] = src[8];
slouken@942
  1264
				dst[9] = src[9];
slouken@942
  1265
				dst[10] = src[10];
slouken@942
  1266
				dst[11] = src[11];
slouken@942
  1267
				src += 24;
slouken@942
  1268
				dst += 12;
slouken@942
  1269
			}
slouken@942
  1270
			break;
slouken@942
  1271
	}
slouken@942
  1272
	cvt->len_cvt /= 2;
slouken@942
  1273
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@942
  1274
		cvt->filters[cvt->filter_index](cvt, format);
slouken@942
  1275
	}
slouken@942
  1276
}
slouken@942
  1277
slouken@0
  1278
/* Very slow rate conversion routine */
slouken@0
  1279
void SDL_RateSLOW(SDL_AudioCVT *cvt, Uint16 format)
slouken@0
  1280
{
slouken@0
  1281
	double ipos;
slouken@0
  1282
	int i, clen;
slouken@0
  1283
slouken@0
  1284
#ifdef DEBUG_CONVERT
slouken@0
  1285
	fprintf(stderr, "Converting audio rate * %4.4f\n", 1.0/cvt->rate_incr);
slouken@0
  1286
#endif
slouken@0
  1287
	clen = (int)((double)cvt->len_cvt / cvt->rate_incr);
slouken@0
  1288
	if ( cvt->rate_incr > 1.0 ) {
slouken@0
  1289
		switch (format & 0xFF) {
slouken@0
  1290
			case 8: {
slouken@0
  1291
				Uint8 *output;
slouken@0
  1292
slouken@0
  1293
				output = cvt->buf;
slouken@0
  1294
				ipos = 0.0;
slouken@0
  1295
				for ( i=clen; i; --i ) {
slouken@0
  1296
					*output = cvt->buf[(int)ipos];
slouken@0
  1297
					ipos += cvt->rate_incr;
slouken@0
  1298
					output += 1;
slouken@0
  1299
				}
slouken@0
  1300
			}
slouken@0
  1301
			break;
slouken@0
  1302
slouken@0
  1303
			case 16: {
slouken@0
  1304
				Uint16 *output;
slouken@0
  1305
slouken@0
  1306
				clen &= ~1;
slouken@0
  1307
				output = (Uint16 *)cvt->buf;
slouken@0
  1308
				ipos = 0.0;
slouken@0
  1309
				for ( i=clen/2; i; --i ) {
slouken@0
  1310
					*output=((Uint16 *)cvt->buf)[(int)ipos];
slouken@0
  1311
					ipos += cvt->rate_incr;
slouken@0
  1312
					output += 1;
slouken@0
  1313
				}
slouken@0
  1314
			}
slouken@0
  1315
			break;
slouken@0
  1316
		}
slouken@0
  1317
	} else {
slouken@0
  1318
		switch (format & 0xFF) {
slouken@0
  1319
			case 8: {
slouken@0
  1320
				Uint8 *output;
slouken@0
  1321
slouken@0
  1322
				output = cvt->buf+clen;
slouken@0
  1323
				ipos = (double)cvt->len_cvt;
slouken@0
  1324
				for ( i=clen; i; --i ) {
slouken@0
  1325
					ipos -= cvt->rate_incr;
slouken@0
  1326
					output -= 1;
slouken@0
  1327
					*output = cvt->buf[(int)ipos];
slouken@0
  1328
				}
slouken@0
  1329
			}
slouken@0
  1330
			break;
slouken@0
  1331
slouken@0
  1332
			case 16: {
slouken@0
  1333
				Uint16 *output;
slouken@0
  1334
slouken@0
  1335
				clen &= ~1;
slouken@0
  1336
				output = (Uint16 *)(cvt->buf+clen);
slouken@0
  1337
				ipos = (double)cvt->len_cvt/2;
slouken@0
  1338
				for ( i=clen/2; i; --i ) {
slouken@0
  1339
					ipos -= cvt->rate_incr;
slouken@0
  1340
					output -= 1;
slouken@0
  1341
					*output=((Uint16 *)cvt->buf)[(int)ipos];
slouken@0
  1342
				}
slouken@0
  1343
			}
slouken@0
  1344
			break;
slouken@0
  1345
		}
slouken@0
  1346
	}
slouken@0
  1347
	cvt->len_cvt = clen;
slouken@0
  1348
	if ( cvt->filters[++cvt->filter_index] ) {
slouken@0
  1349
		cvt->filters[cvt->filter_index](cvt, format);
slouken@0
  1350
	}
slouken@0
  1351
}
slouken@0
  1352
slouken@0
  1353
int SDL_ConvertAudio(SDL_AudioCVT *cvt)
slouken@0
  1354
{
slouken@0
  1355
	/* Make sure there's data to convert */
slouken@0
  1356
	if ( cvt->buf == NULL ) {
slouken@0
  1357
		SDL_SetError("No buffer allocated for conversion");
slouken@0
  1358
		return(-1);
slouken@0
  1359
	}
slouken@0
  1360
	/* Return okay if no conversion is necessary */
slouken@0
  1361
	cvt->len_cvt = cvt->len;
slouken@0
  1362
	if ( cvt->filters[0] == NULL ) {
slouken@0
  1363
		return(0);
slouken@0
  1364
	}
slouken@0
  1365
slouken@0
  1366
	/* Set up the conversion and go! */
slouken@0
  1367
	cvt->filter_index = 0;
slouken@0
  1368
	cvt->filters[0](cvt, cvt->src_format);
slouken@0
  1369
	return(0);
slouken@0
  1370
}
slouken@0
  1371
slouken@0
  1372
/* Creates a set of audio filters to convert from one format to another. 
slouken@0
  1373
   Returns -1 if the format conversion is not supported, or 1 if the
slouken@0
  1374
   audio filter is set up.
slouken@0
  1375
*/
slouken@0
  1376
  
slouken@0
  1377
int SDL_BuildAudioCVT(SDL_AudioCVT *cvt,
slouken@0
  1378
	Uint16 src_format, Uint8 src_channels, int src_rate,
slouken@0
  1379
	Uint16 dst_format, Uint8 dst_channels, int dst_rate)
slouken@0
  1380
{
slouken@942
  1381
/*printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
slouken@942
  1382
		src_format, dst_format, src_channels, dst_channels, src_rate, dst_rate);*/
slouken@0
  1383
	/* Start off with no conversion necessary */
slouken@0
  1384
	cvt->needed = 0;
slouken@0
  1385
	cvt->filter_index = 0;
slouken@0
  1386
	cvt->filters[0] = NULL;
slouken@0
  1387
	cvt->len_mult = 1;
slouken@0
  1388
	cvt->len_ratio = 1.0;
slouken@0
  1389
slouken@0
  1390
	/* First filter:  Endian conversion from src to dst */
slouken@0
  1391
	if ( (src_format & 0x1000) != (dst_format & 0x1000)
slouken@0
  1392
	     && ((src_format & 0xff) != 8) ) {
slouken@0
  1393
		cvt->filters[cvt->filter_index++] = SDL_ConvertEndian;
slouken@0
  1394
	}
slouken@0
  1395
	
slouken@0
  1396
	/* Second filter: Sign conversion -- signed/unsigned */
slouken@0
  1397
	if ( (src_format & 0x8000) != (dst_format & 0x8000) ) {
slouken@0
  1398
		cvt->filters[cvt->filter_index++] = SDL_ConvertSign;
slouken@0
  1399
	}
slouken@0
  1400
slouken@0
  1401
	/* Next filter:  Convert 16 bit <--> 8 bit PCM */
slouken@0
  1402
	if ( (src_format & 0xFF) != (dst_format & 0xFF) ) {
slouken@0
  1403
		switch (dst_format&0x10FF) {
slouken@0
  1404
			case AUDIO_U8:
slouken@0
  1405
				cvt->filters[cvt->filter_index++] =
slouken@0
  1406
							 SDL_Convert8;
slouken@0
  1407
				cvt->len_ratio /= 2;
slouken@0
  1408
				break;
slouken@0
  1409
			case AUDIO_U16LSB:
slouken@0
  1410
				cvt->filters[cvt->filter_index++] =
slouken@0
  1411
							SDL_Convert16LSB;
slouken@0
  1412
				cvt->len_mult *= 2;
slouken@0
  1413
				cvt->len_ratio *= 2;
slouken@0
  1414
				break;
slouken@0
  1415
			case AUDIO_U16MSB:
slouken@0
  1416
				cvt->filters[cvt->filter_index++] =
slouken@0
  1417
							SDL_Convert16MSB;
slouken@0
  1418
				cvt->len_mult *= 2;
slouken@0
  1419
				cvt->len_ratio *= 2;
slouken@0
  1420
				break;
slouken@0
  1421
		}
slouken@0
  1422
	}
slouken@0
  1423
slouken@0
  1424
	/* Last filter:  Mono/Stereo conversion */
slouken@0
  1425
	if ( src_channels != dst_channels ) {
slouken@942
  1426
		if ( (src_channels == 1) && (dst_channels > 1) ) {
slouken@942
  1427
			cvt->filters[cvt->filter_index++] = 
slouken@942
  1428
						SDL_ConvertStereo;
slouken@942
  1429
			cvt->len_mult *= 2;
slouken@942
  1430
			src_channels = 2;
slouken@942
  1431
			cvt->len_ratio *= 2;
slouken@942
  1432
		}
slouken@942
  1433
		if ( (src_channels == 2) &&
slouken@942
  1434
				(dst_channels == 6) ) {
slouken@942
  1435
			cvt->filters[cvt->filter_index++] =
slouken@942
  1436
						 SDL_ConvertSurround;
slouken@942
  1437
			src_channels = 6;
slouken@942
  1438
			cvt->len_mult *= 3;
slouken@942
  1439
			cvt->len_ratio *= 3;
slouken@942
  1440
		}
slouken@942
  1441
		if ( (src_channels == 2) &&
slouken@942
  1442
				(dst_channels == 4) ) {
slouken@942
  1443
			cvt->filters[cvt->filter_index++] =
slouken@942
  1444
						 SDL_ConvertSurround_4;
slouken@942
  1445
			src_channels = 4;
slouken@942
  1446
			cvt->len_mult *= 2;
slouken@942
  1447
			cvt->len_ratio *= 2;
slouken@942
  1448
		}
slouken@0
  1449
		while ( (src_channels*2) <= dst_channels ) {
slouken@0
  1450
			cvt->filters[cvt->filter_index++] = 
slouken@0
  1451
						SDL_ConvertStereo;
slouken@0
  1452
			cvt->len_mult *= 2;
slouken@0
  1453
			src_channels *= 2;
slouken@0
  1454
			cvt->len_ratio *= 2;
slouken@0
  1455
		}
slouken@942
  1456
		if ( (src_channels == 6) &&
slouken@942
  1457
				(dst_channels <= 2) ) {
slouken@942
  1458
			cvt->filters[cvt->filter_index++] =
slouken@942
  1459
						 SDL_ConvertStrip;
slouken@942
  1460
			src_channels = 2;
slouken@942
  1461
			cvt->len_ratio /= 3;
slouken@942
  1462
		}
slouken@942
  1463
		if ( (src_channels == 6) &&
slouken@942
  1464
				(dst_channels == 4) ) {
slouken@942
  1465
			cvt->filters[cvt->filter_index++] =
slouken@942
  1466
						 SDL_ConvertStrip_2;
slouken@942
  1467
			src_channels = 4;
slouken@942
  1468
			cvt->len_ratio /= 2;
slouken@942
  1469
		}
slouken@0
  1470
		/* This assumes that 4 channel audio is in the format:
slouken@0
  1471
		     Left {front/back} + Right {front/back}
slouken@0
  1472
		   so converting to L/R stereo works properly.
slouken@0
  1473
		 */
slouken@0
  1474
		while ( ((src_channels%2) == 0) &&
slouken@0
  1475
				((src_channels/2) >= dst_channels) ) {
slouken@0
  1476
			cvt->filters[cvt->filter_index++] =
slouken@0
  1477
						 SDL_ConvertMono;
slouken@0
  1478
			src_channels /= 2;
slouken@0
  1479
			cvt->len_ratio /= 2;
slouken@0
  1480
		}
slouken@0
  1481
		if ( src_channels != dst_channels ) {
slouken@0
  1482
			/* Uh oh.. */;
slouken@0
  1483
		}
slouken@0
  1484
	}
slouken@0
  1485
slouken@0
  1486
	/* Do rate conversion */
slouken@0
  1487
	cvt->rate_incr = 0.0;
slouken@0
  1488
	if ( (src_rate/100) != (dst_rate/100) ) {
slouken@0
  1489
		Uint32 hi_rate, lo_rate;
slouken@0
  1490
		int len_mult;
slouken@0
  1491
		double len_ratio;
slouken@0
  1492
		void (*rate_cvt)(SDL_AudioCVT *cvt, Uint16 format);
slouken@0
  1493
slouken@0
  1494
		if ( src_rate > dst_rate ) {
slouken@0
  1495
			hi_rate = src_rate;
slouken@0
  1496
			lo_rate = dst_rate;
slouken@942
  1497
			switch (src_channels) {
slouken@942
  1498
				case 1: rate_cvt = SDL_RateDIV2; break;
slouken@942
  1499
				case 2: rate_cvt = SDL_RateDIV2_c2; break;
slouken@942
  1500
				case 4: rate_cvt = SDL_RateDIV2_c4; break;
slouken@942
  1501
				case 6: rate_cvt = SDL_RateDIV2_c6; break;
slouken@942
  1502
				default: return -1;
slouken@942
  1503
			}
slouken@0
  1504
			len_mult = 1;
slouken@0
  1505
			len_ratio = 0.5;
slouken@0
  1506
		} else {
slouken@0
  1507
			hi_rate = dst_rate;
slouken@0
  1508
			lo_rate = src_rate;
slouken@942
  1509
			switch (src_channels) {
slouken@942
  1510
				case 1: rate_cvt = SDL_RateMUL2; break;
slouken@942
  1511
				case 2: rate_cvt = SDL_RateMUL2_c2; break;
slouken@942
  1512
				case 4: rate_cvt = SDL_RateMUL2_c4; break;
slouken@942
  1513
				case 6: rate_cvt = SDL_RateMUL2_c6; break;
slouken@942
  1514
				default: return -1;
slouken@942
  1515
			}
slouken@0
  1516
			len_mult = 2;
slouken@0
  1517
			len_ratio = 2.0;
slouken@0
  1518
		}
slouken@0
  1519
		/* If hi_rate = lo_rate*2^x then conversion is easy */
slouken@0
  1520
		while ( ((lo_rate*2)/100) <= (hi_rate/100) ) {
slouken@0
  1521
			cvt->filters[cvt->filter_index++] = rate_cvt;
slouken@0
  1522
			cvt->len_mult *= len_mult;
slouken@0
  1523
			lo_rate *= 2;
slouken@0
  1524
			cvt->len_ratio *= len_ratio;
slouken@0
  1525
		}
slouken@0
  1526
		/* We may need a slow conversion here to finish up */
slouken@0
  1527
		if ( (lo_rate/100) != (hi_rate/100) ) {
slouken@0
  1528
#if 1
slouken@0
  1529
			/* The problem with this is that if the input buffer is
slouken@0
  1530
			   say 1K, and the conversion rate is say 1.1, then the
slouken@0
  1531
			   output buffer is 1.1K, which may not be an acceptable
slouken@0
  1532
			   buffer size for the audio driver (not a power of 2)
slouken@0
  1533
			*/
slouken@0
  1534
			/* For now, punt and hope the rate distortion isn't great.
slouken@0
  1535
			*/
slouken@0
  1536
#else
slouken@0
  1537
			if ( src_rate < dst_rate ) {
slouken@0
  1538
				cvt->rate_incr = (double)lo_rate/hi_rate;
slouken@0
  1539
				cvt->len_mult *= 2;
slouken@0
  1540
				cvt->len_ratio /= cvt->rate_incr;
slouken@0
  1541
			} else {
slouken@0
  1542
				cvt->rate_incr = (double)hi_rate/lo_rate;
slouken@0
  1543
				cvt->len_ratio *= cvt->rate_incr;
slouken@0
  1544
			}
slouken@0
  1545
			cvt->filters[cvt->filter_index++] = SDL_RateSLOW;
slouken@0
  1546
#endif
slouken@0
  1547
		}
slouken@0
  1548
	}
slouken@0
  1549
slouken@0
  1550
	/* Set up the filter information */
slouken@0
  1551
	if ( cvt->filter_index != 0 ) {
slouken@0
  1552
		cvt->needed = 1;
slouken@0
  1553
		cvt->src_format = src_format;
slouken@0
  1554
		cvt->dst_format = dst_format;
slouken@0
  1555
		cvt->len = 0;
slouken@0
  1556
		cvt->buf = NULL;
slouken@0
  1557
		cvt->filters[cvt->filter_index] = NULL;
slouken@0
  1558
	}
slouken@0
  1559
	return(cvt->needed);
slouken@0
  1560
}