////////////////////////////////////////////////////////////////////// // XLogical - A puzzle game // // Copyright (C) 2000 Neil Brown, Tom Warkentin // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // or at the website: http://www.gnu.org // //////////////////////////////////////////////////////////////////////// #ifndef USE_HASH_MAP #include #else #include #endif #include #include #include #include #include "defs.h" #include "exception.h" #include "properties.h" #include "sdl_audio.h" #ifndef USE_HASH_MAP typedef map sound_cache_t; #else typedef hash_map sound_cache_t; #endif bool gAudioEnabled = false; bool gAudioInitialized = false; sound_cache_t gSoundCache; Mix_Music * gCurrMusicPtr = NULL; string gCurrMusicName; string gCurrMusicType; void get_music_info( char *aPath, string& aMusicName, string& aMusicType ) { char *start, *end; int len = strlen( aPath ); for( end=aPath+len; end >= 0; end-=1 ) { if (*end == '.') break; } for( start=end; start >= 0; start-=1 ) { if (*start == *PATHSEP) break; } char *buf = new char[len+1]; strncpy( buf, start+1, end-start-1 ); buf[end-start-1] = '\0'; gCurrMusicName = buf; strncpy( buf, end+1, strlen( end ) - 1); buf[strlen( end )-1] = '\0'; gCurrMusicType = buf; delete [] buf; } Csdl_audio::Csdl_audio() : fMusicFinishedFunc( NULL ), fMusicVolume( 0.7 ), fSoundVolume( 0.7 ) { } Csdl_audio::~Csdl_audio() { } void Csdl_audio::setup() { gAudioEnabled = atoi( properties::instance().get( "audio.enabled" ).c_str() ) > 0; if (gAudioEnabled && !gAudioInitialized) { fMusicVolume = atof( properties::instance().get( "music.volume" ).c_str() ); fSoundVolume = atof( properties::instance().get( "sound.volume" ).c_str() ); int channels = atoi( properties::instance().get( "audio.channels").c_str() ); int frequency = atoi( properties::instance().get( "audio.frequency").c_str() ); int chunksize = atoi( properties::instance().get( "audio.chunksize").c_str() ); int format = atoi( properties::instance().get( "audio.format" ).c_str() ); switch( format ) { case 1: format = AUDIO_U8; break; case 2: format = AUDIO_S8; break; case 3: format = AUDIO_U16LSB; break; case 4: format = AUDIO_S16LSB; break; case 5: format = AUDIO_U16MSB; break; case 6: format = AUDIO_S16MSB; break; default: char buf[100]; sprintf( buf, "audio.format=%d unsupported", format ); ThrowEx( buf ); break; } if (SDL_InitSubSystem( SDL_INIT_AUDIO ) < 0) { ThrowEx( string( "Failed to initialize audio" ) ); } if (Mix_OpenAudio( frequency, format, channels, chunksize ) != 0) { ThrowEx( string( "Mix_OpenAudio: " ) + Mix_GetError() ); } gAudioInitialized = true; } } void Csdl_audio::set_music_finished_func( music_finished_func_t aCallback ) { if (!gAudioEnabled) { return; } fMusicFinishedFunc = aCallback; Mix_HookMusicFinished( fMusicFinishedFunc ); } float Csdl_audio::set_music_volume( float aVolumePercent ) { if (aVolumePercent >= 0.0) { fMusicVolume = aVolumePercent; if (gAudioEnabled) { Mix_VolumeMusic( static_cast( fMusicVolume * MIX_MAX_VOLUME ) ); } } return( fMusicVolume ); } void Csdl_audio::play_current_music() { if (!gAudioEnabled) { return; } if (gCurrMusicPtr) { if (Mix_PlayMusic( gCurrMusicPtr, 1 ) != 0) { cerr << "Mix_PlayMusic: " << Mix_GetError() << endl; return; } Mix_VolumeMusic( static_cast( fMusicVolume * MIX_MAX_VOLUME ) ); } } void Csdl_audio::play_music( const char *aMusicName ) { if (!gAudioEnabled) { return; } if (gCurrMusicPtr) { Mix_HaltMusic(); Mix_FreeMusic( gCurrMusicPtr ); gCurrMusicPtr = NULL; } Mix_Music * musicPtr = NULL; musicPtr = Mix_LoadMUS( aMusicName ); if (!musicPtr) { cerr << "Mix_LoadMUS: " << Mix_GetError() << endl; return; } gCurrMusicPtr = musicPtr; if (Mix_PlayMusic( gCurrMusicPtr, 1 ) != 0) { cerr << "Mix_PlayMusic: " << Mix_GetError() << endl; return; } Mix_VolumeMusic( static_cast( fMusicVolume * MIX_MAX_VOLUME ) ); get_music_info( const_cast(aMusicName), gCurrMusicName, gCurrMusicType ); } void Csdl_audio::stop_music() { if (!gAudioEnabled || !gCurrMusicPtr) { return; } (void) Mix_HaltMusic(); Mix_FreeMusic( gCurrMusicPtr ); gCurrMusicPtr = NULL; } char * Csdl_audio::get_current_music_name() { if (!gAudioEnabled) { return( NULL ); } if (gCurrMusicName.length() > 0) { return( const_cast(gCurrMusicName.c_str()) ); } return( NULL ); } char * Csdl_audio::get_current_music_type() { if (!gAudioEnabled) { return( NULL ); } if (gCurrMusicType.length() > 0) { return( const_cast(gCurrMusicType.c_str()) ); } return( NULL ); } float Csdl_audio::set_sound_volume( float aVolumePercent ) { if (aVolumePercent >= 0.0) { fSoundVolume = aVolumePercent; } return( fSoundVolume ); } void Csdl_audio::load_sound( const char *aSoundName ) { if (!gAudioEnabled) { return; } Mix_Chunk * soundPtr = NULL; sound_cache_t::iterator iter = gSoundCache.find( aSoundName ); if (iter != gSoundCache.end()) { Mix_FreeChunk( iter->second ); gSoundCache.erase( iter ); } soundPtr = Mix_LoadWAV( aSoundName ); if (!soundPtr) { ThrowEx( string( "Mix_LoadWAV: " ) + Mix_GetError() ); } gSoundCache[aSoundName] = soundPtr; } void Csdl_audio::unload_sound( const char *aSoundName ) { if (!gAudioEnabled) { return; } sound_cache_t::iterator iter = gSoundCache.find( aSoundName ); if (iter != gSoundCache.end()) { Mix_FreeChunk( iter->second ); gSoundCache.erase( iter ); } } void Csdl_audio::play_sound( const char *aSoundName ) { if (!gAudioEnabled) { return; } Mix_Chunk * soundPtr = NULL; sound_cache_t::iterator iter = gSoundCache.find( aSoundName ); if (iter == gSoundCache.end()) { soundPtr = Mix_LoadWAV( aSoundName ); if (!soundPtr) { ThrowEx( string( "Mix_LoadWAV: " ) + Mix_GetError() ); } gSoundCache[aSoundName] = soundPtr; } else { soundPtr = iter->second; } // play sound on next available channel - we don't care if it fails Mix_VolumeChunk( soundPtr, static_cast( fSoundVolume * MIX_MAX_VOLUME ) ); (void) Mix_PlayChannel( -1, soundPtr, 0 ); } void Csdl_audio::shutdown() { if (gAudioInitialized) { (void) Mix_HaltMusic(); if (gCurrMusicPtr) { Mix_FreeMusic( gCurrMusicPtr ); gCurrMusicPtr = NULL; } for( sound_cache_t::iterator iter = gSoundCache.begin(); iter != gSoundCache.end(); ++iter ) { Mix_FreeChunk( iter->second ); } Mix_CloseAudio(); gSoundCache.clear(); gAudioInitialized = false; (void) SDL_QuitSubSystem( SDL_INIT_AUDIO ); } }