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