1 #include "sound_manager.hpp"
8 #include "sound_file.hpp"
9 #include "sound_source.hpp"
10 #include "stream_sound_source.hpp"
12 SoundManager* sound_manager = 0;
14 SoundManager::SoundManager()
15 : device(0), context(0), sound_enabled(false), music_source(0),
19 device = alcOpenDevice(0);
21 print_openal_version();
22 throw std::runtime_error("Couldn't open audio device.");
25 int attributes[] = { 0 };
26 context = alcCreateContext(device, attributes);
27 check_alc_error("Couldn't create audio context: ");
28 alcMakeContextCurrent(context);
29 check_alc_error("Couldn't select audio context: ");
31 check_al_error("Audio error after init: ");
33 } catch(std::exception& e) {
36 std::cerr << "Couldn't initialize audio device:" << e.what() << "\n";
37 print_openal_version();
41 SoundManager::~SoundManager()
45 for(SoundSources::iterator i = sources.begin(); i != sources.end(); ++i) {
49 for(SoundBuffers::iterator i = buffers.begin(); i != buffers.end(); ++i) {
50 ALuint buffer = i->second;
51 alDeleteBuffers(1, &buffer);
55 alcDestroyContext(context);
58 alcCloseDevice(device);
63 SoundManager::load_file_into_buffer(SoundFile* file)
65 ALenum format = get_sample_format(file);
67 alGenBuffers(1, &buffer);
68 check_al_error("Couldn't create audio buffer: ");
69 char* samples = new char[file->size];
71 file->read(samples, file->size);
72 alBufferData(buffer, format, samples,
73 static_cast<ALsizei> (file->size),
74 static_cast<ALsizei> (file->rate));
75 check_al_error("Couldn't fill audio buffer: ");
86 SoundManager::create_sound_source(const std::string& filename)
93 // reuse an existing static sound buffer
94 SoundBuffers::iterator i = buffers.find(filename);
95 if(i != buffers.end()) {
99 std::auto_ptr<SoundFile> file (load_sound_file(filename));
101 if(file->size < 100000) {
102 buffer = load_file_into_buffer(file.get());
103 buffers.insert(std::make_pair(filename, buffer));
105 StreamSoundSource* source = new StreamSoundSource();
106 source->set_sound_file(file.release());
111 SoundSource* source = new SoundSource();
112 alSourcei(source->source, AL_BUFFER, buffer);
117 SoundManager::play(const std::string& filename, const Vector& pos)
120 SoundSource* source = create_sound_source(filename);
123 if(pos == Vector(-1, -1)) {
124 alSourcef(source->source, AL_ROLLOFF_FACTOR, 0);
126 source->set_position(pos);
129 sources.push_back(source);
130 } catch(std::exception& e) {
131 std::cout << "Couldn't play sound " << filename << ": " << e.what() << "\n";
136 SoundManager::enable_sound(bool enable)
140 sound_enabled = enable;
144 SoundManager::enable_music(bool enable)
148 music_enabled = enable;
150 play_music(current_music);
160 SoundManager::stop_music(float fadetime)
164 && music_source->get_fade_state() != StreamSoundSource::FadingOff)
165 music_source->set_fading(StreamSoundSource::FadingOff, fadetime);
174 SoundManager::play_music(const std::string& filename, bool fade)
176 if(filename == current_music && music_source != NULL)
178 current_music = filename;
189 std::auto_ptr<StreamSoundSource> newmusic (new StreamSoundSource());
190 alSourcef(newmusic->source, AL_ROLLOFF_FACTOR, 0);
191 newmusic->set_sound_file(load_sound_file(filename));
192 newmusic->set_looping(true);
194 newmusic->set_fading(StreamSoundSource::FadingOn, .5f);
198 music_source = newmusic.release();
199 } catch(std::exception& e) {
200 std::cerr << "Couldn't play music file '" << filename << "': "
206 SoundManager::set_listener_position(const Vector& pos)
208 static Uint32 lastticks = 0;
210 Uint32 current_ticks = SDL_GetTicks();
211 if(current_ticks - lastticks < 300)
213 lastticks = current_ticks;
215 alListener3f(AL_POSITION, pos.x, pos.y, 0);
219 SoundManager::set_listener_velocity(const Vector& vel)
221 alListener3f(AL_VELOCITY, vel.x, vel.y, 0);
225 SoundManager::update()
227 static Uint32 lastticks = 0;
229 Uint32 current_ticks = SDL_GetTicks();
230 if(current_ticks - lastticks < 300)
232 lastticks = current_ticks;
234 // update and check for finished sound sources
235 for(SoundSources::iterator i = sources.begin(); i != sources.end(); ) {
236 SoundSource* source = *i;
240 if(!source->playing()) {
242 i = sources.erase(i);
247 // check streaming sounds
249 music_source->update();
252 alcProcessContext(context);
253 check_alc_error("Error while processing audio context: ");
257 SoundManager::get_sample_format(SoundFile* file)
259 if(file->channels == 2) {
260 if(file->bits_per_sample == 16) {
261 return AL_FORMAT_STEREO16;
262 } else if(file->bits_per_sample == 8) {
263 return AL_FORMAT_STEREO8;
265 throw std::runtime_error("Only 16 and 8 bit samples supported");
267 } else if(file->channels == 1) {
268 if(file->bits_per_sample == 16) {
269 return AL_FORMAT_MONO16;
270 } else if(file->bits_per_sample == 8) {
271 return AL_FORMAT_MONO8;
273 throw std::runtime_error("Only 16 and 8 bit samples supported");
277 throw std::runtime_error("Only 1 and 2 channel samples supported");
281 SoundManager::print_openal_version()
283 std::cout << "OpenAL Vendor: " << alGetString(AL_VENDOR) << "\n"
284 << "OpenAL Version: " << alGetString(AL_VERSION) << "\n"
285 << "OpenAL Renderer: " << alGetString(AL_RENDERER) << "\n"
286 << "OpenAl Extensions: " << alGetString(AL_EXTENSIONS) << "\n";
290 SoundManager::check_alc_error(const char* message)
292 int err = alcGetError(device);
293 if(err != ALC_NO_ERROR) {
294 std::stringstream msg;
295 msg << message << alcGetString(device, err);
296 throw std::runtime_error(msg.str());
301 SoundManager::check_al_error(const char* message)
303 int err = alGetError();
304 if(err != AL_NO_ERROR) {
305 std::stringstream msg;
306 msg << message << alGetString(err);
307 throw std::runtime_error(msg.str());