+// $Id$
+//
+// SuperTux
+// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#include <config.h>
+
#include "sound_manager.hpp"
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <memory>
+#include <assert.h>
+#include <SDL.h>
#include "sound_file.hpp"
#include "sound_source.hpp"
+#include "openal_sound_source.hpp"
#include "stream_sound_source.hpp"
+#include "dummy_sound_source.hpp"
+#include "log.hpp"
+#include "timer.hpp"
+
+#ifndef DEBUG
+ /** Older openal versions often miss this function and it isn't that vital for
+ * supertux...
+ */
+#ifdef alcGetString
+#undef alcGetString
+#endif
+#define alcGetString(x,y) ""
+#endif
SoundManager* sound_manager = 0;
SoundManager::SoundManager()
: device(0), context(0), sound_enabled(false), music_source(0),
- music_enabled(true)
+ music_enabled(false)
{
try {
device = alcOpenDevice(0);
- if(device == 0) {
- print_openal_version();
+ if (device == NULL) {
throw std::runtime_error("Couldn't open audio device.");
}
check_al_error("Audio error after init: ");
sound_enabled = true;
+ music_enabled = true;
} catch(std::exception& e) {
- device = 0;
- context = 0;
- std::cerr << "Couldn't initialize audio device:" << e.what() << "\n";
+ if(context != NULL)
+ alcDestroyContext(context);
+ context = NULL;
+ if(device != NULL)
+ alcCloseDevice(device);
+ device = NULL;
+ log_warning << "Couldn't initialize audio device: " << e.what() << std::endl;
print_openal_version();
}
}
alDeleteBuffers(1, &buffer);
}
- if(context != 0) {
+ if(context != NULL) {
alcDestroyContext(context);
}
- if(device != 0) {
+ if(device != NULL) {
alcCloseDevice(device);
}
}
return buffer;
}
-SoundSource*
-SoundManager::create_sound_source(const std::string& filename)
+OpenALSoundSource*
+SoundManager::intern_create_sound_source(const std::string& filename)
{
if(!sound_enabled)
- return 0;
+ throw std::runtime_error("sound disabled");
+
+ std::auto_ptr<OpenALSoundSource> source (new OpenALSoundSource());
ALuint buffer;
-
- // reuse an existing static sound buffer
+
+ // reuse an existing static sound buffer
SoundBuffers::iterator i = buffers.find(filename);
if(i != buffers.end()) {
buffer = i->second;
source->set_sound_file(file.release());
return source;
}
+
+ log_debug << "Uncached sound \"" << filename << "\" requested to be played" << std::endl;
}
-
- SoundSource* source = new SoundSource();
+
alSourcei(source->source, AL_BUFFER, buffer);
- return source;
+ return source.release();
+}
+
+SoundSource*
+SoundManager::create_sound_source(const std::string& filename)
+{
+ if(!sound_enabled)
+ return create_dummy_sound_source();
+
+ try {
+ return intern_create_sound_source(filename);
+ } catch(std::exception &e) {
+ log_warning << "Couldn't create audio source: " << e.what() << std::endl;
+ return create_dummy_sound_source();
+ }
+}
+
+void
+SoundManager::preload(const std::string& filename)
+{
+ if(!sound_enabled)
+ return;
+
+ SoundBuffers::iterator i = buffers.find(filename);
+ // already loaded?
+ if(i != buffers.end())
+ return;
+
+ std::auto_ptr<SoundFile> file (load_sound_file(filename));
+ // only keep small files
+ if(file->size >= 100000)
+ return;
+
+ ALuint buffer = load_file_into_buffer(file.get());
+ buffers.insert(std::make_pair(filename, buffer));
}
void
SoundManager::play(const std::string& filename, const Vector& pos)
{
+ if(!sound_enabled)
+ return;
+
try {
- SoundSource* source = create_sound_source(filename);
- if(source == 0)
- return;
+ std::auto_ptr<OpenALSoundSource> source
+ (intern_create_sound_source(filename));
+
if(pos == Vector(-1, -1)) {
- alSourcef(source->source, AL_ROLLOFF_FACTOR, 0);
+ source->set_rollof_factor(0);
} else {
source->set_position(pos);
}
source->play();
- sources.push_back(source);
+ sources.push_back(source.release());
} catch(std::exception& e) {
- std::cout << "Couldn't play sound " << filename << ": " << e.what() << "\n";
+ log_warning << "Couldn't play sound " << filename << ": " << e.what() << std::endl;
+ }
+}
+
+void
+SoundManager::manage_source(SoundSource* source)
+{
+ assert(source != NULL);
+
+ OpenALSoundSource* openal_source = dynamic_cast<OpenALSoundSource*> (source);
+ if(openal_source != NULL) {
+ sources.push_back(openal_source);
+ }
+}
+
+void
+SoundManager::register_for_update( StreamSoundSource* sss ){
+ if( sss != NULL ){
+ update_list.push_back( sss );
+ }
+}
+
+void
+SoundManager::remove_from_update( StreamSoundSource* sss ){
+ if( sss != NULL ){
+ StreamSoundSources::iterator i = update_list.begin();
+ while( i != update_list.end() ){
+ if( *i == sss ){
+ i = update_list.erase(i);
+ } else {
+ i++;
+ }
+ }
}
}
void
SoundManager::enable_sound(bool enable)
{
- if(device == 0)
+ if(device == NULL)
return;
+
sound_enabled = enable;
}
void
SoundManager::enable_music(bool enable)
{
- if(device == 0)
+ if(device == NULL)
return;
+
music_enabled = enable;
if(music_enabled) {
play_music(current_music);
music_source->set_fading(StreamSoundSource::FadingOff, fadetime);
} else {
delete music_source;
- music_source = 0;
+ music_source = NULL;
}
current_music = "";
}
if(filename == "") {
delete music_source;
- music_source = 0;
+ music_source = NULL;
return;
}
std::auto_ptr<StreamSoundSource> newmusic (new StreamSoundSource());
alSourcef(newmusic->source, AL_ROLLOFF_FACTOR, 0);
newmusic->set_sound_file(load_sound_file(filename));
+ newmusic->set_looping(true);
if(fade)
newmusic->set_fading(StreamSoundSource::FadingOn, .5f);
newmusic->play();
delete music_source;
music_source = newmusic.release();
} catch(std::exception& e) {
- std::cerr << "Couldn't play music file '" << filename << "': "
- << e.what() << "\n";
+ log_warning << "Couldn't play music file '" << filename << "': " << e.what() << std::endl;
}
}
void
SoundManager::set_listener_position(const Vector& pos)
{
- static Uint32 lastticks = 0;
+ static Uint32 lastticks = SDL_GetTicks();
Uint32 current_ticks = SDL_GetTicks();
if(current_ticks - lastticks < 300)
return;
- lastticks = current_ticks;
+ lastticks = current_ticks;
alListener3f(AL_POSITION, pos.x, pos.y, 0);
}
void
SoundManager::update()
{
- static Uint32 lastticks = 0;
+ static Uint32 lasttime = SDL_GetTicks();
+ Uint32 now = SDL_GetTicks();
- Uint32 current_ticks = SDL_GetTicks();
- if(current_ticks - lastticks < 300)
+ if(now - lasttime < 300)
return;
- lastticks = current_ticks;
+ lasttime = now;
// update and check for finished sound sources
for(SoundSources::iterator i = sources.begin(); i != sources.end(); ) {
- SoundSource* source = *i;
+ OpenALSoundSource* source = *i;
source->update();
-
+
if(!source->playing()) {
delete source;
i = sources.erase(i);
if(music_source) {
music_source->update();
}
-
- alcProcessContext(context);
- check_alc_error("Error while processing audio context: ");
+
+ if (context)
+ {
+ alcProcessContext(context);
+ check_alc_error("Error while processing audio context: ");
+ }
+
+ //run update() for stream_sound_source
+ StreamSoundSources::iterator s = update_list.begin();
+ while( s != update_list.end() ){
+ (*s)->update();
+ s++;
+ }
}
ALenum
throw std::runtime_error("Only 16 and 8 bit samples supported");
}
}
-
+
throw std::runtime_error("Only 1 and 2 channel samples supported");
}
void
SoundManager::print_openal_version()
{
- std::cout << "OpenAL Vendor: " << alGetString(AL_VENDOR) << "\n"
- << "OpenAL Version: " << alGetString(AL_VERSION) << "\n"
- << "OpenAL Renderer: " << alGetString(AL_RENDERER) << "\n"
- << "OpenAl Extensions: " << alGetString(AL_EXTENSIONS) << "\n";
+ log_info << "OpenAL Vendor: " << alGetString(AL_VENDOR) << std::endl;
+ log_info << "OpenAL Version: " << alGetString(AL_VERSION) << std::endl;
+ log_info << "OpenAL Renderer: " << alGetString(AL_RENDERER) << std::endl;
+ log_info << "OpenAl Extensions: " << alGetString(AL_EXTENSIONS) << std::endl;
}
void
std::stringstream msg;
msg << message << alcGetString(device, err);
throw std::runtime_error(msg.str());
- }
+ }
}
void
std::stringstream msg;
msg << message << alGetString(err);
throw std::runtime_error(msg.str());
- }
+ }
}
-