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