playwave.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 21 Aug 2004 12:27:02 +0000
changeset 245 63b3650714de
parent 241 503416fca921
child 321 a72a7f07c8f1
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
    PLAYWAVE:  A test application for the SDL mixer library.
slouken@241
     3
    Copyright (C) 1997-2004 Sam Lantinga
slouken@0
     4
slouken@138
     5
    This library is free software; you can redistribute it and/or
slouken@138
     6
    modify it under the terms of the GNU Library General Public
slouken@138
     7
    License as published by the Free Software Foundation; either
slouken@138
     8
    version 2 of the License, or (at your option) any later version.
slouken@0
     9
slouken@138
    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@138
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@138
    13
    Library General Public License for more details.
slouken@0
    14
slouken@138
    15
    You should have received a copy of the GNU Library General Public
slouken@138
    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@138
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@0
    22
slouken@140
    23
/* $Id$ */
slouken@138
    24
slouken@0
    25
#include <stdlib.h>
slouken@0
    26
#include <stdio.h>
slouken@0
    27
#include <string.h>
slouken@0
    28
#include <signal.h>
slouken@47
    29
#ifdef unix
slouken@0
    30
#include <unistd.h>
slouken@0
    31
#endif
slouken@0
    32
slouken@24
    33
#include "SDL.h"
slouken@34
    34
#include "SDL_mixer.h"
slouken@0
    35
slouken@0
    36
slouken@113
    37
/*
slouken@113
    38
 * rcg06132001 various mixer tests. Define the ones you want.
slouken@113
    39
 */
slouken@127
    40
/*#define TEST_MIX_VERSIONS*/
slouken@127
    41
/*#define TEST_MIX_CHANNELFINISHED*/
slouken@113
    42
/*#define TEST_MIX_PANNING*/
slouken@113
    43
/*#define TEST_MIX_DISTANCE*/
slouken@127
    44
/*#define TEST_MIX_POSITION*/
slouken@113
    45
slouken@113
    46
slouken@113
    47
#if (defined TEST_MIX_POSITION)
slouken@113
    48
slouken@113
    49
#if (defined TEST_MIX_PANNING)
slouken@113
    50
#error TEST_MIX_POSITION interferes with TEST_MIX_PANNING.
slouken@113
    51
#endif
slouken@113
    52
slouken@113
    53
#if (defined TEST_MIX_DISTANCE)
slouken@113
    54
#error TEST_MIX_POSITION interferes with TEST_MIX_DISTANCE.
slouken@113
    55
#endif
slouken@113
    56
slouken@113
    57
#endif
slouken@113
    58
slouken@113
    59
slouken@113
    60
/* rcg06192001 for debugging purposes. */
slouken@113
    61
static void output_test_warnings(void)
slouken@113
    62
{
slouken@113
    63
#if (defined TEST_MIX_CHANNELFINISHED)
slouken@113
    64
	fprintf(stderr, "Warning: TEST_MIX_CHANNELFINISHED is enabled in this binary...\n");
slouken@113
    65
#endif
slouken@113
    66
#if (defined TEST_MIX_PANNING)
slouken@113
    67
	fprintf(stderr, "Warning: TEST_MIX_PANNING is enabled in this binary...\n");
slouken@113
    68
#endif
slouken@113
    69
#if (defined TEST_MIX_VERSIONS)
slouken@113
    70
	fprintf(stderr, "Warning: TEST_MIX_VERSIONS is enabled in this binary...\n");
slouken@113
    71
#endif
slouken@113
    72
#if (defined TEST_MIX_DISTANCE)
slouken@113
    73
	fprintf(stderr, "Warning: TEST_MIX_DISTANCE is enabled in this binary...\n");
slouken@113
    74
#endif
slouken@113
    75
#if (defined TEST_MIX_POSITION)
slouken@113
    76
	fprintf(stderr, "Warning: TEST_MIX_POSITION is enabled in this binary...\n");
slouken@113
    77
#endif
slouken@113
    78
}
slouken@113
    79
slouken@113
    80
slouken@0
    81
static int audio_open = 0;
slouken@0
    82
static Mix_Chunk *wave = NULL;
slouken@0
    83
slouken@113
    84
slouken@113
    85
/* rcg06192001 Check new Mixer version API. */
slouken@113
    86
#if (defined TEST_MIX_VERSIONS)
slouken@113
    87
static void output_versions(const char *libname, const SDL_version *compiled,
slouken@113
    88
							const SDL_version *linked)
slouken@113
    89
{
slouken@113
    90
	fprintf(stderr,
slouken@113
    91
			"This program was compiled against %s %d.%d.%d,\n"
slouken@113
    92
			" and is dynamically linked to %d.%d.%d.\n", libname,
slouken@113
    93
			compiled->major, compiled->minor, compiled->patch,
slouken@113
    94
			linked->major, linked->minor, linked->patch);
slouken@113
    95
}
slouken@113
    96
slouken@113
    97
static void test_versions(void)
slouken@113
    98
{
slouken@113
    99
	SDL_version compiled;
slouken@113
   100
	const SDL_version *linked;
slouken@113
   101
slouken@113
   102
	SDL_VERSION(&compiled);
slouken@113
   103
	linked = SDL_Linked_Version();
slouken@113
   104
	output_versions("SDL", &compiled, linked);
slouken@113
   105
slouken@227
   106
	SDL_MIXER_VERSION(&compiled);
slouken@113
   107
	linked = Mix_Linked_Version();
slouken@113
   108
	output_versions("SDL_mixer", &compiled, linked);
slouken@113
   109
}
slouken@113
   110
#endif
slouken@113
   111
slouken@113
   112
slouken@113
   113
#ifdef TEST_MIX_CHANNELFINISHED  /* rcg06072001 */
slouken@113
   114
static volatile int channel_is_done = 0;
slouken@113
   115
static void channel_complete_callback(int chan)
slouken@113
   116
{
slouken@113
   117
	Mix_Chunk *done_chunk = Mix_GetChunk(chan);
slouken@113
   118
	fprintf(stderr, "We were just alerted that Mixer channel #%d is done.\n", chan);
slouken@113
   119
	fprintf(stderr, "Channel's chunk pointer is (%p).\n", done_chunk);
slouken@113
   120
	fprintf(stderr, " Which %s correct.\n", (wave == done_chunk) ? "is" : "is NOT");
slouken@113
   121
	channel_is_done = 1;
slouken@113
   122
}
slouken@113
   123
#endif
slouken@113
   124
slouken@113
   125
slouken@113
   126
/* rcg06192001 abstract this out for testing purposes. */
slouken@113
   127
static int still_playing(void)
slouken@113
   128
{
slouken@113
   129
#ifdef TEST_MIX_CHANNELFINISHED
slouken@113
   130
	return(!channel_is_done);
slouken@113
   131
#else
slouken@113
   132
	return(Mix_Playing(0));
slouken@113
   133
#endif
slouken@113
   134
}
slouken@113
   135
slouken@113
   136
slouken@113
   137
#if (defined TEST_MIX_PANNING)
slouken@113
   138
static void do_panning_update(void)
slouken@113
   139
{
slouken@113
   140
	static Uint8 leftvol = 128;
slouken@113
   141
	static Uint8 rightvol = 128;
slouken@113
   142
	static Uint8 leftincr = -1;
slouken@113
   143
	static Uint8 rightincr = 1;
slouken@113
   144
	static int panningok = 1;
slouken@113
   145
	static Uint32 next_panning_update = 0;
slouken@113
   146
slouken@113
   147
	if ((panningok) && (SDL_GetTicks() >= next_panning_update)) {
slouken@113
   148
		panningok = Mix_SetPanning(0, leftvol, rightvol);
slouken@113
   149
		if (!panningok) {
slouken@113
   150
			fprintf(stderr, "Mix_SetPanning(0, %d, %d) failed!\n",
slouken@113
   151
					(int) leftvol, (int) rightvol);
slouken@113
   152
			fprintf(stderr, "Reason: [%s].\n", Mix_GetError());
slouken@113
   153
		}
slouken@113
   154
slouken@113
   155
		if ((leftvol == 255) || (leftvol == 0)) {
slouken@113
   156
			if (leftvol == 255)
slouken@113
   157
				printf("All the way in the left speaker.\n");
slouken@113
   158
				leftincr *= -1;
slouken@113
   159
		}
slouken@113
   160
slouken@113
   161
		if ((rightvol == 255) || (rightvol == 0)) {
slouken@113
   162
			if (rightvol == 255)
slouken@113
   163
				printf("All the way in the right speaker.\n");
slouken@113
   164
			rightincr *= -1;
slouken@113
   165
		}
slouken@113
   166
slouken@113
   167
		leftvol += leftincr;
slouken@113
   168
		rightvol += rightincr;
slouken@113
   169
		next_panning_update = SDL_GetTicks() + 10;
slouken@113
   170
	}
slouken@113
   171
}
slouken@113
   172
#endif
slouken@113
   173
slouken@113
   174
slouken@113
   175
#if (defined TEST_MIX_DISTANCE)
slouken@113
   176
static void do_distance_update(void)
slouken@113
   177
{
slouken@113
   178
	static Uint8 distance = 1;
slouken@113
   179
	static Uint8 distincr = 1;
slouken@113
   180
	static int distanceok = 1;
slouken@113
   181
	static Uint32 next_distance_update = 0;
slouken@113
   182
slouken@113
   183
	if ((distanceok) && (SDL_GetTicks() >= next_distance_update)) {
slouken@113
   184
		distanceok = Mix_SetDistance(0, distance);
slouken@113
   185
		if (!distanceok) {
slouken@113
   186
			fprintf(stderr, "Mix_SetDistance(0, %d) failed!\n", (int) distance);
slouken@113
   187
			fprintf(stderr, "Reason: [%s].\n", Mix_GetError());
slouken@113
   188
		}
slouken@113
   189
slouken@113
   190
		if (distance == 0) {
slouken@113
   191
			printf("Distance at nearest point.\n");
slouken@113
   192
			distincr *= -1;
slouken@113
   193
		}
slouken@113
   194
		else if (distance == 255) {
slouken@113
   195
			printf("Distance at furthest point.\n");
slouken@113
   196
			distincr *= -1;
slouken@113
   197
		}
slouken@113
   198
slouken@113
   199
		distance += distincr;
slouken@113
   200
		next_distance_update = SDL_GetTicks() + 15;
slouken@113
   201
	}
slouken@113
   202
}
slouken@113
   203
#endif
slouken@113
   204
slouken@113
   205
slouken@113
   206
#if (defined TEST_MIX_POSITION)
slouken@113
   207
static void do_position_update(void)
slouken@113
   208
{
slouken@113
   209
	static Sint16 distance = 1;
slouken@113
   210
	static Sint8 distincr = 1;
slouken@113
   211
	static Uint16 angle = 0;
slouken@113
   212
	static Sint8 angleincr = 1;
slouken@113
   213
	static int positionok = 1;
slouken@113
   214
	static Uint32 next_position_update = 0;
slouken@113
   215
slouken@113
   216
	if ((positionok) && (SDL_GetTicks() >= next_position_update)) {
slouken@113
   217
		positionok = Mix_SetPosition(0, angle, distance);
slouken@113
   218
		if (!positionok) {
slouken@113
   219
			fprintf(stderr, "Mix_SetPosition(0, %d, %d) failed!\n",
slouken@113
   220
					(int) angle, (int) distance);
slouken@113
   221
			fprintf(stderr, "Reason: [%s].\n", Mix_GetError());
slouken@113
   222
		}
slouken@113
   223
slouken@113
   224
		if (angle == 0) {
slouken@113
   225
			printf("Due north; now rotating clockwise...\n");
slouken@113
   226
			angleincr = 1;
slouken@113
   227
		}
slouken@113
   228
slouken@113
   229
		else if (angle == 360) {
slouken@113
   230
			printf("Due north; now rotating counter-clockwise...\n");
slouken@113
   231
			angleincr = -1;
slouken@113
   232
		}
slouken@113
   233
slouken@113
   234
		distance += distincr;
slouken@113
   235
slouken@113
   236
		if (distance < 0) {
slouken@113
   237
			distance = 0;
slouken@113
   238
			distincr = 3;
slouken@113
   239
			printf("Distance is very, very near. Stepping away by threes...\n");
slouken@113
   240
		} else if (distance > 255) {
slouken@113
   241
			distance = 255;
slouken@113
   242
			distincr = -3;
slouken@113
   243
			printf("Distance is very, very far. Stepping towards by threes...\n");
slouken@113
   244
		}
slouken@113
   245
slouken@113
   246
		angle += angleincr;
slouken@113
   247
		next_position_update = SDL_GetTicks() + 30;
slouken@113
   248
	}
slouken@113
   249
}
slouken@113
   250
#endif
slouken@113
   251
slouken@113
   252
slouken@113
   253
static void CleanUp(void)
slouken@0
   254
{
megastep@21
   255
	if ( wave ) {
megastep@21
   256
		Mix_FreeChunk(wave);
megastep@21
   257
		wave = NULL;
megastep@21
   258
	}
slouken@0
   259
	if ( audio_open ) {
slouken@0
   260
		Mix_CloseAudio();
slouken@0
   261
		audio_open = 0;
slouken@0
   262
	}
slouken@0
   263
	SDL_Quit();
slouken@0
   264
}
slouken@0
   265
slouken@113
   266
slouken@113
   267
static void Usage(char *argv0)
slouken@0
   268
{
slouken@245
   269
	fprintf(stderr, "Usage: %s [-8] [-r rate] [-c channels] [-f] [-F] [-l] [-m] <wavefile>\n", argv0);
slouken@0
   270
}
slouken@92
   271
slouken@92
   272
slouken@113
   273
/*
slouken@113
   274
 * rcg06182001 This is sick, but cool.
slouken@113
   275
 *
slouken@113
   276
 *  Actually, it's meant to be an example of how to manipulate a voice
slouken@113
   277
 *  without having to use the mixer effects API. This is more processing
slouken@113
   278
 *  up front, but no extra during the mixing process. Also, in a case like
slouken@113
   279
 *  this, when you need to touch the whole sample at once, it's the only
slouken@113
   280
 *  option you've got. And, with the effects API, you are altering a copy of
slouken@113
   281
 *  the original sample for each playback, and thus, your changes aren't
slouken@113
   282
 *  permanent; here, you've got a reversed sample, and that's that until
slouken@113
   283
 *  you either reverse it again, or reload it.
slouken@113
   284
 */
slouken@113
   285
static void flip_sample(Mix_Chunk *wave)
slouken@92
   286
{
slouken@113
   287
	Uint16 format;
slouken@113
   288
	int channels, i, incr;
slouken@113
   289
	Uint8 *start = wave->abuf;
slouken@113
   290
	Uint8 *end = wave->abuf + wave->alen;
slouken@113
   291
slouken@113
   292
	Mix_QuerySpec(NULL, &format, &channels);
slouken@113
   293
	incr = (format & 0xFF) * channels;
slouken@113
   294
slouken@113
   295
	end -= incr;
slouken@113
   296
slouken@113
   297
	switch (incr) {
slouken@113
   298
		case 8:
slouken@113
   299
			for (i = wave->alen / 2; i >= 0; i -= 1) {
slouken@113
   300
				Uint8 tmp = *start;
slouken@113
   301
				*start = *end;
slouken@113
   302
				*end = tmp;
slouken@113
   303
				start++;
slouken@113
   304
				end--;
slouken@113
   305
			}
slouken@113
   306
			break;
slouken@113
   307
slouken@113
   308
		case 16:
slouken@113
   309
			for (i = wave->alen / 2; i >= 0; i -= 2) {
slouken@113
   310
				Uint16 tmp = *start;
slouken@113
   311
				*((Uint16 *) start) = *((Uint16 *) end);
slouken@113
   312
				*((Uint16 *) end) = tmp;
slouken@113
   313
				start += 2;
slouken@113
   314
				end -= 2;
slouken@113
   315
			}
slouken@113
   316
			break;
slouken@113
   317
slouken@113
   318
		case 32:
slouken@113
   319
			for (i = wave->alen / 2; i >= 0; i -= 4) {
slouken@113
   320
				Uint32 tmp = *start;
slouken@113
   321
				*((Uint32 *) start) = *((Uint32 *) end);
slouken@113
   322
				*((Uint32 *) end) = tmp;
slouken@113
   323
				start += 4;
slouken@113
   324
				end -= 4;
slouken@113
   325
			}
slouken@113
   326
			break;
slouken@113
   327
slouken@113
   328
		default:
slouken@113
   329
			fprintf(stderr, "Unhandled format in sample flipping.\n");
slouken@113
   330
			return;
slouken@113
   331
	}
slouken@92
   332
}
slouken@92
   333
slouken@92
   334
slouken@113
   335
int main(int argc, char *argv[])
slouken@0
   336
{
slouken@47
   337
	int audio_rate;
slouken@0
   338
	Uint16 audio_format;
slouken@0
   339
	int audio_channels;
megastep@21
   340
	int loops = 0;
slouken@0
   341
	int i;
slouken@113
   342
	int reverse_stereo = 0;
slouken@113
   343
	int reverse_sample = 0;
slouken@113
   344
slouken@113
   345
	setbuf(stdout, NULL);    /* rcg06132001 for debugging purposes. */
slouken@113
   346
	setbuf(stderr, NULL);    /* rcg06192001 for debugging purposes, too. */
slouken@113
   347
	output_test_warnings();
slouken@0
   348
slouken@0
   349
	/* Initialize variables */
slouken@70
   350
	audio_rate = MIX_DEFAULT_FREQUENCY;
slouken@70
   351
	audio_format = MIX_DEFAULT_FORMAT;
slouken@0
   352
	audio_channels = 2;
slouken@0
   353
slouken@0
   354
	/* Check command line usage */
slouken@0
   355
	for ( i=1; argv[i] && (*argv[i] == '-'); ++i ) {
slouken@0
   356
		if ( (strcmp(argv[i], "-r") == 0) && argv[i+1] ) {
slouken@0
   357
			++i;
slouken@0
   358
			audio_rate = atoi(argv[i]);
slouken@0
   359
		} else
slouken@0
   360
		if ( strcmp(argv[i], "-m") == 0 ) {
slouken@0
   361
			audio_channels = 1;
slouken@0
   362
		} else
slouken@245
   363
		if ( (strcmp(argv[i], "-c") == 0) && argv[i+1] ) {
slouken@245
   364
			++i;
slouken@245
   365
			audio_channels = atoi(argv[i]);
slouken@245
   366
		} else
megastep@21
   367
		if ( strcmp(argv[i], "-l") == 0 ) {
megastep@21
   368
			loops = -1;
megastep@21
   369
		} else
slouken@0
   370
		if ( strcmp(argv[i], "-8") == 0 ) {
slouken@0
   371
			audio_format = AUDIO_U8;
slouken@113
   372
		} else
slouken@113
   373
		if ( strcmp(argv[i], "-f") == 0 ) { /* rcg06122001 flip stereo */
slouken@113
   374
			reverse_stereo = 1;
slouken@113
   375
		} else
slouken@113
   376
		if ( strcmp(argv[i], "-F") == 0 ) { /* rcg06172001 flip sample */
slouken@113
   377
			reverse_sample = 1;
slouken@0
   378
		} else {
slouken@0
   379
			Usage(argv[0]);
slouken@83
   380
			return(1);
slouken@0
   381
		}
slouken@0
   382
	}
slouken@0
   383
	if ( ! argv[i] ) {
slouken@0
   384
		Usage(argv[0]);
slouken@83
   385
		return(1);
slouken@0
   386
	}
slouken@0
   387
slouken@0
   388
	/* Initialize the SDL library */
slouken@0
   389
	if ( SDL_Init(SDL_INIT_AUDIO) < 0 ) {
slouken@0
   390
		fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
slouken@83
   391
		return(255);
slouken@0
   392
	}
slouken@0
   393
	atexit(CleanUp);
slouken@0
   394
	signal(SIGINT, exit);
slouken@0
   395
	signal(SIGTERM, exit);
slouken@0
   396
slouken@0
   397
	/* Open the audio device */
slouken@0
   398
	if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, 4096) < 0) {
slouken@0
   399
		fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
slouken@83
   400
		return(2);
slouken@0
   401
	} else {
slouken@0
   402
		Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
megastep@21
   403
		printf("Opened audio at %d Hz %d bit %s", audio_rate,
slouken@0
   404
			(audio_format&0xFF),
slouken@245
   405
			(audio_channels > 2) ? "surround" :
slouken@0
   406
			(audio_channels > 1) ? "stereo" : "mono");
megastep@21
   407
		if ( loops ) {
megastep@21
   408
		  printf(" (looping)\n");
megastep@21
   409
		} else {
megastep@21
   410
		  putchar('\n');
megastep@21
   411
		}
slouken@0
   412
	}
slouken@0
   413
	audio_open = 1;
slouken@0
   414
slouken@113
   415
#if (defined TEST_MIX_VERSIONS)
slouken@113
   416
    test_versions();
slouken@113
   417
#endif
slouken@113
   418
slouken@0
   419
	/* Load the requested wave file */
slouken@0
   420
	wave = Mix_LoadWAV(argv[i]);
slouken@0
   421
	if ( wave == NULL ) {
slouken@0
   422
		fprintf(stderr, "Couldn't load %s: %s\n",
slouken@0
   423
						argv[i], SDL_GetError());
slouken@83
   424
		return(2);
slouken@0
   425
	}
slouken@0
   426
slouken@113
   427
	if (reverse_sample) {
slouken@113
   428
		flip_sample(wave);
slouken@113
   429
	}
slouken@113
   430
slouken@92
   431
#ifdef TEST_MIX_CHANNELFINISHED  /* rcg06072001 */
slouken@92
   432
	Mix_ChannelFinished(channel_complete_callback);
slouken@92
   433
#endif
slouken@92
   434
slouken@113
   435
	if ( (!Mix_SetReverseStereo(MIX_CHANNEL_POST, reverse_stereo)) &&
slouken@113
   436
		 (reverse_stereo) )
slouken@113
   437
	{
slouken@113
   438
		printf("Failed to set up reverse stereo effect!\n");
slouken@113
   439
		printf("Reason: [%s].\n", Mix_GetError());
slouken@113
   440
	}
slouken@113
   441
slouken@0
   442
	/* Play and then exit */
megastep@21
   443
	Mix_PlayChannel(0, wave, loops);
slouken@92
   444
slouken@113
   445
	while (still_playing()) {
slouken@113
   446
slouken@113
   447
#if (defined TEST_MIX_PANNING)  /* rcg06132001 */
slouken@113
   448
		do_panning_update();
slouken@92
   449
#endif
slouken@92
   450
slouken@113
   451
#if (defined TEST_MIX_DISTANCE) /* rcg06192001 */
slouken@113
   452
		do_distance_update();
slouken@113
   453
#endif
slouken@113
   454
slouken@113
   455
#if (defined TEST_MIX_POSITION) /* rcg06202001 */
slouken@113
   456
		do_position_update();
slouken@113
   457
#endif
slouken@113
   458
slouken@113
   459
		SDL_Delay(1);
slouken@113
   460
slouken@113
   461
	} /* while still_playing() loop... */
slouken@113
   462
slouken@83
   463
	return(0);
slouken@0
   464
}
slouken@113
   465
slouken@113
   466
/* end of playwave.c ... */
slouken@113
   467