music.c
author Sam Lantinga <slouken@lokigames.com>
Thu, 21 Oct 1999 18:02:08 +0000
changeset 0 4ce2db4db959
child 3 f6dabb779e45
permissions -rw-r--r--
Initial revision
     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 <SDL/SDL_endian.h>
    26 #include <SDL/SDL_audio.h>
    27 
    28 #include "mixer.h"
    29 
    30 /* The music command hack is UNIX specific */
    31 #ifndef unix
    32 #undef CMD_MUSIC
    33 #endif
    34 
    35 #ifdef CMD_MUSIC
    36 #include "music_cmd.h"
    37 #endif
    38 #ifdef WAV_MUSIC
    39 #include "wavestream.h"
    40 #endif
    41 #ifdef MOD_MUSIC
    42 #include "mikmod.h"
    43 #endif
    44 #ifdef MID_MUSIC
    45 #include "timidity.h"
    46 #endif
    47 #ifdef MP3_MUSIC
    48 #include <smpeg/smpeg.h>
    49 
    50 static SDL_AudioSpec used_mixer;
    51 #endif
    52 
    53 int music_active = 1;
    54 static int music_loops = 0;
    55 static char *music_cmd = NULL;
    56 static int samplesize;
    57 static Mix_Music *music_playing = 0;
    58 static int music_volume;
    59 static int music_swap8;
    60 static int music_swap16;
    61 struct _Mix_Music {
    62 	enum {
    63 		MUS_CMD,
    64 		MUS_WAV,
    65 		MUS_MOD,
    66 		MUS_MID,
    67 		MUS_MP3
    68 	} type;
    69 	union {
    70 #ifdef CMD_MUSIC
    71 		MusicCMD *cmd;
    72 #endif
    73 #ifdef WAV_MUSIC
    74 		WAVStream *wave;
    75 #endif
    76 #ifdef MOD_MUSIC
    77 		UNIMOD *module;
    78 #endif
    79 #ifdef MID_MUSIC
    80 		MidiSong *midi;
    81 #endif
    82 #ifdef MP3_MUSIC
    83 		SMPEG *mp3;
    84 #endif
    85 	} data;
    86 	int error;
    87 };
    88 static int timidity_ok;
    89 
    90 /* Mixing function */
    91 void music_mixer(void *udata, Uint8 *stream, int len)
    92 {
    93 	int i;
    94 
    95 	if ( music_playing ) {
    96 		switch (music_playing->type) {
    97 #ifdef CMD_MUSIC
    98 			case MUS_CMD:
    99 				/* The playing is done externally */
   100 				break;
   101 #endif
   102 #ifdef WAV_MUSIC
   103 			case MUS_WAV:
   104 				WAVStream_PlaySome(stream, len);
   105 				break;
   106 #endif
   107 #ifdef MOD_MUSIC
   108 			case MUS_MOD:
   109 				VC_WriteBytes((SBYTE *)stream, len);
   110 				if ( music_swap8 ) {
   111 					Uint8 *dst;
   112 
   113 					dst = stream;
   114 					for ( i=len; i; --i ) {
   115 						*dst++ ^= 0x80;
   116 					}
   117 				} else
   118 				if ( music_swap16 ) {
   119 					Uint8 *dst, tmp;
   120 
   121 					dst = stream;
   122 					for ( i=(len/2); i; --i ) {
   123 						tmp = dst[0];
   124 						dst[0] = dst[1];
   125 						dst[1] = tmp;
   126 						dst += 2;
   127 					}
   128 				}
   129 				break;
   130 #endif
   131 #ifdef MID_MUSIC
   132 			case MUS_MID:
   133 				Timidity_PlaySome(stream, len/samplesize);
   134 				break;
   135 #endif
   136 #ifdef MP3_MUSIC
   137 		    case MUS_MP3:
   138 			    SMPEG_playAudio(music_playing->data.mp3, stream, len);
   139 				break;
   140 #endif
   141 			default:
   142 				/* Unknown music type?? */
   143 				break;
   144 		}
   145 	}
   146 }
   147 
   148 /* Initialize the music players with a certain desired audio format */
   149 int open_music(SDL_AudioSpec *mixer)
   150 {
   151 	int music_error;
   152 
   153 	music_error = 0;
   154 #ifdef WAV_MUSIC
   155 	if ( WAVStream_Init(mixer) < 0 ) {
   156 		++music_error;
   157 	}
   158 #endif
   159 #ifdef MOD_MUSIC
   160 	/* Set the MikMod music format */
   161 	music_swap8 = 0;
   162 	music_swap16 = 0;
   163 	switch (mixer->format) {
   164 
   165 		case AUDIO_U8:
   166 		case AUDIO_S8: {
   167 			if ( mixer->format == AUDIO_S8 ) {
   168 				music_swap8 = 1;
   169 			}
   170 			md_mode = 0;
   171 		}
   172 		break;
   173 
   174 		case AUDIO_S16LSB:
   175 		case AUDIO_S16MSB: {
   176 			/* See if we need to correct MikMod mixing */
   177 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   178 			if ( mixer->format == AUDIO_S16MSB ) {
   179 #else
   180 			if ( mixer->format == AUDIO_S16LSB ) {
   181 #endif
   182 				music_swap16 = 1;
   183 			}
   184 			md_mode = DMODE_16BITS;
   185 		}
   186 		break;
   187 
   188 		default: {
   189 			SDL_SetError("Unknown hardware audio format");
   190 			++music_error;
   191 		}
   192 	}
   193 	if ( mixer->channels > 1 ) {
   194 		if ( mixer->channels > 2 ) {
   195 			SDL_SetError("Hardware uses more channels than mixer");
   196 			++music_error;
   197 		}
   198 		md_mode |= DMODE_STEREO;
   199 	}
   200 	samplesize     = mixer->size/mixer->samples;
   201 	md_mixfreq     = mixer->freq;
   202 	md_device      = 0;
   203 	md_volume      = 96;
   204 	md_musicvolume = 128;
   205 	md_sndfxvolume = 128;
   206 	md_pansep      = 128;
   207 	md_reverb      = 0;
   208 	MikMod_RegisterAllLoaders();
   209 	MikMod_RegisterAllDrivers();
   210 	if ( MikMod_Init() ) {
   211 		SDL_SetError("%s", _mm_errmsg[_mm_errno]);
   212 		++music_error;
   213 	}
   214 #endif
   215 #ifdef MID_MUSIC
   216 	if ( Timidity_Init(mixer->freq,
   217 			mixer->format, mixer->channels, mixer->samples) == 0 ) {
   218 		timidity_ok = 1;
   219 	} else {
   220 		timidity_ok = 0;
   221 	}
   222 #endif
   223 #ifdef MP3_MUSIC
   224 	/* Keep a copy of the mixer */
   225 	used_mixer = *mixer;
   226 #endif
   227 	music_playing = 0;
   228 	if ( music_error ) {
   229 		return(-1);
   230 	}
   231 	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   232 
   233 	return(0);
   234 }
   235 
   236 /* Load a music file */
   237 Mix_Music *Mix_LoadMUS(const char *file)
   238 {
   239 	FILE *fp;
   240 	unsigned char magic[5];
   241 	Mix_Music *music;
   242 
   243 	/* Figure out what kind of file this is */
   244 	fp = fopen(file, "rb");
   245 	if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
   246 		if ( fp != NULL ) {
   247 			fclose(fp);
   248 		}
   249 		SDL_SetError("Couldn't read from '%s'", file);
   250 		return(NULL);
   251 	}
   252 	magic[4] = '\0';
   253 	fclose(fp);
   254 
   255 	/* Allocate memory for the music structure */
   256 	music = (Mix_Music *)malloc(sizeof(Mix_Music));
   257 	if ( music == NULL ) {
   258 		SDL_SetError("Out of memory");
   259 		return(NULL);
   260 	}
   261 	music->error = 0;
   262 
   263 #ifdef CMD_MUSIC
   264 	if ( music_cmd ) {
   265 		music->type = MUS_CMD;
   266 		music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
   267 		if ( music->data.cmd == NULL ) {
   268 			music->error = 1;
   269 		}
   270 	} else
   271 #endif
   272 #ifdef WAV_MUSIC
   273 	/* WAVE files have the magic four bytes "RIFF"
   274 	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
   275 	 */
   276 	if ( (strcmp(magic, "RIFF") == 0) || (strcmp(magic, "FORM") == 0) ) {
   277 		music->type = MUS_WAV;
   278 		music->data.wave = WAVStream_LoadSong(file, magic);
   279 		if ( music->data.wave == NULL ) {
   280 			music->error = 1;
   281 		}
   282 	} else
   283 #endif
   284 #ifdef MID_MUSIC
   285 	/* MIDI files have the magic four bytes "MThd" */
   286 	if ( strcmp(magic, "MThd") == 0 ) {
   287 		music->type = MUS_MID;
   288 		if ( timidity_ok ) {
   289 			music->data.midi = Timidity_LoadSong((char *)file);
   290 			if ( music->data.midi == NULL ) {
   291 				SDL_SetError("%s", Timidity_Error());
   292 				music->error = 1;
   293 			}
   294 		}
   295 		else {
   296 			SDL_SetError("%s", Timidity_Error());
   297 			music->error = 1;
   298 		}
   299 	} else
   300 #endif
   301 #ifdef MP3_MUSIC
   302 	if ( magic[0]==0xFF && (magic[1]&0xF0)==0xF0) {
   303 		SMPEG_Info info;
   304 		music->type = MUS_MP3;
   305 		music->data.mp3 = SMPEG_new(file, &info, 0);
   306 		if(!info.has_audio){
   307 			SDL_SetError("MPEG file does not have any audio stream.");
   308 			music->error = 1;
   309 		}else{
   310 			SMPEG_actualSpec(music->data.mp3, &used_mixer);
   311 		}
   312 	} else
   313 #endif
   314 #ifdef MOD_MUSIC
   315 	if ( 1 ) {
   316 		music->type = MUS_MOD;
   317 		music->data.module = MikMod_LoadSong((char *)file, 64);
   318 		if ( music->data.module == NULL ) {
   319 			SDL_SetError("%s", _mm_errmsg[_mm_errno]);
   320 			music->error = 1;
   321 		}
   322 	} else
   323 #endif
   324 	{
   325 		SDL_SetError("Unrecognized music format");
   326 		music->error = 1;
   327 	}
   328 	if ( music->error ) {
   329 		free(music);
   330 		music = NULL;
   331 	}
   332 	return(music);
   333 }
   334 
   335 /* Free a music chunk previously loaded */
   336 void Mix_FreeMusic(Mix_Music *music)
   337 {
   338 	if ( music ) {
   339 		/* Caution: If music is playing, mixer will crash */
   340 		if ( music == music_playing ) {
   341 			Mix_HaltMusic();
   342 		}
   343 		switch (music->type) {
   344 #ifdef CMD_MUSIC
   345 			case MUS_CMD:
   346 				MusicCMD_FreeSong(music->data.cmd);
   347 				break;
   348 #endif
   349 #ifdef WAV_MUSIC
   350 			case MUS_WAV:
   351 				WAVStream_FreeSong(music->data.wave);
   352 				break;
   353 #endif
   354 #ifdef MOD_MUSIC
   355 			case MUS_MOD:
   356 				MikMod_FreeSong(music->data.module);
   357 				break;
   358 #endif
   359 #ifdef MID_MUSIC
   360 			case MUS_MID:
   361 				Timidity_FreeSong(music->data.midi);
   362 				break;
   363 #endif
   364 #ifdef MP3_MUSIC
   365 		    case MUS_MP3:
   366 				SMPEG_delete(music->data.mp3);
   367 				break;
   368 #endif
   369 			default:
   370 				/* Unknown music type?? */
   371 				break;
   372 		}
   373 		free(music);
   374 	}
   375 }
   376 
   377 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   378 */
   379 int Mix_PlayMusic(Mix_Music *music, int loops)
   380 {
   381 	/* Don't play null pointers :-) */
   382 	if ( music == NULL ) {
   383 		return(-1);
   384 	}
   385 	switch (music->type) {
   386 #ifdef CMD_MUSIC
   387 		case MUS_CMD:
   388 			MusicCMD_SetVolume(music_volume);
   389 			MusicCMD_Start(music->data.cmd);
   390 			break;
   391 #endif
   392 #ifdef WAV_MUSIC
   393 		case MUS_WAV:
   394 			WAVStream_SetVolume(music_volume);
   395 			WAVStream_Start(music->data.wave);
   396 			break;
   397 #endif
   398 #ifdef MOD_MUSIC
   399 		case MUS_MOD:
   400 			Player_SetVolume(music_volume);
   401 			Player_Start(music->data.module);
   402 			Player_SetPosition(0);
   403 			break;
   404 #endif
   405 #ifdef MID_MUSIC
   406 		case MUS_MID:
   407 			Timidity_SetVolume(music_volume);
   408 			Timidity_Start(music->data.midi);
   409 			break;
   410 #endif
   411 #ifdef MP3_MUSIC
   412 	    case MUS_MP3:
   413 			SMPEG_enableaudio(music->data.mp3,1);
   414 			SMPEG_enablevideo(music->data.mp3,0);
   415 			SMPEG_setvolume(music->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0);
   416 			SMPEG_loop(music->data.mp3, loops);
   417 			SMPEG_play(music->data.mp3);
   418 			break;
   419 #endif
   420 		default:
   421 			/* Unknown music type?? */
   422 			return(-1);
   423 	}
   424 	music_active = 1;
   425 	music_playing = music;
   426 	return(0);
   427 }
   428 
   429 /* Set the music volume */
   430 int Mix_VolumeMusic(int volume)
   431 {
   432 	int prev_volume;
   433 
   434 	prev_volume = music_volume;
   435 	if ( volume >= 0 ) {
   436 		if ( volume > SDL_MIX_MAXVOLUME ) {
   437 			volume = SDL_MIX_MAXVOLUME;
   438 		}
   439 		music_volume = volume;
   440 		if ( music_playing ) {
   441 			switch (music_playing->type) {
   442 #ifdef CMD_MUSIC
   443 				case MUS_CMD:
   444 					MusicCMD_SetVolume(music_volume);
   445 					break;
   446 #endif
   447 #ifdef WAV_MUSIC
   448 				case MUS_WAV:
   449 					WAVStream_SetVolume(music_volume);
   450 					break;
   451 #endif
   452 #ifdef MOD_MUSIC
   453 				case MUS_MOD:
   454 					Player_SetVolume(music_volume);
   455 					break;
   456 #endif
   457 #ifdef MID_MUSIC
   458 				case MUS_MID:
   459 					Timidity_SetVolume(music_volume);
   460 					break;
   461 #endif
   462 #ifdef MP3_MUSIC
   463 			    case MUS_MP3:
   464 					SMPEG_setvolume(music_playing->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0);
   465 					break;
   466 #endif
   467 				default:
   468 					/* Unknown music type?? */
   469 					break;
   470 			}
   471 		}
   472 	}
   473 	return(prev_volume);
   474 }
   475 
   476 /* Halt playing of music */
   477 int Mix_HaltMusic(void)
   478 {
   479 	if ( music_playing ) {
   480 		switch (music_playing->type) {
   481 #ifdef CMD_MUSIC
   482 			case MUS_CMD:
   483 				MusicCMD_Stop(music_playing->data.cmd);
   484 				break;
   485 #endif
   486 #ifdef WAV_MUSIC
   487 			case MUS_WAV:
   488 				WAVStream_Stop();
   489 				break;
   490 #endif
   491 #ifdef MOD_MUSIC
   492 			case MUS_MOD:
   493 				Player_Stop();
   494 				break;
   495 #endif
   496 #ifdef MID_MUSIC
   497 			case MUS_MID:
   498 				Timidity_Stop();
   499 				break;
   500 #endif
   501 #ifdef MP3_MUSIC
   502 		    case MUS_MP3:
   503 				SMPEG_stop(music_playing->data.mp3);
   504 				break;
   505 #endif
   506 			default:
   507 				/* Unknown music type?? */
   508 				return(-1);
   509 		}
   510 		music_playing = 0;
   511 	}
   512 	return(0);
   513 }
   514 
   515 /* Pause/Resume the music stream */
   516 void Mix_PauseMusic(void)
   517 {
   518 	if ( music_playing ) {
   519 		switch ( music_playing->type ) {
   520 #ifdef CMD_MUSIC
   521 		case MUS_CMD:
   522 			MusicCMD_Pause(music_playing->data.cmd);
   523 			break;
   524 #endif
   525 #ifdef MP3_MUSIC
   526 		case MUS_MP3:
   527 			SMPEG_pause(music_playing->data.mp3);
   528 			break;
   529 #endif
   530 		}
   531 	}
   532 	music_active = 0;
   533 }
   534 void Mix_ResumeMusic(void)
   535 {
   536 	if ( music_playing ) {
   537 		switch ( music_playing->type ) {
   538 #ifdef CMD_MUSIC
   539 		case MUS_CMD:
   540 			MusicCMD_Resume(music_playing->data.cmd);
   541 			break;
   542 #endif
   543 #ifdef MP3_MUSIC
   544 		case MUS_MP3:
   545 			SMPEG_pause(music_playing->data.mp3);
   546 			break;
   547 #endif
   548 		}
   549 	}
   550 	music_active = 1;
   551 }
   552 
   553 void Mix_RewindMusic(void)
   554 {
   555 	if ( music_playing ) {
   556 		switch ( music_playing->type ) {
   557 #ifdef MP3_MUSIC
   558 		case MUS_MP3:
   559 			SMPEG_rewind(music_playing->data.mp3);
   560 			break;
   561 #endif
   562 		}
   563 	}
   564 }
   565 
   566 /* Check the status of the music */
   567 int Mix_PlayingMusic(void)
   568 {
   569 	if ( music_playing ) {
   570 		switch (music_playing->type) {
   571 #ifdef CMD_MUSIC
   572 			case MUS_CMD:
   573 				if (!MusicCMD_Active(music_playing->data.cmd)) {
   574 					music_playing = 0;
   575 				}
   576 				break;
   577 #endif
   578 #ifdef WAV_MUSIC
   579 			case MUS_WAV:
   580 				if ( ! WAVStream_Active() ) {
   581 					music_playing = 0;
   582 				}
   583 				break;
   584 #endif
   585 #ifdef MOD_MUSIC
   586 			case MUS_MOD:
   587 				if ( ! Player_Active() ) {
   588 					music_playing = 0;
   589 				}
   590 				break;
   591 #endif
   592 #ifdef MID_MUSIC
   593 			case MUS_MID:
   594 				if ( ! Timidity_Active() ) {
   595 					music_playing = 0;
   596 				}
   597 				break;
   598 #endif
   599 #ifdef MP3_MUSIC
   600 			case MUS_MP3:
   601 				if(SMPEG_status(music_playing->data.mp3)!=SMPEG_PLAYING)
   602 					music_playing = 0;
   603 				break;
   604 #endif
   605 		}
   606 	}
   607 	return(music_playing ? 1 : 0);
   608 }
   609 
   610 /* Set the external music playback command */
   611 int Mix_SetMusicCMD(const char *command)
   612 {
   613 	Mix_HaltMusic();
   614 	if ( music_cmd ) {
   615 		free(music_cmd);
   616 		music_cmd = NULL;
   617 	}
   618 	if ( command ) {
   619 		music_cmd = (char *)malloc(strlen(command)+1);
   620 		if ( music_cmd == NULL ) {
   621 			return(-1);
   622 		}
   623 		strcpy(music_cmd, command);
   624 	}
   625 	return(0);
   626 }
   627 
   628 /* Uninitialize the music players */
   629 void close_music(void)
   630 {
   631 	Mix_HaltMusic();
   632 #ifdef CMD_MUSIC
   633 	Mix_SetMusicCMD(NULL);
   634 #endif
   635 #ifdef MOD_MUSIC
   636 	MikMod_Exit();
   637 #endif
   638 }
   639