- updated TODO
[supertux.git] / src / sound_manager.cpp
1 //  $Id$
2 //
3 //  SuperTux -  A Jump'n Run
4 //  Copyright (C) 2004 Matthias Braun <matze@braunis.de
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 #include "sound_manager.h"
20
21 #include <math.h>
22 #include <assert.h>
23 #include "musicref.h"
24 #include "setup.h"
25 #include "sector.h"
26 #include "camera.h"
27 #include "sound.h"
28 #include "globals.h"
29 #include "moving_object.h"
30
31 SoundManager::SoundManager()
32   : current_music(0), music_enabled(true)
33 {
34 }
35
36 SoundManager::~SoundManager()
37 {
38   if(audio_device)
39     Mix_HaltMusic();
40 }
41
42 void
43 SoundManager::play_sound(Mix_Chunk* sound)
44 {
45   if(!audio_device || !use_sound)
46     return;
47
48   Mix_PlayChannel(-1, sound, 0);  
49 }
50
51 void
52 SoundManager::play_sound(Mix_Chunk* sound, const MovingObject* object)
53 {
54   // TODO keep track of the object later and move the sound along with the
55   // object.
56   play_sound(sound, object->get_pos());
57 }
58
59 void
60 SoundManager::play_sound(Mix_Chunk* sound, const Vector& pos)
61 {
62   if(!audio_device || !use_sound)
63     return;
64
65   // TODO make sure this formula is good
66   float distance 
67     = Sector::current()->player->get_pos().x - pos.x;
68   int loud = int(255.0/float(screen->w*2) * fabsf(distance));
69   if(loud > 255)
70     return;
71
72   int chan = Mix_PlayChannel(-1, sound, 0);
73   if(chan < 0)
74     return;                                  
75   Mix_SetDistance(chan, loud);
76
77   // very bad way to do this...
78   if(distance > 100)
79     Mix_SetPanning(chan, 230, 24);
80   else if(distance < -100)
81     Mix_SetPanning(chan, 24, 230);
82 }
83
84 MusicRef
85 SoundManager::load_music(const std::string& file)
86 {
87   if(!audio_device)
88     return MusicRef(0);
89
90   if(!exists_music(file))
91     st_abort("Couldn't load musicfile ", file.c_str());
92
93   std::map<std::string, MusicResource>::iterator i = musics.find(file);
94   assert(i != musics.end());
95   return MusicRef(& (i->second));
96 }
97
98 bool
99 SoundManager::exists_music(const std::string& file)
100 {
101   if(!audio_device)
102     return true;
103   
104   // song already loaded?
105   std::map<std::string, MusicResource>::iterator i = musics.find(file);
106   if(i != musics.end()) {
107     return true;                                      
108   }
109   
110   Mix_Music* song = Mix_LoadMUS(file.c_str());
111   if(song == 0)
112     return false;
113
114   // insert into music list
115   std::pair<std::map<std::string, MusicResource>::iterator, bool> result = 
116     musics.insert(
117         std::make_pair<std::string, MusicResource> (file, MusicResource()));
118   MusicResource& resource = result.first->second;
119   resource.manager = this;
120   resource.music = song;
121
122   return true;
123 }
124
125 void
126 SoundManager::free_music(MusicResource* )
127 {
128   // TODO free music, currently we can't do this since SDL_mixer seems to have
129   // some bugs if you load/free alot of mod files.  
130 }
131
132 void
133 SoundManager::play_music(const MusicRef& musicref, int loops)
134 {
135   if(!audio_device)
136     return;
137
138   if(musicref.music == 0 || current_music == musicref.music)
139     return;
140
141   if(current_music)
142     current_music->refcount--;
143   
144   current_music = musicref.music;
145   current_music->refcount++;
146   
147   if(music_enabled)
148     Mix_PlayMusic(current_music->music, loops);
149 }
150
151 void
152 SoundManager::halt_music()
153 {
154   if(!audio_device)
155     return;
156   
157   Mix_HaltMusic();
158   
159   if(current_music) {
160     current_music->refcount--;
161     if(current_music->refcount == 0)
162       free_music(current_music);
163     current_music = 0;
164   }
165 }
166
167 void
168 SoundManager::enable_music(bool enable)
169 {
170   if(!audio_device)
171     return;
172
173   if(enable == music_enabled)
174     return;
175   
176   music_enabled = enable;
177   if(music_enabled == false) {
178     Mix_HaltMusic();
179   } else {
180     Mix_PlayMusic(current_music->music, -1);
181   }
182 }
183
184 SoundManager::MusicResource::~MusicResource()
185 {
186   // don't free music buggy SDL_Mixer crashs for some mod files
187   // Mix_FreeMusic(music);
188 }
189