From: Ingo Ruhnke Date: Sat, 24 Apr 2004 14:49:04 +0000 (+0000) Subject: - patch from MatzeB to make music handling easier and more stable X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=bc0492a3da607f7ee777eff4e78aaa2dd95a50e0;p=supertux.git - patch from MatzeB to make music handling easier and more stable SVN-Revision: 682 --- diff --git a/src/Makefile.am b/src/Makefile.am index 4f05fa78d..86985701e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -69,6 +69,10 @@ gameobjs.cpp \ sprite.h \ sprite.cpp \ sprite_manager.cpp \ -sprite_manager.h +sprite_manager.h \ +music_manager.cpp \ +music_manager.h \ +musicref.cpp \ +musicref.h # EOF # diff --git a/src/gameloop.cpp b/src/gameloop.cpp index 24a5df3b7..6e4ee5a31 100644 --- a/src/gameloop.cpp +++ b/src/gameloop.cpp @@ -53,6 +53,7 @@ #include "tile.h" #include "particlesystem.h" #include "resources.h" +#include "music_manager.h" GameSession* GameSession::current_ = 0; @@ -141,6 +142,8 @@ GameSession::~GameSession() void GameSession::levelintro(void) { + music_manager->halt_music(); + char str[60]; /* Level Intro: */ clearscreen(0, 0, 0); @@ -380,7 +383,7 @@ GameSession::check_end_conditions() { end_sequenze = true; last_x_pos = -1; - halt_music(); + music_manager->halt_music(); } else { diff --git a/src/level.cpp b/src/level.cpp index 19ecc4980..0ee5cc752 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -31,6 +31,8 @@ #include "scene.h" #include "tile.h" #include "lispreader.h" +#include "resources.h" +#include "music_manager.h" using namespace std; @@ -199,18 +201,18 @@ void st_subset::free() } Level::Level() - : img_bkgd(0), level_song(0), level_song_fast(0) + : img_bkgd(0) { } Level::Level(const std::string& subset, int level) - : img_bkgd(0), level_song(0), level_song_fast(0) + : img_bkgd(0) { load(subset, level); } Level::Level(const std::string& filename) - : img_bkgd(0), level_song(0), level_song_fast(0) + : img_bkgd(0) { load(filename); } @@ -218,7 +220,6 @@ Level::Level(const std::string& filename) Level::~Level() { free_gfx(); - free_song(); } void @@ -698,29 +699,13 @@ Level::change(float x, float y, int tm, unsigned int c) } } -void -Level::free_song(void) -{ - if(level_song_fast != level_song) { - free_music(level_song_fast); - level_song_fast = 0; - } - - free_music(level_song); - level_song = 0; -} - void Level::load_song() { - free_song(); - char* song_path; char* song_subtitle; - level_song = ::load_song(datadir + "/music/" + song_title); - if(!level_song) - st_abort("Couldn't load song: " , song_title.c_str()); + level_song = music_manager->load_music(datadir + "/music/" + song_title); song_path = (char *) malloc(sizeof(char) * datadir.length() + strlen(song_title.c_str()) + 8 + 5); @@ -728,21 +713,22 @@ Level::load_song() strcpy(strstr(song_subtitle, "."), "\0"); sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(), song_subtitle, strstr(song_title.c_str(), ".")); - level_song_fast = ::load_song(song_path); - if(!level_song_fast) { + if(!music_manager->exists_music(song_path)) { level_song_fast = level_song; + } else { + level_song_fast = music_manager->load_music(song_path); } free(song_subtitle); free(song_path); } -Mix_Music* +MusicRef Level::get_level_music() { return level_song; } -Mix_Music* +MusicRef Level::get_level_music_fast() { return level_song_fast; diff --git a/src/level.h b/src/level.h index 6dcebc56f..ac503ed16 100644 --- a/src/level.h +++ b/src/level.h @@ -25,6 +25,7 @@ #include "texture.h" #include "badguy.h" #include "lispreader.h" +#include "musicref.h" class Tile; @@ -68,8 +69,8 @@ class Level { public: Surface* img_bkgd; - Mix_Music* level_song; - Mix_Music* level_song_fast; + MusicRef level_song; + MusicRef level_song_fast; std::string name; std::string author; @@ -119,8 +120,8 @@ class Level void load_song(); void free_song(); - Mix_Music* get_level_music(); - Mix_Music* get_level_music_fast(); + MusicRef get_level_music(); + MusicRef get_level_music_fast(); void save(const char* subset, int level); diff --git a/src/music_manager.cpp b/src/music_manager.cpp new file mode 100644 index 000000000..6850679cf --- /dev/null +++ b/src/music_manager.cpp @@ -0,0 +1,141 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2004 Ingo Ruhnke +// +// 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. + +#include +#include "music_manager.h" +#include "musicref.h" +#include "sound.h" +#include "setup.h" + +MusicManager::MusicManager() + : music_enabled(true) +{ } + +MusicManager::~MusicManager() +{ + if(audio_device) + Mix_HaltMusic(); +} + +MusicRef +MusicManager::load_music(const std::string& file) +{ + if(!audio_device) + return MusicRef(0); + + if(!exists_music(file)) + st_abort("Couldn't load musicfile ", file.c_str()); + + std::map::iterator i = musics.find(file); + assert(i != musics.end()); + return MusicRef(& (i->second)); +} + +bool +MusicManager::exists_music(const std::string& file) +{ + if(!audio_device) + return true; + + // song already loaded? + std::map::iterator i = musics.find(file); + if(i != musics.end()) { + return true; + } + + Mix_Music* song = Mix_LoadMUS(file.c_str()); + if(song == 0) + return false; + + // insert into music list + std::pair::iterator, bool> result = + musics.insert( + std::make_pair (file, MusicResource())); + MusicResource& resource = result.first->second; + resource.manager = this; + resource.music = song; + + return true; +} + +void +MusicManager::free_music(MusicResource* ) +{ + // TODO free music, currently we can't do this since SDL_mixer seems to have + // some bugs if you load/free alot of mod files. +} + +void +MusicManager::play_music(const MusicRef& musicref) +{ + if(!audio_device) + return; + + if(musicref.music == 0 || current_music == musicref.music) + return; + + if(current_music) + current_music->refcount--; + + current_music = musicref.music; + current_music->refcount++; + + if(music_enabled) + Mix_PlayMusic(current_music->music, -1); +} + +void +MusicManager::halt_music() +{ + if(!audio_device) + return; + + Mix_HaltMusic(); + + if(current_music) { + current_music->refcount--; + if(current_music->refcount == 0) + free_music(current_music); + current_music = 0; + } +} + +void +MusicManager::enable_music(bool enable) +{ + if(!audio_device) + return; + + if(enable == music_enabled) + return; + + music_enabled = enable; + if(music_enabled == false) { + Mix_HaltMusic(); + } else { + Mix_PlayMusic(current_music->music, -1); + } +} + +MusicManager::MusicResource::~MusicResource() +{ + // buggy SDL_mixer :-/ + // Mix_FreeMusic(music); +} + diff --git a/src/music_manager.h b/src/music_manager.h new file mode 100644 index 000000000..d53a86052 --- /dev/null +++ b/src/music_manager.h @@ -0,0 +1,66 @@ +// $Id$ +// +// SuperTux - A Jump'n Run +// Copyright (C) 2000 Bill Kendrick +// Copyright (C) 2004 Duong-Khang NGUYEN +// +// 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. +#ifndef HEADER_MUSIC_MANAGER_H +#define HEADER_MUSIC_MANAGER_H + +#include +#include +#include + +class MusicRef; + +/** This class manages a list of music resources and is responsible for playing + * the music. + */ +class MusicManager +{ +public: + MusicManager(); + ~MusicManager(); + + MusicRef load_music(const std::string& file); + bool exists_music(const std::string& filename); + + void play_music(const MusicRef& music); + void halt_music(); + + void enable_music(bool enable); + +private: + friend class MusicRef; + class MusicResource + { + public: + ~MusicResource(); + + MusicManager* manager; + Mix_Music* music; + int refcount; + }; + + void free_music(MusicResource* music); + + std::map musics; + MusicResource* current_music; + bool music_enabled; +}; + +#endif + diff --git a/src/musicref.cpp b/src/musicref.cpp new file mode 100644 index 000000000..3ba754bcc --- /dev/null +++ b/src/musicref.cpp @@ -0,0 +1,65 @@ +// $Id$ +// +// SuperTux - A Jump'n Run +// Copyright (C) 2000 Bill Kendrick +// Copyright (C) 2004 Matthias Braun +// +// 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. +#include "musicref.h" + +MusicRef::MusicRef() + : music(0) +{ +} + +MusicRef::MusicRef(MusicManager::MusicResource* newmusic) + : music(newmusic) +{ + if(music) + music->refcount++; +} + +MusicRef::~MusicRef() +{ + if(music) { + music->refcount--; + if(music->refcount == 0) + music->manager->free_music(music); + } +} + +MusicRef::MusicRef(const MusicRef& other) + : music(other.music) +{ + if(music) + music->refcount++; +} + +MusicRef& +MusicRef::operator =(const MusicRef& other) +{ + MusicManager::MusicResource* oldres = music; + music = other.music; + if(music) + music->refcount++; + if(oldres) { + oldres->refcount--; + if(oldres->refcount == 0) + music->manager->free_music(music); + } + + return *this; +} + diff --git a/src/musicref.h b/src/musicref.h new file mode 100644 index 000000000..baa0cd583 --- /dev/null +++ b/src/musicref.h @@ -0,0 +1,44 @@ +// $Id$ +// +// SuperTux - A Jump'n Run +// Copyright (C) 2004 Matthias Braun +// +// 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. +#ifndef HEADER_MUSIC_RESOURCE_H +#define HEADER_MUSIC_RESOURCE_H + +#include "music_manager.h" + +/** This class holds a reference to a music file and maintains a correct + * refcount for that file. + */ +class MusicRef +{ +public: + MusicRef(); + MusicRef(const MusicRef& other); + ~MusicRef(); + + MusicRef& operator= (const MusicRef& other); + +private: + friend class MusicManager; + MusicRef(MusicManager::MusicResource* music); + + MusicManager::MusicResource* music; +}; + +#endif + diff --git a/src/resources.cpp b/src/resources.cpp index 30707e637..163895e28 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -36,7 +36,10 @@ Surface* img_cloud[2][4]; Surface* img_red_glow; +MusicRef herring_song; + SpriteManager* sprite_manager = 0; +MusicManager* music_manager = 0; /* Load graphics/sounds shared between all levels: */ void loadshared() @@ -44,6 +47,7 @@ void loadshared() int i; sprite_manager = new SpriteManager(datadir + "/supertux.strf"); + music_manager = new MusicManager(); /* Tuxes: */ smalltux_star = sprite_manager->load("smalltux-star"); @@ -270,17 +274,13 @@ void loadshared() sounds[i] = load_sound(datadir + soundfilenames[i]); /* Herring song */ - herring_song = load_song(datadir + "/music/SALCON.MOD"); - if(!herring_song) - st_abort("Couldn't load song ", "/music/SALCON.MOD"); + herring_song = music_manager->load_music(datadir + "/music/SALCON.MOD"); } /* Free shared data: */ void unloadshared(void) { - delete sprite_manager; - int i; free_special_gfx(); @@ -330,8 +330,10 @@ void unloadshared(void) for (i = 0; i < NUM_SOUNDS; i++) free_chunk(sounds[i]); - /* free the herring song */ - free_music( herring_song ); + delete sprite_manager; + sprite_manager = 0; + delete music_manager; + music_manager = 0; } /* EOF */ diff --git a/src/resources.h b/src/resources.h index 3a7933e96..0b7004b01 100644 --- a/src/resources.h +++ b/src/resources.h @@ -20,7 +20,10 @@ #ifndef SUPERTUX_RESOURCES_H #define SUPERTUX_RESOURCES_H +#include "musicref.h" + class SpriteManager; +class MusicManager; extern Surface* img_waves[3]; extern Surface* img_water; @@ -32,7 +35,10 @@ extern Surface* img_cloud[2][4]; extern Surface* img_super_bkgd; extern Surface* img_red_glow; +extern MusicRef herring_song; + extern SpriteManager* sprite_manager; +extern MusicManager* music_manager; void loadshared(); void unloadshared(); diff --git a/src/setup.cpp b/src/setup.cpp index 3dd909d8b..558b37ffa 100644 --- a/src/setup.cpp +++ b/src/setup.cpp @@ -49,6 +49,7 @@ #include "configfile.h" #include "scene.h" #include "worldmap.h" +#include "resources.h" #include "player.h" @@ -537,10 +538,7 @@ void process_options_menu(void) use_sound = !use_sound; break; case MNID_MUSIC: - if(use_music != options_menu->item[MNID_MUSIC].toggled) - { - enable_music(options_menu->item[MNID_MUSIC].toggled); - } + music_manager->enable_music(options_menu->item[MNID_MUSIC].toggled); break; case MNID_SHOWFPS: if(show_fps != options_menu->item[MNID_SHOWFPS].toggled) diff --git a/src/sound.cpp b/src/sound.cpp index 53a23ca81..fb8359c96 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -24,9 +24,9 @@ #include "setup.h" /*global variable*/ -bool use_sound; /* handle sound on/off menu and command-line option */ -bool use_music; /* handle music on/off menu and command-line option */ -bool audio_device; /* != 0: available and initialized */ +bool use_sound = true; /* handle sound on/off menu and command-line option */ +bool use_music = true; /* handle music on/off menu and command-line option */ +bool audio_device = true; /* != 0: available and initialized */ int current_music; char * soundfilenames[NUM_SOUNDS] = { @@ -55,8 +55,6 @@ char * soundfilenames[NUM_SOUNDS] = { #include Mix_Chunk * sounds[NUM_SOUNDS]; -Mix_Music * herring_song = 0; -Mix_Music * current_song = 0; /* --- OPEN THE AUDIO DEVICE --- */ @@ -158,47 +156,3 @@ void free_chunk(Mix_Chunk *chunk) } } -void halt_music(void) -{ - if (!use_music || !audio_device) - return; - - Mix_HaltMusic(); - current_song = 0; -} - - -void play_music(Mix_Music *music) -{ - if (!audio_device) - return; - if(music == current_song) - return; - - if (use_music && Mix_PlayMusic(music, -1) < 0) - st_abort("Couldn't play music: ", Mix_GetError()); - - current_song = music; -} - - -void free_music(Mix_Music *music) -{ - if(!audio_device) - return; - - Mix_FreeMusic( music ); -} - -void enable_music(bool enable) -{ - if(!audio_device) - return; - - use_music = enable; - if(!use_music) - Mix_HaltMusic(); - else - Mix_PlayMusic(current_song, -1); -} - diff --git a/src/sound.h b/src/sound.h index b491f905a..b6640a61e 100644 --- a/src/sound.h +++ b/src/sound.h @@ -78,7 +78,6 @@ extern char* soundfilenames[NUM_SOUNDS]; /* variables for stocking the sound and music */ extern Mix_Chunk* sounds[NUM_SOUNDS]; -extern Mix_Music* herring_song; /* functions handling the sound and music */ int open_audio(int frequency, Uint16 format, int channels, int chunksize); @@ -88,10 +87,4 @@ Mix_Chunk * load_sound(const std::string& file); void free_chunk(Mix_Chunk*chunk); void play_sound(Mix_Chunk * snd, enum Sound_Speaker whichSpeaker); -Mix_Music* load_song(const std::string& file); -void free_music(Mix_Music* music); -void halt_music(void); -void enable_music(bool enable); -void play_music(Mix_Music* music); - #endif /*SUPERTUX_SOUND_H*/ diff --git a/src/title.cpp b/src/title.cpp index 62469d6c5..878f12210 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -139,7 +139,6 @@ void check_contrib_subset_menu() { index -= 1; // FIXME: Hack std::cout << "Sarting level: " << index << std::endl; - halt_music(); GameSession session(current_contrib_subset, index, ST_GL_PLAY); session.run(); Menu::set_current(main_menu); @@ -308,7 +307,6 @@ void title(void) generate_contrib_menu(); break; case MNID_LEVELEDITOR: - halt_music(); leveleditor(1); Menu::set_current(main_menu); break; diff --git a/src/world.cpp b/src/world.cpp index 655c60a81..6969e7a0c 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -76,7 +76,6 @@ World::~World() for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i) delete *i; - halt_music(); // just to be sure (because levelmusic is freed now) delete level; } @@ -428,16 +427,16 @@ World::play_music(int musictype) currentmusic = musictype; switch(currentmusic) { case HURRYUP_MUSIC: - ::play_music(get_level()->get_level_music_fast()); + music_manager->play_music(get_level()->get_level_music_fast()); break; case LEVEL_MUSIC: - ::play_music(get_level()->get_level_music()); + music_manager->play_music(get_level()->get_level_music()); break; case HERRING_MUSIC: - ::play_music(herring_song); + music_manager->play_music(herring_song); break; default: - ::halt_music(); + music_manager->halt_music(); break; } } diff --git a/src/worldmap.cpp b/src/worldmap.cpp index 95a4c6475..a098d2f3a 100644 --- a/src/worldmap.cpp +++ b/src/worldmap.cpp @@ -28,6 +28,7 @@ #include "gameloop.h" #include "setup.h" #include "worldmap.h" +#include "resources.h" namespace WorldMapNS { @@ -283,7 +284,6 @@ WorldMap::WorldMap() name = ""; music = "SALCON.MOD"; - song = 0; load_map(); } @@ -555,8 +555,6 @@ WorldMap::update() level->y == tux->get_tile_pos().y) { std::cout << "Enter the current level: " << level->name << std::endl;; - halt_music(); - GameSession session(datadir + "levels/" + level->name, 1, ST_GL_LOAD_LEVEL_FILE); @@ -582,7 +580,7 @@ WorldMap::update() break; } - play_music(song); + music_manager->play_music(song); Menu::set_current(0); if (!savegame_file.empty()) savegame(savegame_file); @@ -725,11 +723,8 @@ WorldMap::display() quit = false; - song = load_song(datadir + "/music/" + music); - if(!song) - st_abort("Couldn't load song ", music.c_str()); - - play_music(song); + song = music_manager->load_music(datadir + "/music/" + music); + music_manager->play_music(song); while(!quit) { Point tux_pos = tux->get_pos(); @@ -758,9 +753,6 @@ WorldMap::display() SDL_Delay(20); } - - halt_music(); - free_music(song); } void diff --git a/src/worldmap.h b/src/worldmap.h index eab9e7e88..9f0e08525 100644 --- a/src/worldmap.h +++ b/src/worldmap.h @@ -23,7 +23,7 @@ #include #include -#include +#include "musicref.h" namespace WorldMapNS { @@ -153,7 +153,7 @@ private: typedef std::vector Levels; Levels levels; - Mix_Music* song; + MusicRef song; Direction input_direction; bool enter_level;