/** Introduces a mechanism by which one can load sound effects beyond the basic * enumerated types. This will be used when loading custom sound effects for * individual karts (character voices) so that we can avoid creating an * enumeration for each effect, for each kart. * \param sfx_name * \param sfxFile must be an absolute pathname * \return whether loading this sound effect was successful */ SFXBuffer* SFXManager::addSingleSfx(const std::string &sfx_name, const std::string &sfx_file, bool positional, float rolloff, float max_width, float gain, const bool load) { SFXBuffer* buffer = new SFXBuffer(sfx_file, positional, rolloff, max_width, gain); m_all_sfx_types[sfx_name] = buffer; if (!m_initialized) { // Keep the buffer even if SFX is disabled, in case // SFX is enabled back later return NULL; } if (UserConfigParams::logMisc()) Log::debug("SFXManager", "Loading SFX %s", sfx_file.c_str()); if (load && buffer->load()) return buffer; return NULL; } // addSingleSFX
TrackObjectPresentationSound::TrackObjectPresentationSound(const XMLNode& xml_node, scene::ISceneNode* parent) : TrackObjectPresentation(xml_node) { // TODO: respect 'parent' if any m_sound = NULL; m_xyz = m_init_xyz; std::string sound; xml_node.get("sound", &sound); float rolloff = 0.5; xml_node.get("rolloff", &rolloff ); float volume = 1.0; xml_node.get("volume", &volume ); bool trigger_when_near = false; xml_node.get("play-when-near", &trigger_when_near); float trigger_distance = 1.0f; xml_node.get("distance", &trigger_distance); xml_node.get("conditions", &m_trigger_condition); float max_dist = 390.0f; xml_node.get("max_dist", &max_dist ); // first try track dir, then global dir std::string soundfile = file_manager->getAsset(FileManager::MODEL,sound); if (!file_manager->fileExists(soundfile)) { soundfile = file_manager->getAsset(FileManager::SFX, sound); } SFXBuffer* buffer = new SFXBuffer(soundfile, true /* positional */, rolloff, max_dist, volume); buffer->load(); m_sound = sfx_manager->createSoundSource(buffer, true, true); if (m_sound != NULL) { m_sound->position(m_init_xyz); if (!trigger_when_near && m_trigger_condition.empty()) { m_sound->setLoop(true); m_sound->play(); } } else Log::error("TrackObject", "Sound emitter object could not be created."); if (trigger_when_near) { ItemManager::get()->newItem(m_init_xyz, trigger_distance, this); } }
/** Initialise the data structures for a custom sfx to be played when a * kart is driving on that particular material. * \param sfx The xml node containing the information for this sfx. */ void Material::initCustomSFX(const XMLNode *sfx) { std::string filename; sfx->get("filename", &filename); if (filename.empty()) { Log::warn("material", "Sfx node has no 'filename' " "attribute, sound effect will be ignored."); return; } m_sfx_name = StringUtils::removeExtension(filename); sfx->get("min-speed", &m_sfx_min_speed); // 2.4 style sfx->get("min_speed", &m_sfx_min_speed); // 2.5 style sfx->get("max-speed", &m_sfx_max_speed); // 2.4 style sfx->get("max_speed", &m_sfx_max_speed); // 2.5 style sfx->get("min-pitch", &m_sfx_min_pitch); // 2.4 style sfx->get("min_pitch", &m_sfx_min_pitch); // 2.5 style sfx->get("max-pitch", &m_sfx_max_pitch); // 2.4 style sfx->get("max_pitch", &m_sfx_max_pitch); // 2.5 style if (m_sfx_max_speed == m_sfx_min_speed) { m_sfx_pitch_per_speed = 0.0f; } else { m_sfx_pitch_per_speed = (m_sfx_max_pitch - m_sfx_min_pitch) / (m_sfx_max_speed - m_sfx_min_speed); } if(!SFXManager::get()->soundExist(m_sfx_name)) { // The directory for the track was added to the model search path // so just misuse the getModelFile function const std::string full_path = file_manager->getAsset(FileManager::MODEL, filename); SFXBuffer* buffer = SFXManager::get()->loadSingleSfx(sfx, full_path); if (buffer != NULL) { buffer->setPositional(true); } } } // initCustomSFX
void SFXDevice::_removeBuffer( SFXBuffer* buffer ) { AssertFatal( buffer, "SFXDevice::_removeBuffer() - Got a null buffer!" ); BufferIterator iter = find( mBuffers.begin(), mBuffers.end(), buffer ); if( iter != mBuffers.end() ) { SFXBuffer* buffer = *iter; mStatNumBufferBytes -= buffer->getMemoryUsed(); mStatNumBuffers --; mBuffers.erase( iter ); } }
SFXBuffer* SFXProfile::_createBuffer() { SFXBuffer* buffer = 0; // Try to create through SFXDevie. if( !mFilename.isEmpty() && SFX ) { buffer = SFX->_createBuffer( mFilename, mDescription ); if( buffer ) { #ifdef TORQUE_DEBUG const SFXFormat& format = buffer->getFormat(); Con::printf( "%s SFX: %s (%i channels, %i kHz, %.02f sec, %i kb)", mDescription->mIsStreaming ? "Streaming" : "Loaded", mFilename.c_str(), format.getChannels(), format.getSamplesPerSecond() / 1000, F32( buffer->getDuration() ) / 1000.0f, format.getDataLength( buffer->getDuration() ) / 1024 ); #endif } } // If that failed, load through SFXResource. if( !buffer ) { Resource< SFXResource >& resource = getResource(); if( resource != NULL && SFX ) { #ifdef TORQUE_DEBUG const SFXFormat& format = resource->getFormat(); Con::printf( "%s SFX: %s (%i channels, %i kHz, %.02f sec, %i kb)", mDescription->mIsStreaming ? "Streaming" : "Loading", resource->getFileName().c_str(), format.getChannels(), format.getSamplesPerSecond() / 1000, F32( resource->getDuration() ) / 1000.0f, format.getDataLength( resource->getDuration() ) / 1024 ); #endif ThreadSafeRef< SFXStream > sfxStream = resource->openStream(); buffer = SFX->_createBuffer( sfxStream, mDescription ); } } return buffer; }
/** Destructor, frees all sound effects. */ SFXManager::~SFXManager() { m_thread_id.lock(); pthread_join(*m_thread_id.getData(), NULL); delete m_thread_id.getData(); m_thread_id.unlock(); pthread_cond_destroy(&m_cond_request); // ---- clear m_all_sfx // not strictly necessary, but might avoid copy&paste problems m_all_sfx.lock(); const int sfx_amount = (int) m_all_sfx.getData().size(); for (int n=0; n<sfx_amount; n++) { delete m_all_sfx.getData()[n]; } m_all_sfx.getData().clear(); m_all_sfx.unlock(); m_quick_sounds.lock(); // ---- clear m_quick_sounds { std::map<std::string, SFXBase*>::iterator i = m_quick_sounds.getData().begin(); for (; i != m_quick_sounds.getData().end(); i++) { SFXBase* snd = (*i).second; delete snd; } } m_quick_sounds.getData().clear(); m_quick_sounds.unlock(); // ---- clear m_all_sfx_types { std::map<std::string, SFXBuffer*>::iterator i = m_all_sfx_types.begin(); for (; i != m_all_sfx_types.end(); i++) { SFXBuffer* buffer = (*i).second; buffer->unload(); delete buffer; } m_all_sfx_types.clear(); } m_all_sfx_types.clear(); } // ~SFXManager
/** Called when sound is globally switched on or off. It either pauses or * resumes all sound effects. * \param on If sound is switched on or off. */ void SFXManager::toggleSound(const bool on) { // When activating SFX, load all buffers if (on) { std::map<std::string, SFXBuffer*>::iterator i = m_all_sfx_types.begin(); for (; i != m_all_sfx_types.end(); i++) { SFXBuffer* buffer = (*i).second; buffer->load(); } reallyResumeAllNow(); m_all_sfx.lock(); const int sfx_amount = (int)m_all_sfx.getData().size(); for (int n=0; n<sfx_amount; n++) { m_all_sfx.getData()[n]->onSoundEnabledBack(); } m_all_sfx.unlock(); } else { // First stop all sfx that are not looped const int sfx_amount = (int)m_all_sfx.getData().size(); m_all_sfx.lock(); for (int i=0; i<sfx_amount; i++) { if(!m_all_sfx.getData()[i]->isLooped()) { m_all_sfx.getData()[i]->reallyStopNow(); } } m_all_sfx.unlock(); pauseAll(); } } // toggleSound
// ---------------------------------------------------------------------------- TrackObjectPresentationSound::TrackObjectPresentationSound( const XMLNode& xml_node, scene::ISceneNode* parent, bool disable_for_multiplayer) : TrackObjectPresentation(xml_node) { // TODO: respect 'parent' if any m_enabled = true; m_sound = NULL; m_xyz = m_init_xyz; std::string sound; xml_node.get("sound", &sound); float rolloff = 0.5; xml_node.get("rolloff", &rolloff ); float volume = 1.0; xml_node.get("volume", &volume ); bool trigger_when_near = false; xml_node.get("play-when-near", &trigger_when_near); float trigger_distance = 1.0f; xml_node.get("distance", &trigger_distance); xml_node.get("conditions", &m_trigger_condition); float max_dist = 390.0f; xml_node.get("max_dist", &max_dist ); if (trigger_when_near) { CheckManager::get()->add( new CheckTrigger(m_init_xyz, trigger_distance, std::bind( &TrackObjectPresentationSound::onTriggerItemApproached, this))); } if (disable_for_multiplayer) return; // first try track dir, then global dir std::string soundfile = Track::getCurrentTrack()->getTrackFile(sound); //std::string soundfile = file_manager->getAsset(FileManager::MODEL,sound); if (!file_manager->fileExists(soundfile)) { soundfile = file_manager->getAsset(FileManager::SFX, sound); } SFXBuffer* buffer = new SFXBuffer(soundfile, true /* positional */, rolloff, max_dist, volume); buffer->load(); m_sound = SFXManager::get()->createSoundSource(buffer, true, true); if (m_sound != NULL) { m_sound->setPosition(m_init_xyz); if (!trigger_when_near && m_trigger_condition.empty()) { m_sound->setLoop(true); m_sound->play(); } } else Log::error("TrackObject", "Sound emitter object could not be created."); } // TrackObjectPresentationSound