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