1 #include "sound_manager.hpp"
8 #include "sound_file.hpp"
9 #include "sound_source.hpp"
10 #include "stream_sound_source.hpp"
13 SoundManager* sound_manager = 0;
15 SoundManager::SoundManager()
16 : device(0), context(0), sound_enabled(false), music_source(0),
20 device = alcOpenDevice(0);
22 print_openal_version();
23 throw std::runtime_error("Couldn't open audio device.");
26 int attributes[] = { 0 };
27 context = alcCreateContext(device, attributes);
28 check_alc_error("Couldn't create audio context: ");
29 alcMakeContextCurrent(context);
30 check_alc_error("Couldn't select audio context: ");
32 check_al_error("Audio error after init: ");
34 } catch(std::exception& e) {
37 log_warning << "Couldn't initialize audio device:" << e.what() << std::endl;
38 print_openal_version();
43 SoundManager::~SoundManager()
47 for(SoundSources::iterator i = sources.begin(); i != sources.end(); ++i) {
51 for(SoundBuffers::iterator i = buffers.begin(); i != buffers.end(); ++i) {
52 ALuint buffer = i->second;
53 alDeleteBuffers(1, &buffer);
57 alcDestroyContext(context);
60 alcCloseDevice(device);
65 SoundManager::load_file_into_buffer(SoundFile* file)
67 ALenum format = get_sample_format(file);
69 alGenBuffers(1, &buffer);
70 check_al_error("Couldn't create audio buffer: ");
71 char* samples = new char[file->size];
73 file->read(samples, file->size);
74 alBufferData(buffer, format, samples,
75 static_cast<ALsizei> (file->size),
76 static_cast<ALsizei> (file->rate));
77 check_al_error("Couldn't fill audio buffer: ");
88 SoundManager::create_sound_source(const std::string& filename)
95 // reuse an existing static sound buffer
96 SoundBuffers::iterator i = buffers.find(filename);
97 if(i != buffers.end()) {
101 std::auto_ptr<SoundFile> file (load_sound_file(filename));
103 if(file->size < 100000) {
104 buffer = load_file_into_buffer(file.get());
105 buffers.insert(std::make_pair(filename, buffer));
107 StreamSoundSource* source = new StreamSoundSource();
108 source->set_sound_file(file.release());
113 SoundSource* source = new SoundSource();
114 alSourcei(source->source, AL_BUFFER, buffer);
119 SoundManager::play(const std::string& filename, const Vector& pos)
122 SoundSource* source = create_sound_source(filename);
125 if(pos == Vector(-1, -1)) {
126 alSourcef(source->source, AL_ROLLOFF_FACTOR, 0);
128 source->set_position(pos);
131 sources.push_back(source);
132 } catch(std::exception& e) {
133 log_warning << "Couldn't play sound " << filename << ": " << e.what() << std::endl;
138 SoundManager::enable_sound(bool enable)
142 sound_enabled = enable;
146 SoundManager::enable_music(bool enable)
150 music_enabled = enable;
152 play_music(current_music);
162 SoundManager::stop_music(float fadetime)
166 && music_source->get_fade_state() != StreamSoundSource::FadingOff)
167 music_source->set_fading(StreamSoundSource::FadingOff, fadetime);
176 SoundManager::play_music(const std::string& filename, bool fade)
178 if(filename == current_music && music_source != NULL)
180 current_music = filename;
191 std::auto_ptr<StreamSoundSource> newmusic (new StreamSoundSource());
192 alSourcef(newmusic->source, AL_ROLLOFF_FACTOR, 0);
193 newmusic->set_sound_file(load_sound_file(filename));
194 newmusic->set_looping(true);
196 newmusic->set_fading(StreamSoundSource::FadingOn, .5f);
200 music_source = newmusic.release();
201 } catch(std::exception& e) {
202 log_warning << "Couldn't play music file '" << filename << "': " << e.what() << std::endl;
207 SoundManager::set_listener_position(const Vector& pos)
209 static Uint32 lastticks = 0;
211 Uint32 current_ticks = SDL_GetTicks();
212 if(current_ticks - lastticks < 300)
214 lastticks = current_ticks;
216 alListener3f(AL_POSITION, pos.x, pos.y, 0);
220 SoundManager::set_listener_velocity(const Vector& vel)
222 alListener3f(AL_VELOCITY, vel.x, vel.y, 0);
226 SoundManager::update()
228 static Uint32 lastticks = 0;
230 Uint32 current_ticks = SDL_GetTicks();
231 if(current_ticks - lastticks < 300)
233 lastticks = current_ticks;
235 // update and check for finished sound sources
236 for(SoundSources::iterator i = sources.begin(); i != sources.end(); ) {
237 SoundSource* source = *i;
241 if(!source->playing()) {
243 i = sources.erase(i);
248 // check streaming sounds
250 music_source->update();
253 alcProcessContext(context);
254 check_alc_error("Error while processing audio context: ");
258 SoundManager::get_sample_format(SoundFile* file)
260 if(file->channels == 2) {
261 if(file->bits_per_sample == 16) {
262 return AL_FORMAT_STEREO16;
263 } else if(file->bits_per_sample == 8) {
264 return AL_FORMAT_STEREO8;
266 throw std::runtime_error("Only 16 and 8 bit samples supported");
268 } else if(file->channels == 1) {
269 if(file->bits_per_sample == 16) {
270 return AL_FORMAT_MONO16;
271 } else if(file->bits_per_sample == 8) {
272 return AL_FORMAT_MONO8;
274 throw std::runtime_error("Only 16 and 8 bit samples supported");
278 throw std::runtime_error("Only 1 and 2 channel samples supported");
282 SoundManager::print_openal_version()
284 log_info << "OpenAL Vendor: " << alGetString(AL_VENDOR) << std::endl;
285 log_info << "OpenAL Version: " << alGetString(AL_VERSION) << std::endl;
286 log_info << "OpenAL Renderer: " << alGetString(AL_RENDERER) << std::endl;
287 log_info << "OpenAl Extensions: " << alGetString(AL_EXTENSIONS) << std::endl;
291 SoundManager::check_alc_error(const char* message)
293 int err = alcGetError(device);
294 if(err != ALC_NO_ERROR) {
295 std::stringstream msg;
296 msg << message << alcGetString(device, err);
297 throw std::runtime_error(msg.str());
302 SoundManager::check_al_error(const char* message)
304 int err = alGetError();
305 if(err != AL_NO_ERROR) {
306 std::stringstream msg;
307 msg << message << alGetString(err);
308 throw std::runtime_error(msg.str());