From 8fe800f7afa25e052c387b8a1a7ad6d46f38d916 Mon Sep 17 00:00:00 2001 From: Alexander Baldeck Date: Wed, 29 Dec 2004 12:29:58 +0000 Subject: - ported sound engine to SDL_Mixer - name change from TmwSound to Sound as required by HACKING.txt - slight modification of other files using it due to interface changes - minor speedups in Configuration - makefile.static modfified to link against SDL --- src/configuration.cpp | 16 ++- src/game.cpp | 12 +- src/gui/gui.cpp | 2 +- src/gui/setup.cpp | 5 +- src/gui/setup.h | 3 +- src/main.cpp | 17 ++- src/sound/sound.cpp | 318 ++++++++++++++++++-------------------------------- src/sound/sound.h | 76 +++++------- 8 files changed, 170 insertions(+), 279 deletions(-) (limited to 'src') diff --git a/src/configuration.cpp b/src/configuration.cpp index a7f07aeb..4debdb16 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -100,7 +100,9 @@ bool Configuration::write(std::string filename) { out.write(tmp, strlen(tmp)); strcpy(tmp, ""); } - std::cout << "Configuration::write(" << optionTmp.key << ", \"" << optionTmp.stringValue << "\" / " << optionTmp.numericValue << ")\n"; + #ifdef __DEBUG + std::cout << "Configuration::write(" << optionTmp.key << ", \"" << optionTmp.stringValue << "\" / " << optionTmp.numericValue << ")\n"; + #endif out.write("\n", 1); } @@ -163,11 +165,9 @@ void Configuration::setValue(std::string key, float value) { \param deflt default option if not there or error */ std::string Configuration::getValue(std::string key, std::string deflt) { - for (iter = iniOptions.begin(); iter != iniOptions.end(); iter++) { - if(iter->key == key) - return iter->stringValue; + if(keyExists(key)) { + return iter->stringValue; } - return deflt; } @@ -177,11 +177,9 @@ std::string Configuration::getValue(std::string key, std::string deflt) { \param deflt default option if not there or error */ float Configuration::getValue(std::string key, float deflt) { - for (iter = iniOptions.begin(); iter != iniOptions.end(); iter++) { - if(iter->key == key) - return iter->numericValue; + if(keyExists(key)) { + return iter->numericValue; } - return deflt; } diff --git a/src/game.cpp b/src/game.cpp index 21c5aa3a..8e8c8036 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -40,7 +40,7 @@ char map_path[480]; -extern TmwSound sound; +extern Sound sound; unsigned short dest_x, dest_y, src_x, src_y; unsigned int player_x, player_y; @@ -121,7 +121,7 @@ void do_init() { error("Could not find map file"); } - sound.StartMOD("./data/sound/Mods/somemp.xm", -1); + sound.startBgm("./data/sound/Mods/somemp.xm", -1); // Initialize timers tick_time = 0; @@ -228,9 +228,9 @@ void do_input() { if (key[KEY_F1]) { save_bitmap("./data/graphic/screenshot.bmp", buffer, NULL); } else if (key[KEY_F12]){ - sound.SetAdjVol( 1, 1, 1); + sound.adjustVolume(1); } else if (key[KEY_F11]){ - sound.SetAdjVol(-1,-1,-1); + sound.adjustVolume(-1); } if (key[KEY_F5] && action_time) { if (player_node->action == STAND) @@ -707,7 +707,9 @@ void do_parse() { // Level up case 0x019b: if(RFIFOL(2)==player_node->id) { - sound.StartWAV("./data/sound/wavs/level.wav", 10); + SOUND_SID sound_id = sound.loadItem("./data/sound/wavs/level.wav"); + sound.startItem(sound_id, 64); + sound.clearCache(); } break; // Emotion diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 24069cda..e8217cf8 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -50,7 +50,7 @@ BITMAP *gui_bitmap; bool drag; DATAFILE *gui_gfx; -extern TmwSound sound; +extern Sound sound; /* very internal update stuff */ int (*gui__external_slider_callback)(void *, int); diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp index 233a36a5..d4396408 100644 --- a/src/gui/setup.cpp +++ b/src/gui/setup.cpp @@ -27,7 +27,8 @@ */ #include "setup.h" -#include + +extern Sound sound; /* * Metod returns the number of elements in container @@ -153,8 +154,10 @@ void Setup::action(const std::string& eventId) /* Sound settings */ if(soundCheckBox->isMarked() == true) { config.setValue("sound",1); + sound.init(32, 20); } else { config.setValue("sound",0); + sound.close(); } } else if(eventId == "cancel") { diff --git a/src/gui/setup.h b/src/gui/setup.h index 55343229..f1e10036 100644 --- a/src/gui/setup.h +++ b/src/gui/setup.h @@ -35,6 +35,7 @@ #include #endif +#include "../sound/sound.h" /* * The list model for modes list @@ -71,7 +72,7 @@ class Setup : public Window, public gcn::ActionListener { public: void action(const std::string& eventId); - static Setup * create_setup(); + static Setup * create_setup(); }; #endif diff --git a/src/main.cpp b/src/main.cpp index 07eafbf0..eb830773 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -91,7 +91,7 @@ unsigned char stretch_mode, screen_mode; char *dir; // new sound-engine /- kth5 -TmwSound sound; +Sound sound; // ini file configuration reader Configuration config; @@ -267,6 +267,7 @@ void exit_engine() { config.write(dir); delete dir; gui_exit(); + SDL_Quit(); destroy_bitmap(buffer); allegro_exit(); } @@ -276,9 +277,15 @@ int main() { init_engine(); // initialize sound-engine and start playing intro-theme /-kth5 try { - if (config.getValue("sound", 0) == 1) - sound.Init(32, 20); - sound.SetVol(128, 128, 128); + if (config.getValue("sound", 0) == 1) { + SDL_Init(SDL_INIT_AUDIO); + sound.init(32, 20); + } + sound.setVolume(64); + + /* left here to serve as an example ;) + SOUND_SID id = sound.loadItem("./data/sound/wavs/level.wav"); + sound.startItem(id, 70);*/ } catch (const char *err) { ok("Sound Engine", err); warning(err); @@ -299,7 +306,7 @@ int main() { charSelect(); break; case GAME: - sound.StopBGM(); + sound.stopBgm(); status("GAME"); map_start(); if( state==GAME ) diff --git a/src/sound/sound.cpp b/src/sound/sound.cpp index da65461e..2505f203 100644 --- a/src/sound/sound.cpp +++ b/src/sound/sound.cpp @@ -39,137 +39,86 @@ truments can be a result. 32/20 sounds realistic here. */ -void TmwSound::Init(int voices, int mod_voices) { - isOk = -1; - - if(mod_voices >= voices) - throw("No voices left for SFX! Sound will be disabled!"); - - install_timer(); - reserve_voices (voices, -1); - - #ifdef WIN32 - if (install_sound (DIGI_AUTODETECT, MIDI_AUTODETECT, NULL) < 0) - #else - if (install_sound (DIGI_AUTODETECT, MIDI_NONE, NULL) < 0) - #endif - throw("Could not initialize sound... :-("); - - - if (install_mod (mod_voices) < 0) - throw("Could not install MOD player... :-("); - - mod = NULL; - mid = NULL; - sfx = NULL; +void Sound::init(int voices, int mod_voices) { + if(isOk == 0) { + throw("Sound engine cannot be initialized twice!\n"); + } + bgm = NULL; + int audio_rate = 44100; + Uint16 audio_format = AUDIO_S16; /* 16-bit stereo */ + int audio_channels = 2; + int audio_buffers = 4096; + + if(Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers)) { + #ifndef __DEBUG + throw("Unable to open audio device!\n"); + #else + throw(Mix_GetError()); + #endif + } + + Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels); + pan = 128; - pitch=1000; - - items = 0; - + items = -1; isOk = 0; + + #ifdef __DEBUG + std::cout << "Sound::Init() Initializing Sound\n"; + #endif } /** - \brief set the volume value-range: 0-255 - \param digi for digital playback - \param mid for midi playback - \param mod for... aw, you guess ^^ - + \brief set the volume value-range: 0-128 + \param music volume value + NOTE: - all values may only be between 0-255 where 0 means + all values may only be between 0-128 where 0 means muted. */ -void TmwSound::SetVol(int digi, int mid, int mod) { +void Sound::setVolume(int music) { if(isOk==-1) return; - set_volume(digi, mid); - set_mod_volume(mod); - set_hardware_volume(digi, mid); - - if(isMaxVol(vol_digi + digi)==false) vol_digi += digi; - if(isMaxVol(vol_midi + mid) ==false) vol_midi += mid; - if(isMaxVol(vol_mod + mod) ==false) vol_mod += mod; + + if(isMaxVol(music) == false) { + vol_music = music; + Mix_VolumeMusic(vol_music); + } } /** \brief adjusts current volume - \param adigi for digital playback - \param amid for midi playback - \param amod for... aw, you guess ^^ - - NOTE: - all values may only be between 0-255 where 0 means - muted. -*/ -void TmwSound::SetAdjVol(int adigi, int amid, int amod) { - if(isOk==-1) - return; - set_volume(vol_digi + adigi, vol_midi + amid); - set_mod_volume(vol_mod + amod); - - if(isMaxVol(vol_digi + adigi)==false) vol_digi += adigi; - if(isMaxVol(vol_midi + amid) ==false) vol_midi += amid; - if(isMaxVol(vol_mod + amod) ==false) vol_mod += amod; -} - -/** - \brief start BGM using a midi file - \param in full path of midi file - \param loop how many times should the midi be looped? (-1 = infinite) - - NOTE: - playing midi does not steal away any voices but - does not work w/ most soundcards w/o software - emulation. this means that *nix-users will most - probably be left out. do not use this unless we - find a way to always get it to work. :-) - - at this point of time only standard RMI midi files - can be played. so no m$ extensions like GS and such. + \param amusic volume difference */ -void TmwSound::StartMIDI(char *in, int loop) { +void Sound::adjustVolume(int amusic) { if(isOk==-1) return; - - mid = load_midi(in); - if (!mid) { - isOk=-1; - throw("Could not load MIDI file!"); + + if(isMaxVol(vol_music + amusic) == false) { + vol_music += amusic; + Mix_VolumeMusic(vol_music); } - - play_midi(mid, TRUE); } /** - \brief start BGM using a mod file - \param in full path of mod file + \brief start BGM + \param in full path to file \param loop how many times should the midi be looped? (-1 = infinite) - - NOTE: - playing mod is a pretty good choice. most of the work - is being done by the cpu so it's not dependend on the - sound-card how things sound. if it works, it just - works! ;-) - - JGMOD supports several formats: - MOD - S3M - XM - Unreal - and S3M (in UMX extension) */ -void TmwSound::StartMOD(char * in, int loop) { +void Sound::startBgm(char * in, int loop) { if(isOk==-1) return; - - mod = load_mod(in); - if(!mod) { - isOk=-1; - throw("Error reading MOD file..."); + + if(bgm != NULL) { + stopBgm(); } - play_mod(mod, TRUE); + + bgm = Mix_LoadMUS(in); + Mix_PlayMusic(bgm, loop); + #ifdef __DEBUG + std::cout << "Sound::startBgm() Playing \"" << in << "\" " << loop << " times\n"; + #endif } /** @@ -182,123 +131,79 @@ void TmwSound::StartMOD(char * in, int loop) { passing NULL to the playing functions only means to make playback stop. */ -void TmwSound::StopBGM() { - if(isOk==-1) - return; - - play_midi(NULL,-1); - stop_mod(); - - mod = NULL; - mid = NULL; -} - -/** - \brief play short sample usually for sfx - \param in full path to the sample file - \param pan panning of the sound, values can be 0-255 where 128 is the middle - - NOTE: - later on this will be a subsequent call to another - function that preloads all wavs corresponding to - the current area (e.g. monster screams) to memory. - right now the function loads the file from hdd - everytime you want it to be played. this is kind of - resource intensive even though most OS'ses cache a - already loaded file for some time. - - allegro supports different formats but this is not - stated clear enough - these will work for sure: - WAV - VOC - - i don't know what kind of samples are necessary so we - need to test this thoroughly. -*/ -void TmwSound::StartWAV(char * in, int pan) { - if(isOk==-1) +void Sound::stopBgm() { + if(isOk==-1) { return; - - sfx = load_sample(in); - if (!sfx) - throw("Error reading WAV file..."); - - play_sample(sfx, vol_digi, pan, pitch, FALSE); + } + + #ifdef __DEBUG + std::cout << "Sound::stopBgm()\n"; + #endif + + if(bgm != NULL) { + Mix_HaltMusic(); + Mix_FreeMusic(bgm); + bgm = NULL; + } } /** \brief preloads a sound-item into buffer \param fpath full path to file - \param type type of item (TMWSOUND_MOD, TMWSOUND_MID, TMWSOUND_SFX) + \param type type of item (SOUND_MOD, SOUND_MID, SOUND_SFX) NOTE: - only TMWSOUND_SFX items get preloaded. everything - else will only store the full path to the file. - please make sure that the object is not loaded more - than once since the function will not be able to run - checks for its own! + than once since the function will not run any checks + on its own! the return value should be kept as a reference to the object loaded. if not it is practicaly lost. */ -TMWSOUND_SID TmwSound::LoadItem(char *fpath, char type) { - POOL_ITEM item; - if(type == TMWSOUND_SFX) { - if(!(item.data = (void*)load_sample(fpath))) - throw(sprintf("Unable to load sample: %s\n", fpath)); +SOUND_SID Sound::loadItem(char *fpath) { + #ifdef __DEBUG + std::cout << "Sound::loadItem() precaching \"" << fpath << "\"\n"; + #endif + Mix_Chunk *newItem; + if(newItem = Mix_LoadWAV(fpath)) { + soundpool[++items] = newItem; + #ifdef __DEBUG + std::cout << "Sound::loadItem() success SOUND_SID = " << items << std::endl; + #endif + return items; } - - items++; - item.id = items; - item.type = type; - item.fname = fpath; - - soundpool.push_front(item); - return item.id; + + return 0; } /** - \brief unloads an item from the soundpool - \param id id returned by LoadItem() + \brief plays an item in soundpool + \param id id returned to the item in the soundpool + \param volume volume the sound should be played with (possible range: 0-128) */ -void TmwSound::UnloadItem(TMWSOUND_SID id) { - int cnt = 0; - POOL_ITEM item; - for(sounditem = soundpool.begin(); sounditem != soundpool.end(); sounditem++) { - item = *sounditem; - if(item.id == id) { - destroy_sample((SAMPLE*)item.data); - soundpool.erase(sounditem); - return; - } - cnt++; +void Sound::startItem(SOUND_SID id, int volume) { + if(soundpool[id]) { + #ifdef __DEBUG + std::cout << "Sound::startItem() playing SOUND_SID = " << id << std::endl; + #endif + Mix_VolumeChunk(soundpool[id], volume); + Mix_PlayChannel(-1, soundpool[id], 0); } } /** - \brief plays an item in soundpool - \param id id returned by LoadItem() - \param loop loop n times (-1 is infinite) + \brief wipe all items off the cache */ -void TmwSound::PlayItem(TMWSOUND_SID id, int loop) { - POOL_ITEM item; - for(sounditem = soundpool.begin(); sounditem != soundpool.end(); sounditem++) { - item = *sounditem; - if(item.id = id) { - switch(item.type) { - case TMWSOUND_SFX : - play_sample((SAMPLE*)item.data, vol_digi, pan, pitch, FALSE); - break; - case TMWSOUND_MOD : - StartMOD((char*)item.fname.c_str(),loop); - break; - case TMWSOUND_MID : - StartMIDI((char*)item.fname.c_str(),loop); - break; - } - } +void Sound::clearCache() { + for(SOUND_SID i = 0; i == items; i++) { + Mix_FreeChunk(soundpool[i]); + soundpool[i] = NULL; } + + soundpool.clear(); + #ifdef __DEBUG + std::cout << "Sound::clearCache() wiped all items off the cache\n"; + #endif } /** @@ -306,26 +211,25 @@ void TmwSound::PlayItem(TMWSOUND_SID id, int loop) { NOTE: normally you won't need to call this since this is - done by allegro when shutting itself down. but if + done by SDL when shutting itself down. but if you find a reason to delete the sound-engine from memory (e.g. garbage-collection) feel free to use it. :-P */ -void TmwSound::Close(void) { - mod = NULL; - mid = NULL; - sfx = NULL; - - remove_mod(); - remove_sound(); +void Sound::close(void) { isOk = -1; + clearCache(); + Mix_CloseAudio(); + #ifdef __DEBUG + std::cout << "Sound::close() shutting down Sound\n"; + #endif } /** \brief checks if value equals min-/maximum volume and returns true if that's the case. */ -bool TmwSound::isMaxVol(int vol) { - if( vol > 0 && vol < 255 ) return false; +bool Sound::isMaxVol(int vol) { + if( vol > 0 && vol < 128 ) return false; else return true; } diff --git a/src/sound/sound.h b/src/sound/sound.h index 8df4eb08..a1055b02 100644 --- a/src/sound/sound.h +++ b/src/sound/sound.h @@ -26,82 +26,58 @@ #ifdef WIN32 #pragma warning(disable:4312) #endif -#include -#include -#include +#include +#include +#include #include #include -/** mod file */ -#define TMWSOUND_MOD 1 -/** midi file */ -#define TMWSOUND_MID 2 -/** sample file */ -#define TMWSOUND_SFX 3 +#ifdef __DEBUG + #include +#endif -typedef unsigned short TMWSOUND_SID ; +typedef short SOUND_SID ; /** * Sound engine * * \ingroup CORE */ -class TmwSound { +class Sound { public: - void Init(int, int); - void Close(); - - void StartMIDI(char *, int); - void StartMOD(char *, int); - void StopBGM(); + void init(int, int); + void close(); - void StartWAV(char *, int); - void SetVol(int, int, int); - void SetAdjVol(int, int, int); + void startBgm(char *, int); + void stopBgm(); + + void setVolume(int); + void adjustVolume(int); - TMWSOUND_SID LoadItem(char *, char); - void UnloadItem(TMWSOUND_SID); - void PlayItem(TMWSOUND_SID, int); + SOUND_SID loadItem(char *); + void startItem(SOUND_SID, int); + + void clearCache(); - TmwSound() {isOk=-1;} + Sound() {isOk=-1;} /** if allegro is shut down or object is deleted any BGM is stopped and SFX run out */ - ~TmwSound() {StopBGM(); Close();}; + ~Sound() {stopBgm(); close();}; private: /** initial value is -1 which means error or noninitialzed. you can only play sounds and bgm if this is 0. that should be the case after calling Init() successfully */ int isOk; - MIDI * mid; - JGMOD * mod; - SAMPLE * sfx; - int pan; - int pitch; - - int ret; - int vol_digi; - int vol_midi; - int vol_mod; - - /** structure can hold a sound item's attributes and data (sample-only) */ - typedef struct POOL_ITEM { - /** incremental id of pool item */ - TMWSOUND_SID id; - /** type of item */ - char type; - /** (file-)name of sfx only kept for human reasons ^_^ */ - std::string fname; - /** generic data */ - void * data; - }; + int vol_music; + Mix_Music *bgm; + /** list of preloaded sound data / items */ - std::list soundpool; - std::list::iterator sounditem; - TMWSOUND_SID items; + std::map soundpool; + SOUND_SID items; bool isMaxVol(int); }; -- cgit v1.2.3-70-g09d2