music.c
author Stephane Peter <megastep@lokigames.com>
Tue, 26 Oct 1999 02:24:17 +0000
changeset 7 e73da9dc4bdc
parent 4 5c4485704b30
child 10 2fbd0414a1fc
permissions -rw-r--r--
*** empty log message ***
     1 /*
     2     MIXERLIB:  An audio mixer library based on the SDL library
     3     Copyright (C) 1997-1999  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     5635-34 Springhouse Dr.
    21     Pleasanton, CA 94588 (USA)
    22     slouken@devolution.com
    23 */
    24 
    25 #include <stdlib.h>
    26 #include <string.h>
    27 #include <SDL/SDL_endian.h>
    28 #include <SDL/SDL_audio.h>
    29 
    30 #include "mixer.h"
    31 
    32 /* The music command hack is UNIX specific */
    33 #ifndef unix
    34 #undef CMD_MUSIC
    35 #endif
    36 
    37 #ifdef CMD_MUSIC
    38 #include "music_cmd.h"
    39 #endif
    40 #ifdef WAV_MUSIC
    41 #include "wavestream.h"
    42 #endif
    43 #ifdef MOD_MUSIC
    44 #include "mikmod.h"
    45 #endif
    46 #ifdef MID_MUSIC
    47 #include "timidity.h"
    48 #endif
    49 #ifdef MP3_MUSIC
    50 #include <smpeg/smpeg.h>
    51 
    52 static SDL_AudioSpec used_mixer;
    53 #endif
    54 
    55 int music_active = 1;
    56 static int music_stopped = 0;
    57 static int music_loops = 0;
    58 static char *music_cmd = NULL;
    59 static int samplesize;
    60 static Mix_Music *music_playing = 0;
    61 static int music_volume;
    62 static int music_swap8;
    63 static int music_swap16;
    64 
    65 struct _Mix_Music {
    66 	enum {
    67 		MUS_CMD,
    68 		MUS_WAV,
    69 		MUS_MOD,
    70 		MUS_MID,
    71 		MUS_MP3
    72 	} type;
    73 	union {
    74 #ifdef CMD_MUSIC
    75 		MusicCMD *cmd;
    76 #endif
    77 #ifdef WAV_MUSIC
    78 		WAVStream *wave;
    79 #endif
    80 #ifdef MOD_MUSIC
    81 		UNIMOD *module;
    82 #endif
    83 #ifdef MID_MUSIC
    84 		MidiSong *midi;
    85 #endif
    86 #ifdef MP3_MUSIC
    87 		SMPEG *mp3;
    88 #endif
    89 	} data;
    90 	Mix_Fading fading;
    91 	int fade_volume;
    92 	int fade_length;
    93 	Uint32 ticks_fade;
    94 	int error;
    95 };
    96 static int timidity_ok;
    97 
    98 static void lowlevel_halt(void);
    99 
   100 /* Mixing function */
   101 void music_mixer(void *udata, Uint8 *stream, int len)
   102 {
   103 	int i;
   104 
   105 	if ( music_playing ) {
   106 		if ( music_stopped ) {
   107 			/* To avoid concurrency problems and the use of mutexes,
   108 			   the music is always stopped from the sound thread */
   109 			lowlevel_halt(); /* This function sets music_playing to NULL */
   110 			return;
   111 		}	
   112 		if ( music_playing->fading != MIX_NO_FADING ) {
   113 			Uint32 ticks = SDL_GetTicks() - music_playing->ticks_fade;
   114 			if( ticks > music_playing->fade_length ) {
   115 				if ( music_playing->fading == MIX_FADING_OUT ) {
   116 					music_volume = music_playing->fade_volume;
   117 					music_playing->fading = MIX_NO_FADING;
   118 					lowlevel_halt();
   119 					return;
   120 				}
   121 				music_playing->fading = MIX_NO_FADING;
   122 			} else {
   123 				if ( music_playing->fading == MIX_FADING_OUT ) {
   124 					Mix_VolumeMusic((music_playing->fade_volume * (music_playing->fade_length-ticks)) 
   125 									/ music_playing->fade_length);
   126 				} else { /* Fading in */
   127 					Mix_VolumeMusic((music_playing->fade_volume * ticks) 
   128 									/ music_playing->fade_length);
   129 				}
   130 			}
   131 		}
   132 		switch (music_playing->type) {
   133 #ifdef CMD_MUSIC
   134 			case MUS_CMD:
   135 				/* The playing is done externally */
   136 				break;
   137 #endif
   138 #ifdef WAV_MUSIC
   139 			case MUS_WAV:
   140 				WAVStream_PlaySome(stream, len);
   141 				break;
   142 #endif
   143 #ifdef MOD_MUSIC
   144 			case MUS_MOD:
   145 				VC_WriteBytes((SBYTE *)stream, len);
   146 				if ( music_swap8 ) {
   147 					Uint8 *dst;
   148 
   149 					dst = stream;
   150 					for ( i=len; i; --i ) {
   151 						*dst++ ^= 0x80;
   152 					}
   153 				} else
   154 				if ( music_swap16 ) {
   155 					Uint8 *dst, tmp;
   156 
   157 					dst = stream;
   158 					for ( i=(len/2); i; --i ) {
   159 						tmp = dst[0];
   160 						dst[0] = dst[1];
   161 						dst[1] = tmp;
   162 						dst += 2;
   163 					}
   164 				}
   165 				break;
   166 #endif
   167 #ifdef MID_MUSIC
   168 			case MUS_MID:
   169 				Timidity_PlaySome(stream, len/samplesize);
   170 				break;
   171 #endif
   172 #ifdef MP3_MUSIC
   173 		    case MUS_MP3:
   174 			    SMPEG_playAudio(music_playing->data.mp3, stream, len);
   175 				break;
   176 #endif
   177 			default:
   178 				/* Unknown music type?? */
   179 				break;
   180 		}
   181 	}
   182 }
   183 
   184 /* Initialize the music players with a certain desired audio format */
   185 int open_music(SDL_AudioSpec *mixer)
   186 {
   187 	int music_error;
   188 
   189 	music_error = 0;
   190 #ifdef WAV_MUSIC
   191 	if ( WAVStream_Init(mixer) < 0 ) {
   192 		++music_error;
   193 	}
   194 #endif
   195 #ifdef MOD_MUSIC
   196 	/* Set the MikMod music format */
   197 	music_swap8 = 0;
   198 	music_swap16 = 0;
   199 	switch (mixer->format) {
   200 
   201 		case AUDIO_U8:
   202 		case AUDIO_S8: {
   203 			if ( mixer->format == AUDIO_S8 ) {
   204 				music_swap8 = 1;
   205 			}
   206 			md_mode = 0;
   207 		}
   208 		break;
   209 
   210 		case AUDIO_S16LSB:
   211 		case AUDIO_S16MSB: {
   212 			/* See if we need to correct MikMod mixing */
   213 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   214 			if ( mixer->format == AUDIO_S16MSB ) {
   215 #else
   216 			if ( mixer->format == AUDIO_S16LSB ) {
   217 #endif
   218 				music_swap16 = 1;
   219 			}
   220 			md_mode = DMODE_16BITS;
   221 		}
   222 		break;
   223 
   224 		default: {
   225 			SDL_SetError("Unknown hardware audio format");
   226 			++music_error;
   227 		}
   228 	}
   229 	if ( mixer->channels > 1 ) {
   230 		if ( mixer->channels > 2 ) {
   231 			SDL_SetError("Hardware uses more channels than mixer");
   232 			++music_error;
   233 		}
   234 		md_mode |= DMODE_STEREO;
   235 	}
   236 	samplesize     = mixer->size/mixer->samples;
   237 	md_mixfreq     = mixer->freq;
   238 	md_device      = 0;
   239 	md_volume      = 96;
   240 	md_musicvolume = 128;
   241 	md_sndfxvolume = 128;
   242 	md_pansep      = 128;
   243 	md_reverb      = 0;
   244 	MikMod_RegisterAllLoaders();
   245 	MikMod_RegisterAllDrivers();
   246 	if ( MikMod_Init() ) {
   247 		SDL_SetError("%s", _mm_errmsg[_mm_errno]);
   248 		++music_error;
   249 	}
   250 #endif
   251 #ifdef MID_MUSIC
   252 	if ( Timidity_Init(mixer->freq,
   253 			mixer->format, mixer->channels, mixer->samples) == 0 ) {
   254 		timidity_ok = 1;
   255 	} else {
   256 		timidity_ok = 0;
   257 	}
   258 #endif
   259 #ifdef MP3_MUSIC
   260 	/* Keep a copy of the mixer */
   261 	used_mixer = *mixer;
   262 #endif
   263 	music_playing = 0;
   264 	music_stopped = 0;
   265 
   266 	if ( music_error ) {
   267 		return(-1);
   268 	}
   269 	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   270 
   271 	return(0);
   272 }
   273 
   274 /* Load a music file */
   275 Mix_Music *Mix_LoadMUS(const char *file)
   276 {
   277 	FILE *fp;
   278 	unsigned char magic[5];
   279 	Mix_Music *music;
   280 
   281 	/* Figure out what kind of file this is */
   282 	fp = fopen(file, "rb");
   283 	if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
   284 		if ( fp != NULL ) {
   285 			fclose(fp);
   286 		}
   287 		SDL_SetError("Couldn't read from '%s'", file);
   288 		return(NULL);
   289 	}
   290 	magic[4] = '\0';
   291 	fclose(fp);
   292 
   293 	/* Allocate memory for the music structure */
   294 	music = (Mix_Music *)malloc(sizeof(Mix_Music));
   295 	if ( music == NULL ) {
   296 		SDL_SetError("Out of memory");
   297 		return(NULL);
   298 	}
   299 	music->error = 0;
   300 
   301 #ifdef CMD_MUSIC
   302 	if ( music_cmd ) {
   303 		music->type = MUS_CMD;
   304 		music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
   305 		if ( music->data.cmd == NULL ) {
   306 			music->error = 1;
   307 		}
   308 	} else
   309 #endif
   310 #ifdef WAV_MUSIC
   311 	/* WAVE files have the magic four bytes "RIFF"
   312 	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
   313 	 */
   314 	if ( (strcmp(magic, "RIFF") == 0) || (strcmp(magic, "FORM") == 0) ) {
   315 		music->type = MUS_WAV;
   316 		music->data.wave = WAVStream_LoadSong(file, magic);
   317 		if ( music->data.wave == NULL ) {
   318 			music->error = 1;
   319 		}
   320 	} else
   321 #endif
   322 #ifdef MID_MUSIC
   323 	/* MIDI files have the magic four bytes "MThd" */
   324 	if ( strcmp(magic, "MThd") == 0 ) {
   325 		music->type = MUS_MID;
   326 		if ( timidity_ok ) {
   327 			music->data.midi = Timidity_LoadSong((char *)file);
   328 			if ( music->data.midi == NULL ) {
   329 				SDL_SetError("%s", Timidity_Error());
   330 				music->error = 1;
   331 			}
   332 		}
   333 		else {
   334 			SDL_SetError("%s", Timidity_Error());
   335 			music->error = 1;
   336 		}
   337 	} else
   338 #endif
   339 #ifdef MP3_MUSIC
   340 	if ( magic[0]==0xFF && (magic[1]&0xF0)==0xF0) {
   341 		SMPEG_Info info;
   342 		music->type = MUS_MP3;
   343 		music->data.mp3 = SMPEG_new(file, &info, 0);
   344 		if(!info.has_audio){
   345 			SDL_SetError("MPEG file does not have any audio stream.");
   346 			music->error = 1;
   347 		}else{
   348 			SMPEG_actualSpec(music->data.mp3, &used_mixer);
   349 		}
   350 	} else
   351 #endif
   352 #ifdef MOD_MUSIC
   353 	if ( 1 ) {
   354 		music->type = MUS_MOD;
   355 		music->data.module = MikMod_LoadSong((char *)file, 64);
   356 		if ( music->data.module == NULL ) {
   357 			SDL_SetError("%s", _mm_errmsg[_mm_errno]);
   358 			music->error = 1;
   359 		}
   360 	} else
   361 #endif
   362 	{
   363 		SDL_SetError("Unrecognized music format");
   364 		music->error = 1;
   365 	}
   366 	if ( music->error ) {
   367 		free(music);
   368 		music = NULL;
   369 	}
   370 	return(music);
   371 }
   372 
   373 /* Free a music chunk previously loaded */
   374 void Mix_FreeMusic(Mix_Music *music)
   375 {
   376 	if ( music ) {
   377 		/* Caution: If music is playing, mixer will crash */
   378 		if ( music == music_playing && !music_stopped ) {
   379 			if ( music->fading == MIX_FADING_OUT ) {
   380 				/* Wait for the fade out to finish */
   381 				while(music->fading == MIX_FADING_OUT)
   382 					SDL_Delay(100);
   383 			} else {
   384 				Mix_HaltMusic(); /* Stop it immediately */
   385 			}
   386 		}
   387 		switch (music->type) {
   388 #ifdef CMD_MUSIC
   389 			case MUS_CMD:
   390 				MusicCMD_FreeSong(music->data.cmd);
   391 				break;
   392 #endif
   393 #ifdef WAV_MUSIC
   394 			case MUS_WAV:
   395 				WAVStream_FreeSong(music->data.wave);
   396 				break;
   397 #endif
   398 #ifdef MOD_MUSIC
   399 			case MUS_MOD:
   400 				MikMod_FreeSong(music->data.module);
   401 				break;
   402 #endif
   403 #ifdef MID_MUSIC
   404 			case MUS_MID:
   405 				Timidity_FreeSong(music->data.midi);
   406 				break;
   407 #endif
   408 #ifdef MP3_MUSIC
   409 		    case MUS_MP3:
   410 				SMPEG_delete(music->data.mp3);
   411 				break;
   412 #endif
   413 			default:
   414 				/* Unknown music type?? */
   415 				break;
   416 		}
   417 		free(music);
   418 	}
   419 }
   420 
   421 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   422 */
   423 int Mix_PlayMusic(Mix_Music *music, int loops)
   424 {
   425 	/* Don't play null pointers :-) */
   426 	if ( music == NULL ) {
   427 		return(-1);
   428 	}
   429 	/* If the current music is fading out, wait for the fade to complete */
   430 	while ( music_playing && !music_stopped && music_playing->fading==MIX_FADING_OUT ) {
   431 		SDL_Delay(100);
   432 	}
   433 	switch (music->type) {
   434 #ifdef CMD_MUSIC
   435 		case MUS_CMD:
   436 			MusicCMD_SetVolume(music_volume);
   437 			MusicCMD_Start(music->data.cmd);
   438 			break;
   439 #endif
   440 #ifdef WAV_MUSIC
   441 		case MUS_WAV:
   442 			WAVStream_SetVolume(music_volume);
   443 			WAVStream_Start(music->data.wave);
   444 			break;
   445 #endif
   446 #ifdef MOD_MUSIC
   447 		case MUS_MOD:
   448 			Player_SetVolume(music_volume);
   449 			Player_Start(music->data.module);
   450 			Player_SetPosition(0);
   451 			break;
   452 #endif
   453 #ifdef MID_MUSIC
   454 		case MUS_MID:
   455 			Timidity_SetVolume(music_volume);
   456 			Timidity_Start(music->data.midi);
   457 			break;
   458 #endif
   459 #ifdef MP3_MUSIC
   460 	    case MUS_MP3:
   461 			SMPEG_enableaudio(music->data.mp3,1);
   462 			SMPEG_enablevideo(music->data.mp3,0);
   463 			SMPEG_setvolume(music->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0);
   464 			SMPEG_loop(music->data.mp3, loops);
   465 			SMPEG_play(music->data.mp3);
   466 			break;
   467 #endif
   468 		default:
   469 			/* Unknown music type?? */
   470 			return(-1);
   471 	}
   472 	music_active = 1;
   473 	music_stopped = 0;
   474 	music_playing = music;
   475 	music_playing->fading = MIX_NO_FADING;
   476 	return(0);
   477 }
   478 
   479 /* Fade in a music over "ms" milliseconds */
   480 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   481 {
   482 	if ( music && music_volume > 0 ) { /* No need to fade if we can't hear it */
   483 		music->fade_volume = music_volume;
   484 		music_volume = 0;
   485 		if(Mix_PlayMusic(music,loops)<0)
   486 			return(-1);
   487 		music_playing->fading = MIX_FADING_IN;
   488 		music_playing->fade_length = ms;
   489 		music_playing->ticks_fade = SDL_GetTicks();
   490 	}
   491 	return(0);
   492 }
   493 
   494 /* Set the music volume */
   495 int Mix_VolumeMusic(int volume)
   496 {
   497 	int prev_volume;
   498 
   499 	prev_volume = music_volume;
   500 	if ( volume < 0 ) {
   501 		volume = 0;
   502 	}
   503 	if ( volume > SDL_MIX_MAXVOLUME ) {
   504 		volume = SDL_MIX_MAXVOLUME;
   505 	}
   506 	music_volume = volume;
   507 	if ( music_playing && !music_stopped ) {
   508 		switch (music_playing->type) {
   509 #ifdef CMD_MUSIC
   510 		case MUS_CMD:
   511 			MusicCMD_SetVolume(music_volume);
   512 			break;
   513 #endif
   514 #ifdef WAV_MUSIC
   515 		case MUS_WAV:
   516 			WAVStream_SetVolume(music_volume);
   517 			break;
   518 #endif
   519 #ifdef MOD_MUSIC
   520 		case MUS_MOD:
   521 			Player_SetVolume(music_volume);
   522 			break;
   523 #endif
   524 #ifdef MID_MUSIC
   525 		case MUS_MID:
   526 			Timidity_SetVolume(music_volume);
   527 			break;
   528 #endif
   529 #ifdef MP3_MUSIC
   530 		case MUS_MP3:
   531 			SMPEG_setvolume(music_playing->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0);
   532 			break;
   533 #endif
   534 		default:
   535 			/* Unknown music type?? */
   536 			break;
   537 		}
   538 	}
   539 	return(prev_volume);
   540 }
   541 
   542 static void lowlevel_halt(void)
   543 {
   544 	switch (music_playing->type) {
   545 #ifdef CMD_MUSIC
   546 	case MUS_CMD:
   547 		MusicCMD_Stop(music_playing->data.cmd);
   548 		break;
   549 #endif
   550 #ifdef WAV_MUSIC
   551 	case MUS_WAV:
   552 		WAVStream_Stop();
   553 		break;
   554 #endif
   555 #ifdef MOD_MUSIC
   556 	case MUS_MOD:
   557 		Player_Stop();
   558 		break;
   559 #endif
   560 #ifdef MID_MUSIC
   561 	case MUS_MID:
   562 		Timidity_Stop();
   563 		break;
   564 #endif
   565 #ifdef MP3_MUSIC
   566 	case MUS_MP3:
   567 		SMPEG_stop(music_playing->data.mp3);
   568 		break;
   569 #endif
   570 	default:
   571 		/* Unknown music type?? */
   572 		return;
   573 	}
   574 	if(music_playing->fading != MIX_NO_FADING) /* Restore volume */
   575 		music_volume = music_playing->fade_volume;
   576 	music_playing->fading = MIX_NO_FADING;
   577 	music_playing = 0;
   578 	music_active = 0;
   579 	music_stopped = 0;
   580 }
   581 
   582 /* Halt playing of music */
   583 int Mix_HaltMusic(void)
   584 {
   585 	if ( music_playing && !music_stopped ) {
   586 		/* Mark the music to be stopped from the sound thread */
   587 		music_stopped = 1;
   588 		/* Wait for it to be actually stopped */
   589 		while ( music_playing )
   590 			SDL_Delay(10);
   591 	}
   592 	return(0);
   593 }
   594 
   595 /* Progressively stop the music */
   596 int Mix_FadeOutMusic(int ms)
   597 {
   598 	if ( music_playing && !music_stopped && music_playing->fading==MIX_NO_FADING ) {
   599 		if ( music_volume>0 ) {
   600 			music_playing->fading = MIX_FADING_OUT;
   601 			music_playing->fade_volume = music_volume;
   602 			music_playing->fade_length = ms;
   603 			music_playing->ticks_fade = SDL_GetTicks();
   604 			return(1);
   605 		}
   606 	}
   607 	return(0);
   608 }
   609 
   610 Mix_Fading Mix_FadingMusic(void)
   611 {
   612 	if( music_playing && !music_stopped )
   613 		return music_playing->fading;
   614 	return MIX_NO_FADING;
   615 }
   616 
   617 /* Pause/Resume the music stream */
   618 void Mix_PauseMusic(void)
   619 {
   620 	if ( music_playing && !music_stopped ) {
   621 		switch ( music_playing->type ) {
   622 #ifdef CMD_MUSIC
   623 		case MUS_CMD:
   624 			MusicCMD_Pause(music_playing->data.cmd);
   625 			break;
   626 #endif
   627 #ifdef MP3_MUSIC
   628 		case MUS_MP3:
   629 			SMPEG_pause(music_playing->data.mp3);
   630 			break;
   631 #endif
   632 		}
   633 	}
   634 	music_active = 0;
   635 }
   636 
   637 void Mix_ResumeMusic(void)
   638 {
   639 	if ( music_playing && !music_stopped ) {
   640 		switch ( music_playing->type ) {
   641 #ifdef CMD_MUSIC
   642 		case MUS_CMD:
   643 			MusicCMD_Resume(music_playing->data.cmd);
   644 			break;
   645 #endif
   646 #ifdef MP3_MUSIC
   647 		case MUS_MP3:
   648 			SMPEG_pause(music_playing->data.mp3);
   649 			break;
   650 #endif
   651 		}
   652 	}
   653 	music_active = 1;
   654 }
   655 
   656 void Mix_RewindMusic(void)
   657 {
   658 	if ( music_playing && !music_stopped ) {
   659 		switch ( music_playing->type ) {
   660 #ifdef MP3_MUSIC
   661 		case MUS_MP3:
   662 			SMPEG_rewind(music_playing->data.mp3);
   663 			break;
   664 #endif
   665 			/* TODO: Implement this for other music backends */
   666 		}
   667 	}
   668 }
   669 
   670 /* Check the status of the music */
   671 int Mix_PlayingMusic(void)
   672 {
   673 	if ( music_playing && !music_stopped ) {
   674 		switch (music_playing->type) {
   675 #ifdef CMD_MUSIC
   676 			case MUS_CMD:
   677 				if (!MusicCMD_Active(music_playing->data.cmd)) {
   678 					music_playing = 0;
   679 				}
   680 				break;
   681 #endif
   682 #ifdef WAV_MUSIC
   683 			case MUS_WAV:
   684 				if ( ! WAVStream_Active() ) {
   685 					music_playing = 0;
   686 				}
   687 				break;
   688 #endif
   689 #ifdef MOD_MUSIC
   690 			case MUS_MOD:
   691 				if ( ! Player_Active() ) {
   692 					music_playing = 0;
   693 				}
   694 				break;
   695 #endif
   696 #ifdef MID_MUSIC
   697 			case MUS_MID:
   698 				if ( ! Timidity_Active() ) {
   699 					music_playing = 0;
   700 				}
   701 				break;
   702 #endif
   703 #ifdef MP3_MUSIC
   704 			case MUS_MP3:
   705 				if(SMPEG_status(music_playing->data.mp3)!=SMPEG_PLAYING)
   706 					music_playing = 0;
   707 				break;
   708 #endif
   709 		}
   710 	}
   711 	return(music_playing ? 1 : 0);
   712 }
   713 
   714 /* Set the external music playback command */
   715 int Mix_SetMusicCMD(const char *command)
   716 {
   717 	Mix_HaltMusic();
   718 	if ( music_cmd ) {
   719 		free(music_cmd);
   720 		music_cmd = NULL;
   721 	}
   722 	if ( command ) {
   723 		music_cmd = (char *)malloc(strlen(command)+1);
   724 		if ( music_cmd == NULL ) {
   725 			return(-1);
   726 		}
   727 		strcpy(music_cmd, command);
   728 	}
   729 	return(0);
   730 }
   731 
   732 /* Uninitialize the music players */
   733 void close_music(void)
   734 {
   735 	Mix_HaltMusic();
   736 #ifdef CMD_MUSIC
   737 	Mix_SetMusicCMD(NULL);
   738 #endif
   739 #ifdef MOD_MUSIC
   740 	MikMod_Exit();
   741 #endif
   742 }
   743