playwave.c
changeset 113 c0c3018bd787
parent 92 2a30d721bd79
child 127 cfd3d3afb32e
     1.1 --- a/playwave.c	Tue Sep 11 18:49:18 2001 +0000
     1.2 +++ b/playwave.c	Tue Sep 11 19:14:36 2001 +0000
     1.3 @@ -34,10 +34,223 @@
     1.4  #include "SDL_mixer.h"
     1.5  
     1.6  
     1.7 +/*
     1.8 + * rcg06132001 various mixer tests. Define the ones you want.
     1.9 + */
    1.10 +#define TEST_MIX_VERSIONS
    1.11 +#define TEST_MIX_CHANNELFINISHED
    1.12 +/*#define TEST_MIX_PANNING*/
    1.13 +/*#define TEST_MIX_DISTANCE*/
    1.14 +#define TEST_MIX_POSITION
    1.15 +
    1.16 +
    1.17 +#if (defined TEST_MIX_POSITION)
    1.18 +
    1.19 +#if (defined TEST_MIX_PANNING)
    1.20 +#error TEST_MIX_POSITION interferes with TEST_MIX_PANNING.
    1.21 +#endif
    1.22 +
    1.23 +#if (defined TEST_MIX_DISTANCE)
    1.24 +#error TEST_MIX_POSITION interferes with TEST_MIX_DISTANCE.
    1.25 +#endif
    1.26 +
    1.27 +#endif
    1.28 +
    1.29 +
    1.30 +/* rcg06192001 for debugging purposes. */
    1.31 +static void output_test_warnings(void)
    1.32 +{
    1.33 +#if (defined TEST_MIX_CHANNELFINISHED)
    1.34 +	fprintf(stderr, "Warning: TEST_MIX_CHANNELFINISHED is enabled in this binary...\n");
    1.35 +#endif
    1.36 +#if (defined TEST_MIX_PANNING)
    1.37 +	fprintf(stderr, "Warning: TEST_MIX_PANNING is enabled in this binary...\n");
    1.38 +#endif
    1.39 +#if (defined TEST_MIX_VERSIONS)
    1.40 +	fprintf(stderr, "Warning: TEST_MIX_VERSIONS is enabled in this binary...\n");
    1.41 +#endif
    1.42 +#if (defined TEST_MIX_DISTANCE)
    1.43 +	fprintf(stderr, "Warning: TEST_MIX_DISTANCE is enabled in this binary...\n");
    1.44 +#endif
    1.45 +#if (defined TEST_MIX_POSITION)
    1.46 +	fprintf(stderr, "Warning: TEST_MIX_POSITION is enabled in this binary...\n");
    1.47 +#endif
    1.48 +}
    1.49 +
    1.50 +
    1.51  static int audio_open = 0;
    1.52  static Mix_Chunk *wave = NULL;
    1.53  
    1.54 -void CleanUp(void)
    1.55 +
    1.56 +/* rcg06192001 Check new Mixer version API. */
    1.57 +#if (defined TEST_MIX_VERSIONS)
    1.58 +static void output_versions(const char *libname, const SDL_version *compiled,
    1.59 +							const SDL_version *linked)
    1.60 +{
    1.61 +	fprintf(stderr,
    1.62 +			"This program was compiled against %s %d.%d.%d,\n"
    1.63 +			" and is dynamically linked to %d.%d.%d.\n", libname,
    1.64 +			compiled->major, compiled->minor, compiled->patch,
    1.65 +			linked->major, linked->minor, linked->patch);
    1.66 +}
    1.67 +
    1.68 +static void test_versions(void)
    1.69 +{
    1.70 +	SDL_version compiled;
    1.71 +	const SDL_version *linked;
    1.72 +
    1.73 +	SDL_VERSION(&compiled);
    1.74 +	linked = SDL_Linked_Version();
    1.75 +	output_versions("SDL", &compiled, linked);
    1.76 +
    1.77 +	MIX_VERSION(&compiled);
    1.78 +	linked = Mix_Linked_Version();
    1.79 +	output_versions("SDL_mixer", &compiled, linked);
    1.80 +}
    1.81 +#endif
    1.82 +
    1.83 +
    1.84 +#ifdef TEST_MIX_CHANNELFINISHED  /* rcg06072001 */
    1.85 +static volatile int channel_is_done = 0;
    1.86 +static void channel_complete_callback(int chan)
    1.87 +{
    1.88 +	Mix_Chunk *done_chunk = Mix_GetChunk(chan);
    1.89 +	fprintf(stderr, "We were just alerted that Mixer channel #%d is done.\n", chan);
    1.90 +	fprintf(stderr, "Channel's chunk pointer is (%p).\n", done_chunk);
    1.91 +	fprintf(stderr, " Which %s correct.\n", (wave == done_chunk) ? "is" : "is NOT");
    1.92 +	channel_is_done = 1;
    1.93 +}
    1.94 +#endif
    1.95 +
    1.96 +
    1.97 +/* rcg06192001 abstract this out for testing purposes. */
    1.98 +static int still_playing(void)
    1.99 +{
   1.100 +#ifdef TEST_MIX_CHANNELFINISHED
   1.101 +	return(!channel_is_done);
   1.102 +#else
   1.103 +	return(Mix_Playing(0));
   1.104 +#endif
   1.105 +}
   1.106 +
   1.107 +
   1.108 +#if (defined TEST_MIX_PANNING)
   1.109 +static void do_panning_update(void)
   1.110 +{
   1.111 +	static Uint8 leftvol = 128;
   1.112 +	static Uint8 rightvol = 128;
   1.113 +	static Uint8 leftincr = -1;
   1.114 +	static Uint8 rightincr = 1;
   1.115 +	static int panningok = 1;
   1.116 +	static Uint32 next_panning_update = 0;
   1.117 +
   1.118 +	if ((panningok) && (SDL_GetTicks() >= next_panning_update)) {
   1.119 +		panningok = Mix_SetPanning(0, leftvol, rightvol);
   1.120 +		if (!panningok) {
   1.121 +			fprintf(stderr, "Mix_SetPanning(0, %d, %d) failed!\n",
   1.122 +					(int) leftvol, (int) rightvol);
   1.123 +			fprintf(stderr, "Reason: [%s].\n", Mix_GetError());
   1.124 +		}
   1.125 +
   1.126 +		if ((leftvol == 255) || (leftvol == 0)) {
   1.127 +			if (leftvol == 255)
   1.128 +				printf("All the way in the left speaker.\n");
   1.129 +				leftincr *= -1;
   1.130 +		}
   1.131 +
   1.132 +		if ((rightvol == 255) || (rightvol == 0)) {
   1.133 +			if (rightvol == 255)
   1.134 +				printf("All the way in the right speaker.\n");
   1.135 +			rightincr *= -1;
   1.136 +		}
   1.137 +
   1.138 +		leftvol += leftincr;
   1.139 +		rightvol += rightincr;
   1.140 +		next_panning_update = SDL_GetTicks() + 10;
   1.141 +	}
   1.142 +}
   1.143 +#endif
   1.144 +
   1.145 +
   1.146 +#if (defined TEST_MIX_DISTANCE)
   1.147 +static void do_distance_update(void)
   1.148 +{
   1.149 +	static Uint8 distance = 1;
   1.150 +	static Uint8 distincr = 1;
   1.151 +	static int distanceok = 1;
   1.152 +	static Uint32 next_distance_update = 0;
   1.153 +
   1.154 +	if ((distanceok) && (SDL_GetTicks() >= next_distance_update)) {
   1.155 +		distanceok = Mix_SetDistance(0, distance);
   1.156 +		if (!distanceok) {
   1.157 +			fprintf(stderr, "Mix_SetDistance(0, %d) failed!\n", (int) distance);
   1.158 +			fprintf(stderr, "Reason: [%s].\n", Mix_GetError());
   1.159 +		}
   1.160 +
   1.161 +		if (distance == 0) {
   1.162 +			printf("Distance at nearest point.\n");
   1.163 +			distincr *= -1;
   1.164 +		}
   1.165 +		else if (distance == 255) {
   1.166 +			printf("Distance at furthest point.\n");
   1.167 +			distincr *= -1;
   1.168 +		}
   1.169 +
   1.170 +		distance += distincr;
   1.171 +		next_distance_update = SDL_GetTicks() + 15;
   1.172 +	}
   1.173 +}
   1.174 +#endif
   1.175 +
   1.176 +
   1.177 +#if (defined TEST_MIX_POSITION)
   1.178 +static void do_position_update(void)
   1.179 +{
   1.180 +	static Sint16 distance = 1;
   1.181 +	static Sint8 distincr = 1;
   1.182 +	static Uint16 angle = 0;
   1.183 +	static Sint8 angleincr = 1;
   1.184 +	static int positionok = 1;
   1.185 +	static Uint32 next_position_update = 0;
   1.186 +
   1.187 +	if ((positionok) && (SDL_GetTicks() >= next_position_update)) {
   1.188 +		positionok = Mix_SetPosition(0, angle, distance);
   1.189 +		if (!positionok) {
   1.190 +			fprintf(stderr, "Mix_SetPosition(0, %d, %d) failed!\n",
   1.191 +					(int) angle, (int) distance);
   1.192 +			fprintf(stderr, "Reason: [%s].\n", Mix_GetError());
   1.193 +		}
   1.194 +
   1.195 +		if (angle == 0) {
   1.196 +			printf("Due north; now rotating clockwise...\n");
   1.197 +			angleincr = 1;
   1.198 +		}
   1.199 +
   1.200 +		else if (angle == 360) {
   1.201 +			printf("Due north; now rotating counter-clockwise...\n");
   1.202 +			angleincr = -1;
   1.203 +		}
   1.204 +
   1.205 +		distance += distincr;
   1.206 +
   1.207 +		if (distance < 0) {
   1.208 +			distance = 0;
   1.209 +			distincr = 3;
   1.210 +			printf("Distance is very, very near. Stepping away by threes...\n");
   1.211 +		} else if (distance > 255) {
   1.212 +			distance = 255;
   1.213 +			distincr = -3;
   1.214 +			printf("Distance is very, very far. Stepping towards by threes...\n");
   1.215 +		}
   1.216 +
   1.217 +		angle += angleincr;
   1.218 +		next_position_update = SDL_GetTicks() + 30;
   1.219 +	}
   1.220 +}
   1.221 +#endif
   1.222 +
   1.223 +
   1.224 +static void CleanUp(void)
   1.225  {
   1.226  	if ( wave ) {
   1.227  		Mix_FreeChunk(wave);
   1.228 @@ -50,33 +263,88 @@
   1.229  	SDL_Quit();
   1.230  }
   1.231  
   1.232 -void Usage(char *argv0)
   1.233 +
   1.234 +static void Usage(char *argv0)
   1.235  {
   1.236 -	fprintf(stderr, "Usage: %s [-8] [-r rate] [-l] [-m] <wavefile>\n", argv0);
   1.237 +	fprintf(stderr, "Usage: %s [-8] [-r rate] [-f] [-F] [-l] [-m] <wavefile>\n", argv0);
   1.238  }
   1.239  
   1.240  
   1.241 -/*#define TEST_MIX_CHANNELFINISHED*/
   1.242 -#ifdef TEST_MIX_CHANNELFINISHED  /* rcg06072001 */
   1.243 -static volatile int channel_is_done = 0;
   1.244 -static void channel_complete_callback(int chan)
   1.245 +/*
   1.246 + * rcg06182001 This is sick, but cool.
   1.247 + *
   1.248 + *  Actually, it's meant to be an example of how to manipulate a voice
   1.249 + *  without having to use the mixer effects API. This is more processing
   1.250 + *  up front, but no extra during the mixing process. Also, in a case like
   1.251 + *  this, when you need to touch the whole sample at once, it's the only
   1.252 + *  option you've got. And, with the effects API, you are altering a copy of
   1.253 + *  the original sample for each playback, and thus, your changes aren't
   1.254 + *  permanent; here, you've got a reversed sample, and that's that until
   1.255 + *  you either reverse it again, or reload it.
   1.256 + */
   1.257 +static void flip_sample(Mix_Chunk *wave)
   1.258  {
   1.259 -	Mix_Chunk *done_chunk = Mix_GetChunk(chan);
   1.260 -	printf("We were just alerted that Mixer channel #%d is done.\n", chan);
   1.261 -	printf("Channel's chunk pointer is (%p).\n", done_chunk);
   1.262 -	printf(" Which %s correct.\n", (wave == done_chunk) ? "is" : "is NOT");
   1.263 -	channel_is_done = 1;
   1.264 +	Uint16 format;
   1.265 +	int channels, i, incr;
   1.266 +	Uint8 *start = wave->abuf;
   1.267 +	Uint8 *end = wave->abuf + wave->alen;
   1.268 +
   1.269 +	Mix_QuerySpec(NULL, &format, &channels);
   1.270 +	incr = (format & 0xFF) * channels;
   1.271 +
   1.272 +	end -= incr;
   1.273 +
   1.274 +	switch (incr) {
   1.275 +		case 8:
   1.276 +			for (i = wave->alen / 2; i >= 0; i -= 1) {
   1.277 +				Uint8 tmp = *start;
   1.278 +				*start = *end;
   1.279 +				*end = tmp;
   1.280 +				start++;
   1.281 +				end--;
   1.282 +			}
   1.283 +			break;
   1.284 +
   1.285 +		case 16:
   1.286 +			for (i = wave->alen / 2; i >= 0; i -= 2) {
   1.287 +				Uint16 tmp = *start;
   1.288 +				*((Uint16 *) start) = *((Uint16 *) end);
   1.289 +				*((Uint16 *) end) = tmp;
   1.290 +				start += 2;
   1.291 +				end -= 2;
   1.292 +			}
   1.293 +			break;
   1.294 +
   1.295 +		case 32:
   1.296 +			for (i = wave->alen / 2; i >= 0; i -= 4) {
   1.297 +				Uint32 tmp = *start;
   1.298 +				*((Uint32 *) start) = *((Uint32 *) end);
   1.299 +				*((Uint32 *) end) = tmp;
   1.300 +				start += 4;
   1.301 +				end -= 4;
   1.302 +			}
   1.303 +			break;
   1.304 +
   1.305 +		default:
   1.306 +			fprintf(stderr, "Unhandled format in sample flipping.\n");
   1.307 +			return;
   1.308 +	}
   1.309  }
   1.310 -#endif
   1.311  
   1.312  
   1.313 -main(int argc, char *argv[])
   1.314 +int main(int argc, char *argv[])
   1.315  {
   1.316  	int audio_rate;
   1.317  	Uint16 audio_format;
   1.318  	int audio_channels;
   1.319  	int loops = 0;
   1.320  	int i;
   1.321 +	int reverse_stereo = 0;
   1.322 +	int reverse_sample = 0;
   1.323 +
   1.324 +	setbuf(stdout, NULL);    /* rcg06132001 for debugging purposes. */
   1.325 +	setbuf(stderr, NULL);    /* rcg06192001 for debugging purposes, too. */
   1.326 +	output_test_warnings();
   1.327  
   1.328  	/* Initialize variables */
   1.329  	audio_rate = MIX_DEFAULT_FREQUENCY;
   1.330 @@ -97,6 +365,12 @@
   1.331  		} else
   1.332  		if ( strcmp(argv[i], "-8") == 0 ) {
   1.333  			audio_format = AUDIO_U8;
   1.334 +		} else
   1.335 +		if ( strcmp(argv[i], "-f") == 0 ) { /* rcg06122001 flip stereo */
   1.336 +			reverse_stereo = 1;
   1.337 +		} else
   1.338 +		if ( strcmp(argv[i], "-F") == 0 ) { /* rcg06172001 flip sample */
   1.339 +			reverse_sample = 1;
   1.340  		} else {
   1.341  			Usage(argv[0]);
   1.342  			return(1);
   1.343 @@ -133,6 +407,10 @@
   1.344  	}
   1.345  	audio_open = 1;
   1.346  
   1.347 +#if (defined TEST_MIX_VERSIONS)
   1.348 +    test_versions();
   1.349 +#endif
   1.350 +
   1.351  	/* Load the requested wave file */
   1.352  	wave = Mix_LoadWAV(argv[i]);
   1.353  	if ( wave == NULL ) {
   1.354 @@ -141,23 +419,44 @@
   1.355  		return(2);
   1.356  	}
   1.357  
   1.358 +	if (reverse_sample) {
   1.359 +		flip_sample(wave);
   1.360 +	}
   1.361 +
   1.362  #ifdef TEST_MIX_CHANNELFINISHED  /* rcg06072001 */
   1.363 -	setbuf(stdout, NULL);
   1.364  	Mix_ChannelFinished(channel_complete_callback);
   1.365  #endif
   1.366  
   1.367 +	if ( (!Mix_SetReverseStereo(MIX_CHANNEL_POST, reverse_stereo)) &&
   1.368 +		 (reverse_stereo) )
   1.369 +	{
   1.370 +		printf("Failed to set up reverse stereo effect!\n");
   1.371 +		printf("Reason: [%s].\n", Mix_GetError());
   1.372 +	}
   1.373 +
   1.374  	/* Play and then exit */
   1.375  	Mix_PlayChannel(0, wave, loops);
   1.376  
   1.377 -#ifdef TEST_MIX_CHANNELFINISHED  /* rcg06072001 */
   1.378 -	while (!channel_is_done) {
   1.379 -		SDL_Delay(100);
   1.380 -	}
   1.381 -#else
   1.382 -	while ( Mix_Playing(0) ) {
   1.383 -		SDL_Delay(100);
   1.384 -	}
   1.385 +	while (still_playing()) {
   1.386 +
   1.387 +#if (defined TEST_MIX_PANNING)  /* rcg06132001 */
   1.388 +		do_panning_update();
   1.389  #endif
   1.390  
   1.391 +#if (defined TEST_MIX_DISTANCE) /* rcg06192001 */
   1.392 +		do_distance_update();
   1.393 +#endif
   1.394 +
   1.395 +#if (defined TEST_MIX_POSITION) /* rcg06202001 */
   1.396 +		do_position_update();
   1.397 +#endif
   1.398 +
   1.399 +		SDL_Delay(1);
   1.400 +
   1.401 +	} /* while still_playing() loop... */
   1.402 +
   1.403  	return(0);
   1.404  }
   1.405 +
   1.406 +/* end of playwave.c ... */
   1.407 +