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