c34f91f7d4933acdf6bdb5e8b904ecf3ac4af8c0
[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 <cmath>
21 #include <cassert>
22
23 #include "audio/sound_manager.h"
24 #include "audio/musicref.h"
25 #include "audio/sound.h"
26 #include "app/globals.h"
27 #include "app/setup.h"
28 #include "special/moving_object.h"
29
30 using namespace SuperTux;
31
32 SoundManager::SoundManager()
33   : current_music(0), music_enabled(true)
34 {
35 }
36
37 SoundManager::~SoundManager()
38 {
39   if(audio_device)
40     Mix_HaltMusic();
41 }
42
43 void
44 SoundManager::play_sound(Mix_Chunk* sound)
45 {
46   if(!audio_device || !use_sound)
47     return;
48
49   Mix_PlayChannel(-1, sound, 0);  
50 }
51
52 void
53 SoundManager::play_sound(Mix_Chunk* sound, const MovingObject* object, const Vector& pos)
54 {
55   // TODO keep track of the object later and move the sound along with the
56   // object.
57   play_sound(sound, object->get_pos(), pos);
58 }
59
60 void
61 SoundManager::play_sound(Mix_Chunk* sound, const Vector& pos, const Vector& pos2)
62 {
63   if(!audio_device || !use_sound)
64     return;
65
66   // TODO make sure this formula is good
67   float distance 
68     = pos2.x- pos.x;
69   int loud = int(255.0/float(screen->w*2) * fabsf(distance));
70   if(loud > 255)
71     return;
72
73   int chan = Mix_PlayChannel(-1, sound, 0);
74   if(chan < 0)
75     return;                                  
76   Mix_SetDistance(chan, loud);
77
78   // very bad way to do this...
79   if(distance > 100)
80     Mix_SetPanning(chan, 230, 24);
81   else if(distance < -100)
82     Mix_SetPanning(chan, 24, 230);
83 }
84
85 MusicRef
86 SoundManager::load_music(const std::string& file)
87 {
88   if(!audio_device)
89     return MusicRef(0);
90
91   if(!exists_music(file))
92     st_abort("Couldn't load musicfile ", file.c_str());
93
94   std::map<std::string, MusicResource>::iterator i = musics.find(file);
95   assert(i != musics.end());
96   return MusicRef(& (i->second));
97 }
98
99 bool
100 SoundManager::exists_music(const std::string& file)
101 {
102   if(!audio_device)
103     return true;
104   
105   // song already loaded?
106   std::map<std::string, MusicResource>::iterator i = musics.find(file);
107   if(i != musics.end()) {
108     return true;                                      
109   }
110   
111   Mix_Music* song = Mix_LoadMUS(file.c_str());
112   if(song == 0)
113     return false;
114
115   // insert into music list
116   std::pair<std::map<std::string, MusicResource>::iterator, bool> result = 
117     musics.insert(
118         std::make_pair<std::string, MusicResource> (file, MusicResource()));
119   MusicResource& resource = result.first->second;
120   resource.manager = this;
121   resource.music = song;
122
123   return true;
124 }
125
126 void
127 SoundManager::free_music(MusicResource* )
128 {
129   // TODO free music, currently we can't do this since SDL_mixer seems to have
130   // some bugs if you load/free alot of mod files.  
131 }
132
133 void
134 SoundManager::play_music(const MusicRef& musicref, int loops)
135 {
136   if(!audio_device)
137     return;
138
139   if(musicref.music == 0 || current_music == musicref.music)
140     return;
141
142   if(current_music)
143     current_music->refcount--;
144   
145   current_music = musicref.music;
146   current_music->refcount++;
147   
148   if(music_enabled)
149     Mix_PlayMusic(current_music->music, loops);
150 }
151
152 void
153 SoundManager::halt_music()
154 {
155   if(!audio_device)
156     return;
157   
158   Mix_HaltMusic();
159   
160   if(current_music) {
161     current_music->refcount--;
162     if(current_music->refcount == 0)
163       free_music(current_music);
164     current_music = 0;
165   }
166 }
167
168 void
169 SoundManager::enable_music(bool enable)
170 {
171   if(!audio_device)
172     return;
173
174   if(enable == music_enabled)
175     return;
176   
177   music_enabled = enable;
178   if(music_enabled == false) {
179     Mix_HaltMusic();
180   } else {
181     Mix_PlayMusic(current_music->music, -1);
182   }
183 }
184
185 SoundManager::MusicResource::~MusicResource()
186 {
187   // don't free music buggy SDL_Mixer crashs for some mod files
188   // Mix_FreeMusic(music);
189 }
190