4 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
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.
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.
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.
21 #include "sound_manager.hpp"
28 #include "sound_file.hpp"
29 #include "sound_source.hpp"
30 #include "stream_sound_source.hpp"
34 SoundManager* sound_manager = 0;
36 SoundManager::SoundManager()
37 : device(0), context(0), sound_enabled(false), music_source(0),
41 device = alcOpenDevice(0);
43 throw std::runtime_error("Couldn't open audio device.");
46 int attributes[] = { 0 };
47 context = alcCreateContext(device, attributes);
48 check_alc_error("Couldn't create audio context: ");
49 alcMakeContextCurrent(context);
50 check_alc_error("Couldn't select audio context: ");
52 check_al_error("Audio error after init: ");
55 } catch(std::exception& e) {
57 alcDestroyContext(context);
60 alcCloseDevice(device);
62 log_warning << "Couldn't initialize audio device: " << e.what() << std::endl;
63 print_openal_version();
67 SoundManager::~SoundManager()
71 for(SoundSources::iterator i = sources.begin(); i != sources.end(); ++i) {
75 for(SoundBuffers::iterator i = buffers.begin(); i != buffers.end(); ++i) {
76 ALuint buffer = i->second;
77 alDeleteBuffers(1, &buffer);
81 alcDestroyContext(context);
84 alcCloseDevice(device);
89 SoundManager::load_file_into_buffer(SoundFile* file)
91 ALenum format = get_sample_format(file);
93 alGenBuffers(1, &buffer);
94 check_al_error("Couldn't create audio buffer: ");
95 char* samples = new char[file->size];
97 file->read(samples, file->size);
98 alBufferData(buffer, format, samples,
99 static_cast<ALsizei> (file->size),
100 static_cast<ALsizei> (file->rate));
101 check_al_error("Couldn't fill audio buffer: ");
112 SoundManager::create_sound_source(const std::string& filename)
119 // reuse an existing static sound buffer
120 SoundBuffers::iterator i = buffers.find(filename);
121 if(i != buffers.end()) {
125 std::auto_ptr<SoundFile> file (load_sound_file(filename));
127 if(file->size < 100000) {
128 buffer = load_file_into_buffer(file.get());
129 buffers.insert(std::make_pair(filename, buffer));
131 StreamSoundSource* source = new StreamSoundSource();
132 source->set_sound_file(file.release());
137 SoundSource* source = new SoundSource();
138 alSourcei(source->source, AL_BUFFER, buffer);
143 SoundManager::preload(const std::string& filename)
148 SoundBuffers::iterator i = buffers.find(filename);
150 if(i != buffers.end())
153 std::auto_ptr<SoundFile> file (load_sound_file(filename));
154 // only keep small files
155 if(file->size >= 100000)
158 ALuint buffer = load_file_into_buffer(file.get());
159 buffers.insert(std::make_pair(filename, buffer));
163 SoundManager::play(const std::string& filename, const Vector& pos)
166 SoundSource* source = create_sound_source(filename);
169 if(pos == Vector(-1, -1)) {
170 alSourcef(source->source, AL_ROLLOFF_FACTOR, 0);
172 source->set_position(pos);
175 sources.push_back(source);
176 } catch(std::exception& e) {
177 log_warning << "Couldn't play sound " << filename << ": " << e.what() << std::endl;
182 SoundManager::play_and_delete(SoundSource* source)
185 log_debug << "ignoring NULL SoundSource" << std::endl;
190 sources.push_back(source);
191 } catch(std::exception& e) {
192 log_warning << "Couldn't play SoundSource: " << e.what() << std::endl;
197 SoundManager::enable_sound(bool enable)
202 sound_enabled = enable;
206 SoundManager::enable_music(bool enable)
211 music_enabled = enable;
213 play_music(current_music);
223 SoundManager::stop_music(float fadetime)
227 && music_source->get_fade_state() != StreamSoundSource::FadingOff)
228 music_source->set_fading(StreamSoundSource::FadingOff, fadetime);
237 SoundManager::play_music(const std::string& filename, bool fade)
239 if(filename == current_music && music_source != NULL)
241 current_music = filename;
252 std::auto_ptr<StreamSoundSource> newmusic (new StreamSoundSource());
253 alSourcef(newmusic->source, AL_ROLLOFF_FACTOR, 0);
254 newmusic->set_sound_file(load_sound_file(filename));
255 newmusic->set_looping(true);
257 newmusic->set_fading(StreamSoundSource::FadingOn, .5f);
261 music_source = newmusic.release();
262 } catch(std::exception& e) {
263 log_warning << "Couldn't play music file '" << filename << "': " << e.what() << std::endl;
268 SoundManager::set_listener_position(const Vector& pos)
270 static Uint32 lastticks = 0;
272 Uint32 current_ticks = SDL_GetTicks();
273 if(current_ticks - lastticks < 300)
275 lastticks = current_ticks;
277 alListener3f(AL_POSITION, pos.x, pos.y, 0);
281 SoundManager::set_listener_velocity(const Vector& vel)
283 alListener3f(AL_VELOCITY, vel.x, vel.y, 0);
287 SoundManager::update()
289 static float lasttime = real_time;
291 if(real_time - lasttime < 0.3)
293 lasttime = real_time;
295 // update and check for finished sound sources
296 for(SoundSources::iterator i = sources.begin(); i != sources.end(); ) {
297 SoundSource* source = *i;
301 if(!source->playing()) {
303 i = sources.erase(i);
308 // check streaming sounds
310 music_source->update();
315 alcProcessContext(context);
316 check_alc_error("Error while processing audio context: ");
321 SoundManager::get_sample_format(SoundFile* file)
323 if(file->channels == 2) {
324 if(file->bits_per_sample == 16) {
325 return AL_FORMAT_STEREO16;
326 } else if(file->bits_per_sample == 8) {
327 return AL_FORMAT_STEREO8;
329 throw std::runtime_error("Only 16 and 8 bit samples supported");
331 } else if(file->channels == 1) {
332 if(file->bits_per_sample == 16) {
333 return AL_FORMAT_MONO16;
334 } else if(file->bits_per_sample == 8) {
335 return AL_FORMAT_MONO8;
337 throw std::runtime_error("Only 16 and 8 bit samples supported");
341 throw std::runtime_error("Only 1 and 2 channel samples supported");
345 SoundManager::print_openal_version()
347 log_info << "OpenAL Vendor: " << alGetString(AL_VENDOR) << std::endl;
348 log_info << "OpenAL Version: " << alGetString(AL_VERSION) << std::endl;
349 log_info << "OpenAL Renderer: " << alGetString(AL_RENDERER) << std::endl;
350 log_info << "OpenAl Extensions: " << alGetString(AL_EXTENSIONS) << std::endl;
354 SoundManager::check_alc_error(const char* message)
356 int err = alcGetError(device);
357 if(err != ALC_NO_ERROR) {
358 std::stringstream msg;
359 msg << message << alcGetString(device, err);
360 throw std::runtime_error(msg.str());
365 SoundManager::check_al_error(const char* message)
367 int err = alGetError();
368 if(err != AL_NO_ERROR) {
369 std::stringstream msg;
370 msg << message << alGetString(err);
371 throw std::runtime_error(msg.str());