- patch from MatzeB to make music handling easier and more stable
authorIngo Ruhnke <grumbel@gmx.de>
Sat, 24 Apr 2004 14:49:04 +0000 (14:49 +0000)
committerIngo Ruhnke <grumbel@gmx.de>
Sat, 24 Apr 2004 14:49:04 +0000 (14:49 +0000)
SVN-Revision: 682

17 files changed:
src/Makefile.am
src/gameloop.cpp
src/level.cpp
src/level.h
src/music_manager.cpp [new file with mode: 0644]
src/music_manager.h [new file with mode: 0644]
src/musicref.cpp [new file with mode: 0644]
src/musicref.h [new file with mode: 0644]
src/resources.cpp
src/resources.h
src/setup.cpp
src/sound.cpp
src/sound.h
src/title.cpp
src/world.cpp
src/worldmap.cpp
src/worldmap.h

index 4f05fa7..8698570 100644 (file)
@@ -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 #
index 24a5df3..6e4ee5a 100644 (file)
@@ -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
     {
index 19ecc49..0ee5cc7 100644 (file)
@@ -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;
index 6dcebc5..ac503ed 100644 (file)
@@ -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 (file)
index 0000000..6850679
--- /dev/null
@@ -0,0 +1,141 @@
+//  $Id$
+//
+//  SuperTux
+//  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//
+//  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 <assert.h>
+#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<std::string, MusicResource>::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<std::string, MusicResource>::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<std::map<std::string, MusicResource>::iterator, bool> result = 
+    musics.insert(
+        std::make_pair<std::string, MusicResource> (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 (file)
index 0000000..d53a860
--- /dev/null
@@ -0,0 +1,66 @@
+//  $Id$
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+//  Copyright (C) 2004 Duong-Khang NGUYEN <neoneurone@users.sf.net>
+//
+//  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 <SDL_mixer.h>
+#include <string>
+#include <map>
+
+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<std::string, MusicResource> musics;
+  MusicResource* current_music;
+  bool music_enabled;
+};
+
+#endif
+
diff --git a/src/musicref.cpp b/src/musicref.cpp
new file mode 100644 (file)
index 0000000..3ba754b
--- /dev/null
@@ -0,0 +1,65 @@
+//  $Id$
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de>
+//
+//  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 (file)
index 0000000..baa0cd5
--- /dev/null
@@ -0,0 +1,44 @@
+//  $Id$
+//
+//  SuperTux -  A Jump'n Run
+//  Copyright (C) 2004 Matthias Braun <matze@braunis.de>
+//
+//  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
+
index 30707e6..163895e 100644 (file)
@@ -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 */
index 3a7933e..0b7004b 100644 (file)
 #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();
index 3dd909d..558b37f 100644 (file)
@@ -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)
index 53a23ca..fb8359c 100644 (file)
@@ -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 <SDL_mixer.h>
 
 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);
-}
-
index b491f90..b6640a6 100644 (file)
@@ -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*/
index 62469d6..878f122 100644 (file)
@@ -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;
index 655c60a..6969e7a 100644 (file)
@@ -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;
   }
 }
index 95a4c64..a098d2f 100644 (file)
@@ -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 = "<no file>";
   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
index eab9e7e..9f0e085 100644 (file)
@@ -23,7 +23,7 @@
 #include <vector>
 #include <string>
 
-#include <SDL_mixer.h>
+#include "musicref.h"
 
 namespace WorldMapNS {
 
@@ -153,7 +153,7 @@ private:
   typedef std::vector<Level> Levels;
   Levels levels;
 
-  Mix_Music* song;
+  MusicRef song;
 
   Direction input_direction;
   bool enter_level;