updating Nolok contrib templates
[supertux.git] / lib / audio / 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
20 #include <config.h>
21
22 #include <cmath>
23 #include <cassert>
24
25 #include "audio/sound_manager.h"
26 #include "audio/musicref.h"
27 #include "app/globals.h"
28 #include "app/setup.h"
29 #include "special/moving_object.h"
30
31 using namespace SuperTux;
32
33 SoundManager* SoundManager::instance_ = 0;
34
35 SoundManager::SoundManager()
36   : current_music(0), m_music_enabled(true) , m_sound_enabled(true),
37     audio_device(true)
38 {
39 }
40
41 SoundManager::~SoundManager()
42 {
43   if(audio_device)
44     Mix_HaltMusic();
45
46   sounds.clear();
47 }
48
49 void
50 SoundManager::play_sound(Mix_Chunk* sound)
51 {
52   if(!audio_device || !m_sound_enabled)
53     return;
54
55   Mix_PlayChannel(-1, sound, 0);  
56 }
57
58 void
59 SoundManager::play_sound(Mix_Chunk* sound, const MovingObject* object, const Vector& pos)
60 {
61   // TODO keep track of the object later and move the sound along with the
62   // object.
63   play_sound(sound, object->get_pos(), pos);
64 }
65
66 void
67 SoundManager::play_sound(Mix_Chunk* sound, const Vector& pos, const Vector& pos2)
68 {
69   if(!audio_device || !m_sound_enabled)
70     return;
71
72   // TODO make sure this formula is good
73   float distance 
74     = pos2.x- pos.x;
75   int loud = int(255.0/float(SCREEN_WIDTH*2) * fabsf(distance));
76   if(loud > 255)
77     return;
78
79   int chan = Mix_PlayChannel(-1, sound, 0);
80   if(chan < 0)
81     return;                                  
82   Mix_SetDistance(chan, loud);
83
84   // very bad way to do this...
85   if(distance > 100)
86     Mix_SetPanning(chan, 230, 24);
87   else if(distance < -100)
88     Mix_SetPanning(chan, 24, 230);
89 }
90
91 MusicRef
92 SoundManager::load_music(const std::string& file)
93 {
94   if(!audio_device)
95     return MusicRef(0);
96
97   if(!exists_music(file))
98     Termination::abort("Couldn't load musicfile ", file.c_str());
99
100   std::map<std::string, MusicResource>::iterator i = musics.find(file);
101   assert(i != musics.end());
102   return MusicRef(& (i->second));
103 }
104
105 bool
106 SoundManager::exists_music(const std::string& file)
107 {
108   if(!audio_device)
109     return true;
110   
111   // song already loaded?
112   std::map<std::string, MusicResource>::iterator i = musics.find(file);
113   if(i != musics.end()) {
114     return true;                                      
115   }
116   
117   Mix_Music* song = Mix_LoadMUS(file.c_str());
118   if(song == 0)
119     return false;
120
121   // insert into music list
122   std::pair<std::map<std::string, MusicResource>::iterator, bool> result = 
123     musics.insert(
124         std::make_pair<std::string, MusicResource> (file, MusicResource()));
125   MusicResource& resource = result.first->second;
126   resource.manager = this;
127   resource.music = song;
128
129   return true;
130 }
131
132 void
133 SoundManager::free_music(MusicResource* )
134 {
135   // TODO free music, currently we can't do this since SDL_mixer seems to have
136   // some bugs if you load/free alot of mod files.  
137 }
138
139 void
140 SoundManager::play_music(const MusicRef& musicref, int loops)
141 {
142   if(!audio_device)
143     return;
144
145   if(musicref.music == 0 || current_music == musicref.music)
146     return;
147
148   if(current_music)
149     current_music->refcount--;
150   
151   current_music = musicref.music;
152   current_music->refcount++;
153   
154   if(m_music_enabled)
155     Mix_PlayMusic(current_music->music, loops);
156 }
157
158 void
159 SoundManager::halt_music()
160 {
161   if(!audio_device)
162     return;
163   
164   Mix_HaltMusic();
165   
166   if(current_music) {
167     current_music->refcount--;
168     if(current_music->refcount == 0)
169       free_music(current_music);
170     current_music = 0;
171   }
172 }
173
174 void
175 SoundManager::enable_music(bool enable)
176 {
177   if(!audio_device)
178     return;
179
180   if(enable == m_music_enabled)
181     return;
182   
183   m_music_enabled = enable;
184   if(m_music_enabled == false) {
185     Mix_HaltMusic();
186   } else {
187     if(current_music)
188       Mix_PlayMusic(current_music->music, -1);
189   }
190 }
191
192 void
193 SoundManager::enable_sound(bool enable)
194 {
195   if(!audio_device)
196     return;
197   
198   m_sound_enabled = enable;
199 }
200
201 SoundManager::MusicResource::~MusicResource()
202 {
203   // don't free music buggy SDL_Mixer crashs for some mod files
204   // Mix_FreeMusic(music);
205 }
206
207 /* --- LOAD A SOUND --- */
208
209 Mix_Chunk* SoundManager::load_sound(const std::string& file)
210 {
211   if(!audio_device)
212     return 0;
213   
214   Mix_Chunk* snd = Mix_LoadWAV(file.c_str());
215
216   /*if (snd == 0)
217     Termination::abort("Can't load", file);*/
218
219   return(snd);
220 }
221
222 void SoundManager::free_chunk(Mix_Chunk *chunk)
223 {
224   Mix_FreeChunk( chunk );
225 }
226
227
228 /* --- OPEN THE AUDIO DEVICE --- */
229
230 int SoundManager::open_audio (int frequency, Uint16 format, int channels, int chunksize)
231 {
232   if (Mix_OpenAudio( frequency, format, channels, chunksize ) < 0)
233     return -1;
234
235   // allocate 16 channels for mixing
236   if (Mix_AllocateChannels(8)  != 8)
237     return -2;
238   
239   return 0;
240 }
241
242
243 /* --- CLOSE THE AUDIO DEVICE --- */
244
245 void SoundManager::close_audio( void )
246 {
247   if (audio_device) {
248     Mix_CloseAudio();
249   }
250 }
251
252 Mix_Chunk* SuperTux::IDToSound(int id)
253 {
254   return SoundManager::get()->sounds[id];
255 }
256