#include "PrecompiledHeader.h" #include "SoundSystem.h" #include "World.h" void Systems::SoundSystem::Initialize() { EVENT_SUBSCRIBE_MEMBER(m_EComponentCreated, &SoundSystem::OnComponentCreated); EVENT_SUBSCRIBE_MEMBER(m_EPlaySFX, &SoundSystem::PlaySFX); EVENT_SUBSCRIBE_MEMBER(m_EPlayBGM, &SoundSystem::PlayBGM); EVENT_SUBSCRIBE_MEMBER(m_EStopSound, &SoundSystem::StopSound); m_TransformSystem = m_World->GetSystem(); FMOD_System_Create(&m_System); FMOD_RESULT result = FMOD_System_Init(m_System, 32, FMOD_INIT_3D_RIGHTHANDED, 0); if(result != FMOD_OK) { LOG_ERROR("Did initialized load FMOD correctly"); } else { LOG_INFO("FMOD initialized successfully"); } FMOD_System_Set3DSettings(m_System, 1.f, 1.f, 1.f); //dopplerScale, distancefactor, rolloffscale } void Systems::SoundSystem::RegisterComponents(ComponentFactory* cf) { cf->Register([]() { return new Components::SoundEmitter(); }); cf->Register([]() { return new Components::Listener(); }); } void Systems::SoundSystem::RegisterResourceTypes(std::shared_ptr<::ResourceManager> rm) { rm->RegisterType("Sound3D", [this](std::string resourceName) { return new Sound(resourceName, this->m_System, Components::SoundEmitter::SoundType::SOUND_3D); }); rm->RegisterType("Sound2D", [this](std::string resourceName) { return new Sound(resourceName, this->m_System, Components::SoundEmitter::SoundType::SOUND_2D); }); } void Systems::SoundSystem::Update(double dt) { FMOD_System_Update(m_System); //Delete sounds. Not until it's done playing std::map::iterator it; for(it = m_DeleteChannels.begin(); it != m_DeleteChannels.end();) { FMOD_BOOL *isPlaying = false; FMOD_Channel_IsPlaying(it->second, isPlaying); if(isPlaying) { it++; } else { FMOD_Sound_Release(m_DeleteSounds[it->first]); m_DeleteSounds.erase(it->first); it = m_DeleteChannels.erase(it); } } } void Systems::SoundSystem::UpdateEntity(double dt, EntityID entity, EntityID parent) { auto listener = m_World->GetComponent(entity); if(listener) { int lID = std::find(m_Listeners.begin(), m_Listeners.end(), entity) - m_Listeners.begin(); auto lTransform = m_World->GetComponent(entity); glm::vec3 tPos = m_TransformSystem->AbsolutePosition(entity); FMOD_VECTOR lPos = {tPos.x, tPos.y, tPos.z}; glm::vec3 tVel = (lTransform->Velocity * 1000.f) / (float)dt; FMOD_VECTOR lVel = {tVel.x, tVel.y, tVel.z}; glm::vec3 tUp = glm::normalize(lTransform->Orientation * glm::vec3(0,1,0)); FMOD_VECTOR lUp = {tUp.x, tUp.y, tUp.z}; glm::vec3 tForward = glm::normalize(lTransform->Orientation * glm::vec3(0,0,-1)); FMOD_VECTOR lForward = {tForward.x, tForward.y, tForward.z}; FMOD_System_Set3DListenerAttributes(m_System, lID, (const FMOD_VECTOR*)&lPos, (const FMOD_VECTOR*)&lVel, (const FMOD_VECTOR*)&lForward, (const FMOD_VECTOR*)&lUp); } auto emitter = m_World->GetComponent(entity); if(emitter) { FMOD_CHANNEL* channel = m_Channels[entity]; FMOD_SOUND* sound = m_Sounds[entity]; auto eTransform = m_World->GetComponent(entity); glm::vec3 tPos = m_TransformSystem->AbsolutePosition(entity); FMOD_VECTOR ePos = {tPos.x, tPos.y, tPos.z}; glm::vec3 tVel = (eTransform->Velocity * 1000.f) / float(dt); FMOD_VECTOR eVel = {tVel.x, tVel.y, tVel.z}; FMOD_Channel_Set3DAttributes(channel, &ePos, &eVel); } } bool Systems::SoundSystem::OnComponentCreated(const Events::ComponentCreated &event) { auto listener = std::dynamic_pointer_cast(event.Component); if(listener) { m_Listeners.push_back(listener->Entity); } auto emitter = std::dynamic_pointer_cast(event.Component); if(emitter) { FMOD_CHANNEL* channel; FMOD_SOUND* sound; std::string path = emitter->Path; float volume = emitter->Gain; bool loop = emitter->Loop; float maxDist = emitter->MaxDistance; float minDist = emitter->MinDistance; float pitch = emitter->Pitch; //LoadSound(sound, path, maxDist, minDist); m_Channels.insert(std::make_pair(emitter->Entity, channel)); m_Sounds.insert(std::make_pair(emitter->Entity, sound)); } return true; } bool Systems::SoundSystem::PlaySFX(const Events::PlaySFX &event) { auto emitter = m_World->GetComponent(event.Emitter); if(!emitter) { LOG_ERROR("FMOD: The Entity %i does not have a SoundEmitter-component, but is trying to play a sound", event.Emitter);FMOD_CHANNEL* channel = m_Channels[event.Emitter]; return false; } emitter->type = Components::SoundEmitter::SoundType::SOUND_3D; Sound* sound = ResourceManager->Load("Sound3D", event.Resource); m_Sounds[event.Emitter] = *sound; FMOD_Sound_Set3DMinMaxDistance(*sound, emitter->MinDistance, emitter->MaxDistance); PlaySound(&m_Channels[event.Emitter], m_Sounds[event.Emitter], 1.0, event.Loop); FMOD_System_Update(m_System); FMOD_BOOL isPlaying = false; FMOD_Channel_IsPlaying(m_Channels[event.Emitter], &isPlaying); if(!isPlaying) LOG_ERROR("FMOD: File %s is not playing", event.Resource.c_str()); else LOG_INFO("Now playing sound %s", event.Resource.c_str()); return true; } bool Systems::SoundSystem::PlayBGM(const Events::PlayBGM &event) { auto emitter = m_World->CreateEntity(); auto eTransform = m_World->AddComponent(emitter); auto eComponent = m_World->AddComponent(emitter); m_Channels[emitter] = m_BGMChannel; eComponent->type = Components::SoundEmitter::SoundType::SOUND_3D; Sound* sound = ResourceManager->Load("Sound2D", event.Resource); m_Sounds[emitter] = *sound; FMOD_System_PlaySound(m_System, FMOD_CHANNEL_FREE, *sound, false, &m_Channels[emitter]); return true; } bool Systems::SoundSystem::StopSound(const Events::StopSound &event) { FMOD_Channel_Stop(m_Channels[event.Emitter]); return true; } void Systems::SoundSystem::LoadSound(FMOD_SOUND* &sound, std::string filePath, float maxDist, float minDist) { FMOD_RESULT result = FMOD_System_CreateSound(m_System, filePath.c_str(), FMOD_3D | FMOD_HARDWARE , 0, &sound); if (result != FMOD_OK) { LOG_ERROR("FMOD did not load file: %s", filePath.c_str()); } FMOD_Sound_Set3DMinMaxDistance(sound, minDist, maxDist); } void Systems::SoundSystem::PlaySound(FMOD_CHANNEL** channel, FMOD_SOUND* sound, float volume, bool loop) { FMOD_System_PlaySound(m_System, FMOD_CHANNEL_FREE, sound, false, channel); FMOD_Channel_SetVolume(*channel, volume); if(loop) { FMOD_Channel_SetMode(*channel, FMOD_LOOP_NORMAL); FMOD_Sound_SetLoopCount(sound, -1); } } void Systems::SoundSystem::OnComponentRemoved(EntityID entity, std::string type, Component* component) { auto emitter = dynamic_cast(component); if(emitter) { m_DeleteChannels.insert(std::make_pair(entity, m_Channels[entity])); m_DeleteSounds.insert(std::make_pair(entity, m_Sounds[entity])); m_Channels.erase(entity); m_Sounds.erase(entity); } }