/* client/soundext.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #include "audio/audio.h" #include "audio/buffers.h" #include "audio/sources.h" #include "auxiliary/functions.h" #include "core/gameinterface.h" #include "core/entity.h" #include "core/entityprojectile.h" #include "client/soundext.h" #include "client/client.h" #include "render/draw.h" #include #include namespace client { // cvars are initialized in client.cc core::Cvar *snd_doppler = 0; core::Cvar *snd_engines = 0; core::Cvar *snd_volume = 0; float master_volume = 0; void render_listener_sound() { if (!(snd_engines && snd_engines->value())) return; math::Vector3f velocity(0, 0 , 0); if (snd_doppler->value() && core::localcontrol()) { velocity.assign(core::localcontrol()->axis().forward() * core::localcontrol()->speed()); } if (master_volume != snd_volume->value()) { master_volume = snd_volume->value(); math::clamp(master_volume, 0, 1); (*snd_volume) = master_volume; } audio::update_listener(render::camera().location(), render::camera().axis(), velocity, master_volume); } void render_entity_sound(core::Entity *entity) { if (!ext_render(entity) || (ext_render(entity)->distance() > core::range::fxdistance)) { if (ext_sound(entity)) delete ext_sound(entity); return; } else { if (!ext_sound(entity)) { new SoundExt(entity); } ext_sound(entity)->frame(0.0f); } } Sound::Sound() { sound_source = 0; sound_buffer = 0; } Sound::Sound(const std::string & name) { sound_source = 0; sound_buffer = 0; if (name.size()) { sound_source = audio::Sources::get(); sound_buffer = audio::Buffers::load(name.c_str()); } } SoundExt::SoundExt(core::Entity *entity) : core::Extension(core::Extension::Sound, entity) { state_thusterloopbuffer = 0; state_impulseloopbuffer = 0; state_impulsestartbuffer = 0; state_impulsestopbuffer = 0; state_jumpstartbuffer = 0; state_jumpstopbuffer = 0; state_explosionbuffer = 0; state_projectilebuffer = 0; state_engineloopbuffer = 0; state_engineloopsource = 0; state_engineeventbuffer = 0; state_engineeventsource = 0; // load engine sound if (entity->type() == core::Entity::Controlable) { core::EntityControlable *entityco = static_cast(entity); unsigned int enginesoundset = 0; //unsigned int impulsesoundset = 0; if (entityco->model()) { enginesoundset = entityco->model()->enginesound(); //impulsesoundset = entityco->model()->impulsesound(); } std::stringstream soundname; soundname << "engines/loop" << std::setfill('0') << std::setw(2) << enginesoundset; state_thusterloopbuffer = audio::Buffers::load(soundname.str()); // load sound set // FIXME alway sound set 0 for now state_impulseloopbuffer = audio::Buffers::load("engines/impulse_loop00"); state_impulsestartbuffer = audio::Buffers::load("engines/impulse_start00"); state_impulsestopbuffer = audio::Buffers::load("engines/impulse_stop00"); state_jumpstartbuffer = audio::Buffers::load("engines/jump_start00"); state_jumpstopbuffer = audio::Buffers::load("engines/jump_stop00"); state_explosionbuffer = audio::Buffers::load("fx/explosion01"); state_engineloopsource = audio::Sources::get(); state_engineeventsource = audio::Sources::get(); } else if (entity->type() == core::Entity::Dynamic) { state_explosionbuffer = audio::Buffers::load("fx/explosion01"); } else if (entity->type() == core::Entity::Projectile) { core::EntityProjectile *projectile = static_cast(entity); // if the sound name is set if (projectile->projectile_soundname().size()) { state_projectilebuffer = audio::Buffers::load("projectiles/" + projectile->projectile_soundname()); // if the sound file was loaded if (state_projectilebuffer) { state_engineeventsource = audio::Sources::get(); // of the OpenAL source is available if (state_engineeventsource) { audio::update_source(state_engineeventsource, entity->location(), math::Vector3f(), 1.0f, 1.0f); audio::play(state_engineeventsource, state_projectilebuffer); } } } } // load model sounds // TODO only sound loops for now if (entity->model() && entity->model()->sounds().size()) { for (model::Model::Sounds::iterator it = entity->model()->sounds().begin(); it != entity->model()->sounds().end(); it++) { model::Sound *tag = (*it); client::Sound *sound = new client::Sound(tag->name()); sound->set_location(tag->location()); state_soundlist.push_back(sound); if (sound->source()) { audio::loop(sound->source(), sound->buffer(), 1.0f, 0.0f); } } } } SoundExt::~SoundExt() { for (Sounds::iterator it = state_soundlist.begin(); it != state_soundlist.end(); it++) { client::Sound *sound = *it; if (sound->source()) { audio::Sources::remove(sound->source()); } } state_soundlist.clear(); if (state_engineloopsource) { audio::Sources::remove(state_engineloopsource); } if (state_engineeventsource) { audio::Sources::remove(state_engineeventsource); } state_thusterloopbuffer = 0; state_impulseloopbuffer = 0; state_impulsestartbuffer = 0; state_impulsestopbuffer = 0; state_jumpstartbuffer = 0; state_jumpstopbuffer = 0; state_explosionbuffer = 0; state_engineloopbuffer = 0; state_engineloopsource = 0; state_engineeventbuffer = 0; state_engineeventsource = 0; } void SoundExt::frame(float elapsed) { float speed = 0; float pitch = 1.0f; float gain = 0.0; float r = (entity()->model() ? entity()->model()->box().max().x() * entity()->radius() / entity()->model()->radius() : entity()->radius()); math::Vector3f velocity; if (entity()->type() == core::Entity::Controlable) { // update engine sounds core::EntityControlable *controlable = static_cast(this->entity()); speed = controlable->speed(); if (snd_doppler->value()) velocity.assign(controlable->axis().forward() * speed); if (controlable->state() == core::Entity::Impulse) { pitch = 1.0f; gain = (snd_engines ? snd_engines->value() : 0.0f); } else { pitch = 0.2f + controlable->thrust() * 0.8f; gain = (snd_engines ? snd_engines->value() : 0.0f); } if (controlable->state() == core::Entity::ImpulseInitiate) { if (state_engineeventbuffer != state_impulsestartbuffer) { audio::update_source(state_engineeventsource, controlable->location() - controlable->axis().forward() * r , controlable->axis().forward() * speed); state_engineeventbuffer = audio::play(state_engineeventsource, state_impulsestartbuffer); } } else if (controlable->state() == core::Entity::JumpInitiate) { if (state_engineeventbuffer != state_jumpstartbuffer) { audio::update_source(state_engineeventsource, controlable->location() - controlable->axis().forward() * r , controlable->axis().forward() * speed); state_engineeventbuffer = audio::play(state_engineeventsource, state_jumpstartbuffer); } } else if (controlable->state() == core::Entity::Jump) { if (state_engineeventbuffer != state_jumpstopbuffer) { audio::update_source(state_engineeventsource, controlable->location() - controlable->axis().forward() * r , controlable->axis().forward() * speed); state_engineeventbuffer = audio::play(state_engineeventsource, state_jumpstopbuffer); } } else if (controlable->state() == core::Entity::Impulse) { state_engineeventbuffer = state_impulseloopbuffer; if (state_engineloopbuffer != state_impulseloopbuffer) { state_engineloopbuffer = audio::loop(state_engineloopsource, state_impulseloopbuffer, pitch, 0); } pitch = 1.0f; } else if (controlable->state() == core::Entity::Destroyed) { if (state_engineloopbuffer) { audio::stop(state_engineloopsource); state_engineloopbuffer = 0; } if (state_engineeventbuffer != state_explosionbuffer) { audio::update_source(state_engineeventsource, controlable->location() - controlable->axis().forward() * r , controlable->axis().forward() * speed); // pack random explosion sound if (math::randomf(100.0f) < 50.0f) { state_explosionbuffer = audio::Buffers::load("fx/explosion01"); } else { state_explosionbuffer = audio::Buffers::load("fx/explosion02"); } state_engineeventbuffer = audio::play(state_engineeventsource, state_explosionbuffer); } pitch = 1.0f; gain = 0.0f; // loop buffer gain } else if (controlable->state() == core::Entity::Docked) { if (state_engineloopbuffer) { audio::stop(state_engineloopsource); state_engineloopbuffer = 0; } if (state_engineeventbuffer) { audio::stop(state_engineeventsource); state_engineeventbuffer = 0; } gain = 0.0f; // loop buffer gain } else { if ((state_engineeventbuffer == state_impulsestartbuffer) || (state_engineeventbuffer == state_impulseloopbuffer)) { audio::update_source(state_engineeventsource, controlable->location() - controlable->axis().forward() * r , controlable->axis().forward() * speed); state_engineeventbuffer = audio::play(state_engineeventsource, state_impulsestopbuffer); } state_engineeventbuffer = 0; if (state_engineloopbuffer != state_thusterloopbuffer) { state_engineloopbuffer = audio::loop(state_engineloopsource, state_thusterloopbuffer, pitch, 0); } } if (state_engineloopbuffer) { audio::update_source(state_engineloopsource, controlable->location() - controlable->axis().forward() * r ,velocity, pitch, gain); } if (state_engineeventbuffer) { audio::update_source(state_engineeventsource, controlable->location() - controlable->axis().forward() * r , velocity); } } else if (entity()->type() == core::Entity::Dynamic) { core::EntityDynamic *dynamic = static_cast(this->entity()); speed = dynamic->speed(); if (snd_doppler->value()) { velocity.assign(dynamic->axis().forward() * speed); } if (dynamic->state() == core::Entity::Destroyed) { if (!state_engineeventsource) { state_engineeventsource = audio::Sources::get(); } if (state_engineeventbuffer != state_explosionbuffer) { audio::update_source(state_engineeventsource, dynamic->location() - dynamic->axis().forward() * r , dynamic->axis().forward() * speed); // pack random explosion sound if (math::randomf(100.0f) < 50.0f) { state_explosionbuffer = audio::Buffers::load("fx/explosion01"); } else { state_explosionbuffer = audio::Buffers::load("fx/explosion02"); } state_engineeventbuffer = audio::play(state_engineeventsource, state_explosionbuffer); } } else { if (state_engineeventbuffer) { audio::stop(state_engineeventsource); state_engineloopbuffer = 0; } if (state_engineeventsource) { audio::Sources::remove(state_engineeventsource); state_engineeventsource = 0; } } if (state_engineeventbuffer) { audio::update_source(state_engineeventsource, dynamic->location() - dynamic->axis().forward() * r , velocity, 1.0f, 1.0f); } } else if (entity()->type() == core::Entity::Projectile) { if (state_engineeventsource && !audio::Sources::is_playing(state_engineeventsource)) { audio::Sources::remove(state_engineeventsource); state_engineeventsource = 0; } } for (Sounds::iterator it = state_soundlist.begin(); it != state_soundlist.end(); it++) { client::Sound *sound = *it; if (sound->source()) { audio::update_source(sound->source(), entity()->location() + entity()->axis() * sound->location(), velocity, 1.0f, 1.0f); } } } } // namespace client