- fix debugging functions for killing player
[supertux.git] / src / audio / sound_manager.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2006 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 "sound_manager.hpp"
21
22 #include <stdexcept>
23 #include <iostream>
24 #include <sstream>
25 #include <memory>
26
27 #include "sound_file.hpp"
28 #include "sound_source.hpp"
29 #include "stream_sound_source.hpp"
30 #include "log.hpp"
31 #include "timer.hpp"
32
33 SoundManager* sound_manager = 0;
34
35 SoundManager::SoundManager()
36   : device(0), context(0), sound_enabled(false), music_source(0),
37     music_enabled(true)
38 {
39   try {
40     device = alcOpenDevice(0);
41     if (device == NULL) {
42       throw std::runtime_error("Couldn't open audio device.");
43     }
44
45     int attributes[] = { 0 };
46     context = alcCreateContext(device, attributes);
47     check_alc_error("Couldn't create audio context: ");
48     alcMakeContextCurrent(context);
49     check_alc_error("Couldn't select audio context: ");
50
51     check_al_error("Audio error after init: ");
52     sound_enabled = true;
53   } catch(std::exception& e) {
54     if(context != NULL)
55       alcDestroyContext(context);
56     context = NULL;
57     if(device != NULL)
58       alcCloseDevice(device);
59     device = NULL;
60     log_warning << "Couldn't initialize audio device: " << e.what() << std::endl;
61     print_openal_version();
62   }
63 }
64
65 SoundManager::~SoundManager()
66 {
67   delete music_source;
68
69   for(SoundSources::iterator i = sources.begin(); i != sources.end(); ++i) {
70     delete *i;
71   }
72
73   for(SoundBuffers::iterator i = buffers.begin(); i != buffers.end(); ++i) {
74     ALuint buffer = i->second;
75     alDeleteBuffers(1, &buffer);
76   }
77
78   if(context != NULL) {
79     alcDestroyContext(context);
80   }
81   if(device != NULL) {
82     alcCloseDevice(device);
83   }
84 }
85
86 ALuint
87 SoundManager::load_file_into_buffer(SoundFile* file)
88 {
89   ALenum format = get_sample_format(file);
90   ALuint buffer;
91   alGenBuffers(1, &buffer);
92   check_al_error("Couldn't create audio buffer: ");
93   char* samples = new char[file->size];
94   try {
95     file->read(samples, file->size);
96     alBufferData(buffer, format, samples,
97         static_cast<ALsizei> (file->size),
98         static_cast<ALsizei> (file->rate));
99     check_al_error("Couldn't fill audio buffer: ");
100   } catch(...) {
101     delete[] samples;
102     throw;
103   }
104   delete[] samples;
105
106   return buffer;
107 }
108
109 SoundSource*
110 SoundManager::create_sound_source(const std::string& filename)
111 {
112   if(!sound_enabled)
113     return 0;
114
115   ALuint buffer;
116   
117   // reuse an existing static sound buffer            
118   SoundBuffers::iterator i = buffers.find(filename);
119   if(i != buffers.end()) {
120     buffer = i->second;
121   } else {
122     // Load sound file
123     std::auto_ptr<SoundFile> file (load_sound_file(filename));
124
125     if(file->size < 100000) {
126       buffer = load_file_into_buffer(file.get());
127       buffers.insert(std::make_pair(filename, buffer));
128     } else {
129       StreamSoundSource* source = new StreamSoundSource();
130       source->set_sound_file(file.release());
131       return source;
132     }
133   }
134   
135   SoundSource* source = new SoundSource();
136   alSourcei(source->source, AL_BUFFER, buffer);
137   return source;  
138 }
139
140 void
141 SoundManager::play(const std::string& filename, const Vector& pos)
142 {
143   try {
144     SoundSource* source = create_sound_source(filename);
145     if(source == NULL)
146       return;
147     if(pos == Vector(-1, -1)) {
148       alSourcef(source->source, AL_ROLLOFF_FACTOR, 0);
149     } else {
150       source->set_position(pos);
151     }
152     source->play();
153     sources.push_back(source);
154   } catch(std::exception& e) {
155     log_warning << "Couldn't play sound " << filename << ": " << e.what() << std::endl;
156   }
157 }
158
159 void
160 SoundManager::enable_sound(bool enable)
161 {
162   if(device == NULL)
163     return;
164
165   sound_enabled = enable;
166 }
167
168 void
169 SoundManager::enable_music(bool enable)
170 {
171   if(device == NULL)
172     return;
173
174   music_enabled = enable;
175   if(music_enabled) {
176     play_music(current_music);
177   } else {
178     if(music_source) {
179       delete music_source;
180       music_source = 0;
181     }
182   }
183 }
184
185 void
186 SoundManager::stop_music(float fadetime)
187 {
188   if(fadetime > 0) {
189     if(music_source
190         && music_source->get_fade_state() != StreamSoundSource::FadingOff)
191       music_source->set_fading(StreamSoundSource::FadingOff, fadetime);
192   } else {
193     delete music_source;
194     music_source = NULL;
195   }
196   current_music = "";
197 }
198
199 void
200 SoundManager::play_music(const std::string& filename, bool fade)
201 {
202   if(filename == current_music && music_source != NULL)
203     return;
204   current_music = filename;
205   if(!music_enabled)
206     return;
207
208   if(filename == "") {
209     delete music_source;
210     music_source = NULL;
211     return;
212   }
213
214   try {
215     std::auto_ptr<StreamSoundSource> newmusic (new StreamSoundSource());
216     alSourcef(newmusic->source, AL_ROLLOFF_FACTOR, 0);
217     newmusic->set_sound_file(load_sound_file(filename));
218     newmusic->set_looping(true);
219     if(fade)
220       newmusic->set_fading(StreamSoundSource::FadingOn, .5f);
221     newmusic->play();
222
223     delete music_source;
224     music_source = newmusic.release();
225   } catch(std::exception& e) {
226     log_warning << "Couldn't play music file '" << filename << "': " << e.what() << std::endl;
227   }
228 }
229
230 void
231 SoundManager::set_listener_position(const Vector& pos)
232 {
233   static Uint32 lastticks = 0;
234
235   Uint32 current_ticks = SDL_GetTicks();
236   if(current_ticks - lastticks < 300)
237     return;
238   lastticks = current_ticks;                 
239
240   alListener3f(AL_POSITION, pos.x, pos.y, 0);
241 }
242
243 void
244 SoundManager::set_listener_velocity(const Vector& vel)
245 {
246   alListener3f(AL_VELOCITY, vel.x, vel.y, 0);
247 }
248
249 void
250 SoundManager::update()
251 {
252   static float lasttime = real_time;
253
254   if(real_time - lasttime < 0.3)
255     return;
256   lasttime = real_time;
257
258   // update and check for finished sound sources
259   for(SoundSources::iterator i = sources.begin(); i != sources.end(); ) {
260     SoundSource* source = *i;
261
262     source->update();
263     
264     if(!source->playing()) {
265       delete source;
266       i = sources.erase(i);
267     } else {
268       ++i;
269     }
270   }
271   // check streaming sounds
272   if(music_source) {
273     music_source->update();
274   }
275
276   if (context)
277   {
278     alcProcessContext(context);
279     check_alc_error("Error while processing audio context: ");
280   }
281 }
282
283 ALenum
284 SoundManager::get_sample_format(SoundFile* file)
285 {
286   if(file->channels == 2) {
287     if(file->bits_per_sample == 16) {
288       return AL_FORMAT_STEREO16;
289     } else if(file->bits_per_sample == 8) {
290       return AL_FORMAT_STEREO8;
291     } else {
292       throw std::runtime_error("Only 16 and 8 bit samples supported");
293     }
294   } else if(file->channels == 1) {
295     if(file->bits_per_sample == 16) {
296       return AL_FORMAT_MONO16;
297     } else if(file->bits_per_sample == 8) {
298       return AL_FORMAT_MONO8;
299     } else {
300       throw std::runtime_error("Only 16 and 8 bit samples supported");
301     }
302   }
303   
304   throw std::runtime_error("Only 1 and 2 channel samples supported");
305 }
306
307 void
308 SoundManager::print_openal_version()
309 {
310   log_info << "OpenAL Vendor: " << alGetString(AL_VENDOR) << std::endl;
311   log_info << "OpenAL Version: " << alGetString(AL_VERSION) << std::endl;
312   log_info << "OpenAL Renderer: " << alGetString(AL_RENDERER) << std::endl;
313   log_info << "OpenAl Extensions: " << alGetString(AL_EXTENSIONS) << std::endl;
314 }
315
316 void
317 SoundManager::check_alc_error(const char* message)
318 {
319   int err = alcGetError(device);
320   if(err != ALC_NO_ERROR) {
321     std::stringstream msg;
322     msg << message << alcGetString(device, err);
323     throw std::runtime_error(msg.str());
324   }                
325 }
326
327 void
328 SoundManager::check_al_error(const char* message)
329 {
330   int err = alGetError();
331   if(err != AL_NO_ERROR) {
332     std::stringstream msg;
333     msg << message << alGetString(err);
334     throw std::runtime_error(msg.str());
335   }  
336 }
337