1 #include "sound_manager.hpp"
8 #include "sound_file.hpp"
9 #include "sound_source.hpp"
10 #include "stream_sound_source.hpp"
12 SoundManager::SoundManager()
13 : device(0), context(0), sound_enabled(false), music_source(0),
17 device = alcOpenDevice(0);
19 print_openal_version();
20 throw std::runtime_error("Couldn't open audio device.");
23 int attributes[] = { 0 };
24 context = alcCreateContext(device, attributes);
25 check_alc_error("Couldn't create audio context: ");
26 alcMakeContextCurrent(context);
27 check_alc_error("Couldn't select audio context: ");
29 check_al_error("Audio error after init: ");
31 } catch(std::exception& e) {
34 std::cerr << "Couldn't initialize audio device:" << e.what() << "\n";
35 print_openal_version();
39 SoundManager::~SoundManager()
42 delete next_music_source;
44 for(SoundSources::iterator i = sources.begin(); i != sources.end(); ++i) {
48 for(SoundBuffers::iterator i = buffers.begin(); i != buffers.end(); ++i) {
49 ALuint buffer = i->second;
50 alDeleteBuffers(1, &buffer);
54 alcMakeContextCurrent(0);
55 alcDestroyContext(context);
58 alcCloseDevice(device);
63 SoundManager::load_file_into_buffer(const std::string& filename)
66 std::auto_ptr<SoundFile> file (load_sound_file(filename));
68 ALenum format = get_sample_format(file.get());
70 alGenBuffers(1, &buffer);
71 check_al_error("Couldn't create audio buffer: ");
72 char* samples = new char[file->size];
74 file->read(samples, file->size);
75 alBufferData(buffer, format, samples,
76 static_cast<ALsizei> (file->size),
77 static_cast<ALsizei> (file->rate));
78 check_al_error("Couldn't fill audio buffer: ");
89 SoundManager::create_sound_source(const std::string& filename)
96 // reuse an existing static sound buffer
97 SoundBuffers::iterator i = buffers.find(filename);
98 if(i != buffers.end()) {
101 buffer = load_file_into_buffer(filename);
102 buffers.insert(std::make_pair(filename, buffer));
105 SoundSource* source = new SoundSource();
106 alSourcei(source->source, AL_BUFFER, buffer);
111 SoundManager::play(const std::string& filename, const Vector& pos)
114 SoundSource* source = create_sound_source(filename);
117 if(pos == Vector(-1, -1)) {
118 alSourcef(source->source, AL_ROLLOFF_FACTOR, 0);
120 source->set_position(pos);
123 sources.push_back(source);
124 } catch(std::exception& e) {
125 std::cout << "Couldn't play sound " << filename << ": " << e.what() << "\n";
130 SoundManager::enable_sound(bool enable)
134 sound_enabled = enable;
138 SoundManager::enable_music(bool enable)
142 music_enabled = enable;
144 play_music(current_music);
154 SoundManager::play_music(const std::string& filename, bool fade)
156 if(filename == current_music)
158 current_music = filename;
163 StreamSoundSource* newmusic
164 = new StreamSoundSource(load_sound_file(filename));
166 alSourcef(newmusic->source, AL_ROLLOFF_FACTOR, 0);
170 music_source->setFading(StreamSoundSource::FadingOff, .25f);
171 delete next_music_source;
172 next_music_source = newmusic;
175 music_source = newmusic;
176 music_source->play();
177 next_music_source = 0;
179 } catch(std::exception& e) {
180 std::cerr << "Couldn't play music file '" << filename << "': "
186 SoundManager::set_listener_position(Vector pos)
188 alListener3f(AL_POSITION, pos.x, pos.y, 0);
192 SoundManager::set_listener_velocity(Vector vel)
194 alListener3f(AL_VELOCITY, vel.x, vel.y, 0);
198 SoundManager::update()
200 // check for finished sound sources
201 for(SoundSources::iterator i = sources.begin(); i != sources.end(); ) {
202 SoundSource* source = *i;
203 if(!source->playing()) {
205 i = sources.erase(i);
210 // check streaming sounds
212 music_source->update();
215 if(next_music_source && !music_source || !music_source->playing()) {
217 music_source = next_music_source;
218 //music_source->setFading(StreamSoundSource::FadingOn, 1.0f);
219 music_source->play();
220 next_music_source = 0;
223 alcProcessContext(context);
224 check_alc_error("Error while processing audio context: ");
228 SoundManager::get_sample_format(SoundFile* file)
230 if(file->channels == 2) {
231 if(file->bits_per_sample == 16) {
232 return AL_FORMAT_STEREO16;
233 } else if(file->bits_per_sample == 8) {
234 return AL_FORMAT_STEREO8;
236 throw std::runtime_error("Only 16 and 8 bit samples supported");
238 } else if(file->channels == 1) {
239 if(file->bits_per_sample == 16) {
240 return AL_FORMAT_MONO16;
241 } else if(file->bits_per_sample == 8) {
242 return AL_FORMAT_MONO8;
244 throw std::runtime_error("Only 16 and 8 bit samples supported");
248 throw std::runtime_error("Only 1 and 2 channel samples supported");
252 SoundManager::print_openal_version()
254 std::cout << "OpenAL Vendor: " << alGetString(AL_VENDOR) << "\n"
255 << "OpenAL Version: " << alGetString(AL_VERSION) << "\n"
256 << "OpenAL Renderer: " << alGetString(AL_RENDERER) << "\n"
257 << "OpenAl Extensions: " << alGetString(AL_RENDERER) << "\n";
261 SoundManager::check_alc_error(const char* message)
263 int err = alcGetError(device);
264 if(err != ALC_NO_ERROR) {
265 std::stringstream msg;
266 msg << message << alcGetString(device, err);
267 throw std::runtime_error(msg.str());
272 SoundManager::check_al_error(const char* message)
274 int err = alGetError();
275 if(err != AL_NO_ERROR) {
276 std::stringstream msg;
277 msg << message << alGetString(err);
278 throw std::runtime_error(msg.str());