1 #include "sound_manager.h"
8 #include "sound_file.h"
9 #include "sound_source.h"
10 #include "stream_sound_source.h"
12 SoundManager::SoundManager()
13 : device(0), context(0), sound_enabled(false), music_source(0)
16 device = alcOpenDevice(0);
18 print_openal_version();
19 throw std::runtime_error("Couldn't open audio device.");
22 int attributes[] = { 0 };
23 context = alcCreateContext(device, attributes);
24 check_alc_error("Couldn't create audio context: ");
25 alcMakeContextCurrent(context);
26 check_alc_error("Couldn't select audio context: ");
28 check_al_error("Audio error after init: ");
30 } catch(std::exception& e) {
33 std::cerr << "Couldn't initialize audio device:" << e.what() << "\n";
34 print_openal_version();
38 SoundManager::~SoundManager()
42 for(SoundSources::iterator i = sources.begin(); i != sources.end(); ++i) {
46 for(SoundBuffers::iterator i = buffers.begin(); i != buffers.end(); ++i) {
47 ALuint buffer = i->second;
48 alDeleteBuffers(1, &buffer);
52 alcMakeContextCurrent(0);
53 alcDestroyContext(context);
56 alcCloseDevice(device);
61 SoundManager::load_file_into_buffer(const std::string& filename)
64 std::auto_ptr<SoundFile> file (load_sound_file(filename));
66 ALenum format = get_sample_format(file.get());
68 alGenBuffers(1, &buffer);
69 check_al_error("Couldn't create audio buffer: ");
70 char* samples = new char[file->size];
72 file->read(samples, file->size);
73 alBufferData(buffer, format, samples,
74 static_cast<ALsizei> (file->size),
75 static_cast<ALsizei> (file->rate));
76 check_al_error("Couldn't fill audio buffer: ");
87 SoundManager::create_sound_source(const std::string& filename)
94 // reuse an existing static sound buffer
95 SoundBuffers::iterator i = buffers.find(filename);
96 if(i != buffers.end()) {
99 buffer = load_file_into_buffer(filename);
100 buffers.insert(std::make_pair(filename, buffer));
103 SoundSource* source = new SoundSource();
104 alSourcei(source->source, AL_BUFFER, buffer);
109 SoundManager::play(const std::string& soundname, const Vector& pos)
111 std::string filename = "sounds/";
112 filename += soundname;
115 SoundSource* source = create_sound_source(filename);
118 if(pos == Vector(-1, -1)) {
119 alSourcef(source->source, AL_ROLLOFF_FACTOR, 0);
121 source->set_position(pos);
124 sources.push_back(source);
125 } catch(std::exception& e) {
126 std::cout << "Couldn't play sound " << filename << ": " << e.what() << "\n";
131 SoundManager::enable_sound(bool enable)
135 sound_enabled = enable;
139 SoundManager::enable_music(bool enable)
143 music_enabled = enable;
145 play_music(current_music);
155 SoundManager::play_music(const std::string& filename)
157 if(filename == current_music)
159 current_music = filename;
164 StreamSoundSource* newmusic
165 = new StreamSoundSource(load_sound_file(filename));
167 alSourcef(newmusic->source, AL_ROLLOFF_FACTOR, 0);
171 music_source = newmusic;
172 } catch(std::exception& e) {
173 std::cerr << "Couldn't play music file '" << filename << "': "
179 SoundManager::set_listener_position(Vector pos)
181 alListener3f(AL_POSITION, pos.x, pos.y, 0);
185 SoundManager::set_listener_velocity(Vector vel)
187 alListener3f(AL_VELOCITY, vel.x, vel.y, 0);
191 SoundManager::update()
193 // check for finished sound sources
194 for(SoundSources::iterator i = sources.begin(); i != sources.end(); ) {
195 SoundSource* source = *i;
196 if(!source->playing()) {
198 i = sources.erase(i);
203 // check streaming sounds
205 music_source->update();
207 alcProcessContext(context);
208 check_alc_error("Error while processing audio context: ");
212 SoundManager::get_sample_format(SoundFile* file)
214 if(file->channels == 2) {
215 if(file->bits_per_sample == 16) {
216 return AL_FORMAT_STEREO16;
217 } else if(file->bits_per_sample == 8) {
218 return AL_FORMAT_STEREO8;
220 throw std::runtime_error("Only 16 and 8 bit samples supported");
222 } else if(file->channels == 1) {
223 if(file->bits_per_sample == 16) {
224 return AL_FORMAT_MONO16;
225 } else if(file->bits_per_sample == 8) {
226 return AL_FORMAT_MONO8;
228 throw std::runtime_error("Only 16 and 8 bit samples supported");
232 throw std::runtime_error("Only 1 and 2 channel samples supported");
236 SoundManager::print_openal_version()
238 std::cout << "OpenAL Vendor: " << alGetString(AL_VENDOR) << "\n"
239 << "OpenAL Version: " << alGetString(AL_VERSION) << "\n"
240 << "OpenAL Renderer: " << alGetString(AL_RENDERER) << "\n"
241 << "OpenAl Extensions: " << alGetString(AL_RENDERER) << "\n";
245 SoundManager::check_alc_error(const char* message)
247 int err = alcGetError(device);
248 if(err != ALC_NO_ERROR) {
249 std::stringstream msg;
250 msg << message << alcGetString(device, err);
251 throw std::runtime_error(msg.str());
256 SoundManager::check_al_error(const char* message)
258 int err = alGetError();
259 if(err != AL_NO_ERROR) {
260 std::stringstream msg;
261 msg << message << alGetString(err);
262 throw std::runtime_error(msg.str());