00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "audio/sound_manager.hpp"
00018
00019 #include <SDL.h>
00020 #include <assert.h>
00021 #include <stdexcept>
00022 #include <sstream>
00023 #include <memory>
00024
00025 #include "audio/dummy_sound_source.hpp"
00026 #include "audio/sound_file.hpp"
00027 #include "audio/stream_sound_source.hpp"
00028 #include "util/log.hpp"
00029
00030 SoundManager::SoundManager() :
00031 device(0),
00032 context(0),
00033 sound_enabled(false),
00034 buffers(),
00035 sources(),
00036 update_list(),
00037 music_source(0),
00038 music_enabled(false),
00039 current_music()
00040 {
00041 try {
00042 device = alcOpenDevice(0);
00043 if (device == NULL) {
00044 throw std::runtime_error("Couldn't open audio device.");
00045 }
00046
00047 int attributes[] = { 0 };
00048 context = alcCreateContext(device, attributes);
00049 check_alc_error("Couldn't create audio context: ");
00050 alcMakeContextCurrent(context);
00051 check_alc_error("Couldn't select audio context: ");
00052
00053 check_al_error("Audio error after init: ");
00054 sound_enabled = true;
00055 music_enabled = true;
00056 } catch(std::exception& e) {
00057 if(context != NULL) {
00058 alcDestroyContext(context);
00059 context = NULL;
00060 }
00061 if(device != NULL) {
00062 alcCloseDevice(device);
00063 device = NULL;
00064 }
00065 log_warning << "Couldn't initialize audio device: " << e.what() << std::endl;
00066 print_openal_version();
00067 }
00068 }
00069
00070 SoundManager::~SoundManager()
00071 {
00072 delete music_source;
00073
00074 for(SoundSources::iterator i = sources.begin(); i != sources.end(); ++i) {
00075 delete *i;
00076 }
00077
00078 for(SoundBuffers::iterator i = buffers.begin(); i != buffers.end(); ++i) {
00079 ALuint buffer = i->second;
00080 alDeleteBuffers(1, &buffer);
00081 }
00082
00083 if(context != NULL) {
00084 alcDestroyContext(context);
00085 context = NULL;
00086 }
00087 if(device != NULL) {
00088 alcCloseDevice(device);
00089 device = NULL;
00090 }
00091 }
00092
00093 ALuint
00094 SoundManager::load_file_into_buffer(SoundFile* file)
00095 {
00096 ALenum format = get_sample_format(file);
00097 ALuint buffer;
00098 alGenBuffers(1, &buffer);
00099 check_al_error("Couldn't create audio buffer: ");
00100 char* samples = new char[file->size];
00101 try {
00102 file->read(samples, file->size);
00103 alBufferData(buffer, format, samples,
00104 static_cast<ALsizei> (file->size),
00105 static_cast<ALsizei> (file->rate));
00106 check_al_error("Couldn't fill audio buffer: ");
00107 } catch(...) {
00108 delete[] samples;
00109 throw;
00110 }
00111 delete[] samples;
00112
00113 return buffer;
00114 }
00115
00116 OpenALSoundSource*
00117 SoundManager::intern_create_sound_source(const std::string& filename)
00118 {
00119 assert(sound_enabled);
00120
00121 std::auto_ptr<OpenALSoundSource> source (new OpenALSoundSource());
00122
00123 ALuint buffer;
00124
00125
00126 SoundBuffers::iterator i = buffers.find(filename);
00127 if(i != buffers.end()) {
00128 buffer = i->second;
00129 } else {
00130
00131 std::auto_ptr<SoundFile> file (load_sound_file(filename));
00132
00133 if(file->size < 100000) {
00134 buffer = load_file_into_buffer(file.get());
00135 buffers.insert(std::make_pair(filename, buffer));
00136 } else {
00137 StreamSoundSource* source = new StreamSoundSource();
00138 source->set_sound_file(file.release());
00139 return source;
00140 }
00141
00142 log_debug << "Uncached sound \"" << filename << "\" requested to be played" << std::endl;
00143 }
00144
00145 alSourcei(source->source, AL_BUFFER, buffer);
00146 return source.release();
00147 }
00148
00149 SoundSource*
00150 SoundManager::create_sound_source(const std::string& filename)
00151 {
00152 if(!sound_enabled)
00153 return create_dummy_sound_source();
00154
00155 try {
00156 return intern_create_sound_source(filename);
00157 } catch(std::exception &e) {
00158 log_warning << "Couldn't create audio source: " << e.what() << std::endl;
00159 return create_dummy_sound_source();
00160 }
00161 }
00162
00163 void
00164 SoundManager::preload(const std::string& filename)
00165 {
00166 if(!sound_enabled)
00167 return;
00168
00169 SoundBuffers::iterator i = buffers.find(filename);
00170
00171 if(i != buffers.end())
00172 return;
00173 try {
00174 std::auto_ptr<SoundFile> file (load_sound_file(filename));
00175
00176 if(file->size >= 100000)
00177 return;
00178
00179 ALuint buffer = load_file_into_buffer(file.get());
00180 buffers.insert(std::make_pair(filename, buffer));
00181 } catch(std::exception& e) {
00182 log_warning << "Error while preloading sound file: " << e.what() << std::endl;
00183 }
00184 }
00185
00186 void
00187 SoundManager::play(const std::string& filename, const Vector& pos)
00188 {
00189 if(!sound_enabled)
00190 return;
00191
00192 try {
00193 std::auto_ptr<OpenALSoundSource> source
00194 (intern_create_sound_source(filename));
00195
00196 if(pos.x < 0 || pos.y < 0) {
00197 source->set_relative(true);
00198 } else {
00199 source->set_position(pos);
00200 }
00201 source->play();
00202 sources.push_back(source.release());
00203 } catch(std::exception& e) {
00204 log_warning << "Couldn't play sound " << filename << ": " << e.what() << std::endl;
00205 }
00206 }
00207
00208 void
00209 SoundManager::manage_source(SoundSource* source)
00210 {
00211 assert(source != NULL);
00212
00213 OpenALSoundSource* openal_source = dynamic_cast<OpenALSoundSource*> (source);
00214 if(openal_source != NULL) {
00215 sources.push_back(openal_source);
00216 }
00217 }
00218
00219 void
00220 SoundManager::register_for_update( StreamSoundSource* sss ){
00221 if( sss != NULL ){
00222 update_list.push_back( sss );
00223 }
00224 }
00225
00226 void
00227 SoundManager::remove_from_update( StreamSoundSource* sss ){
00228 if( sss != NULL ){
00229 StreamSoundSources::iterator i = update_list.begin();
00230 while( i != update_list.end() ){
00231 if( *i == sss ){
00232 i = update_list.erase(i);
00233 } else {
00234 i++;
00235 }
00236 }
00237 }
00238 }
00239
00240 void
00241 SoundManager::enable_sound(bool enable)
00242 {
00243 if(device == NULL)
00244 return;
00245
00246 sound_enabled = enable;
00247 }
00248
00249 void
00250 SoundManager::enable_music(bool enable)
00251 {
00252 if(device == NULL)
00253 return;
00254
00255 music_enabled = enable;
00256 if(music_enabled) {
00257 play_music(current_music);
00258 } else {
00259 if(music_source) {
00260 delete music_source;
00261 music_source = NULL;
00262 }
00263 }
00264 }
00265
00266 void
00267 SoundManager::stop_music(float fadetime)
00268 {
00269 if(fadetime > 0) {
00270 if(music_source
00271 && music_source->get_fade_state() != StreamSoundSource::FadingOff)
00272 music_source->set_fading(StreamSoundSource::FadingOff, fadetime);
00273 } else {
00274 delete music_source;
00275 music_source = NULL;
00276 }
00277 current_music = "";
00278 }
00279
00280 void
00281 SoundManager::play_music(const std::string& filename, bool fade)
00282 {
00283 if(filename == current_music && music_source != NULL)
00284 return;
00285 current_music = filename;
00286 if(!music_enabled)
00287 return;
00288
00289 if(filename == "") {
00290 delete music_source;
00291 music_source = NULL;
00292 return;
00293 }
00294
00295 try {
00296 std::auto_ptr<StreamSoundSource> newmusic (new StreamSoundSource());
00297 newmusic->set_sound_file(load_sound_file(filename));
00298 newmusic->set_looping(true);
00299 newmusic->set_relative(true);
00300 if(fade)
00301 newmusic->set_fading(StreamSoundSource::FadingOn, .5f);
00302 newmusic->play();
00303
00304 delete music_source;
00305 music_source = newmusic.release();
00306 } catch(std::exception& e) {
00307 log_warning << "Couldn't play music file '" << filename << "': " << e.what() << std::endl;
00308 }
00309 }
00310
00311 void
00312 SoundManager::set_listener_position(const Vector& pos)
00313 {
00314 static Uint32 lastticks = SDL_GetTicks();
00315
00316 Uint32 current_ticks = SDL_GetTicks();
00317 if(current_ticks - lastticks < 300)
00318 return;
00319 lastticks = current_ticks;
00320
00321 alListener3f(AL_POSITION, pos.x, pos.y, 0);
00322 }
00323
00324 void
00325 SoundManager::set_listener_velocity(const Vector& vel)
00326 {
00327 alListener3f(AL_VELOCITY, vel.x, vel.y, 0);
00328 }
00329
00330 void
00331 SoundManager::update()
00332 {
00333 static Uint32 lasttime = SDL_GetTicks();
00334 Uint32 now = SDL_GetTicks();
00335
00336 if(now - lasttime < 300)
00337 return;
00338 lasttime = now;
00339
00340
00341 for(SoundSources::iterator i = sources.begin(); i != sources.end(); ) {
00342 OpenALSoundSource* source = *i;
00343
00344 source->update();
00345
00346 if(!source->playing()) {
00347 delete source;
00348 i = sources.erase(i);
00349 } else {
00350 ++i;
00351 }
00352 }
00353
00354 if(music_source) {
00355 music_source->update();
00356 }
00357
00358 if (context)
00359 {
00360 alcProcessContext(context);
00361 check_alc_error("Error while processing audio context: ");
00362 }
00363
00364
00365 StreamSoundSources::iterator s = update_list.begin();
00366 while( s != update_list.end() ){
00367 (*s)->update();
00368 s++;
00369 }
00370 }
00371
00372 ALenum
00373 SoundManager::get_sample_format(SoundFile* file)
00374 {
00375 if(file->channels == 2) {
00376 if(file->bits_per_sample == 16) {
00377 return AL_FORMAT_STEREO16;
00378 } else if(file->bits_per_sample == 8) {
00379 return AL_FORMAT_STEREO8;
00380 } else {
00381 throw std::runtime_error("Only 16 and 8 bit samples supported");
00382 }
00383 } else if(file->channels == 1) {
00384 if(file->bits_per_sample == 16) {
00385 return AL_FORMAT_MONO16;
00386 } else if(file->bits_per_sample == 8) {
00387 return AL_FORMAT_MONO8;
00388 } else {
00389 throw std::runtime_error("Only 16 and 8 bit samples supported");
00390 }
00391 }
00392
00393 throw std::runtime_error("Only 1 and 2 channel samples supported");
00394 }
00395
00396 void
00397 SoundManager::print_openal_version()
00398 {
00399 log_info << "OpenAL Vendor: " << alGetString(AL_VENDOR) << std::endl;
00400 log_info << "OpenAL Version: " << alGetString(AL_VERSION) << std::endl;
00401 log_info << "OpenAL Renderer: " << alGetString(AL_RENDERER) << std::endl;
00402 log_info << "OpenAl Extensions: " << alGetString(AL_EXTENSIONS) << std::endl;
00403 }
00404
00405 void
00406 SoundManager::check_alc_error(const char* message)
00407 {
00408 int err = alcGetError(device);
00409 if(err != ALC_NO_ERROR) {
00410 std::stringstream msg;
00411 msg << message << alcGetString(device, err);
00412 throw std::runtime_error(msg.str());
00413 }
00414 }
00415
00416 void
00417 SoundManager::check_al_error(const char* message)
00418 {
00419 int err = alGetError();
00420 if(err != AL_NO_ERROR) {
00421 std::stringstream msg;
00422 msg << message << alGetString(err);
00423 throw std::runtime_error(msg.str());
00424 }
00425 }
00426
00427