| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include "MiniAudioPlaybackComponentController.h"
- #include <AzCore/Asset/AssetSerializer.h>
- #include <AzCore/Component/TransformBus.h>
- #include <AzCore/Serialization/EditContext.h>
- #include "AzCore/Math/MathUtils.h"
- #include "MiniAudioIncludes.h"
- namespace MiniAudio
- {
- MiniAudioPlaybackComponentController::MiniAudioPlaybackComponentController()
- {
- }
- // placement of this destructor is intentional. It forces unique_ptr<ma_sound> to declare its destructor here
- // instead of in the header before inclusion of the giant MiniAudioIncludes.h file
- MiniAudioPlaybackComponentController::~MiniAudioPlaybackComponentController()
- {
- }
- MiniAudioPlaybackComponentController::MiniAudioPlaybackComponentController(const MiniAudioPlaybackComponentConfig& config)
- {
- m_config = config;
- }
- void MiniAudioPlaybackComponentController::Reflect(AZ::ReflectContext* context)
- {
- MiniAudioPlaybackComponentConfig::Reflect(context);
- if (auto serialize = azrtti_cast<AZ::SerializeContext*>(context))
- {
- serialize->Class<MiniAudioPlaybackComponentController>()
- ->Field("Config", &MiniAudioPlaybackComponentController::m_config)
- ->Version(1);
- }
- }
- void MiniAudioPlaybackComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
- {
- provided.push_back(AZ_CRC_CE("MiniAudioPlaybackComponent"));
- }
- void MiniAudioPlaybackComponentController::Activate(const AZ::EntityComponentIdPair& entityComponentIdPair)
- {
- m_entityComponentIdPair = entityComponentIdPair;
- m_config.m_innerAngleInRadians = AZ::DegToRad(m_config.m_innerAngleInDegrees);
- m_config.m_outerAngleInRadians = AZ::DegToRad(m_config.m_outerAngleInDegrees);
- MiniAudioPlaybackRequestBus::Handler::BusConnect(m_entityComponentIdPair.GetEntityId());
- OnConfigurationUpdated();
- }
- void MiniAudioPlaybackComponentController::SetConfiguration(const MiniAudioPlaybackComponentConfig& config)
- {
- m_config = config;
- OnConfigurationUpdated();
- }
- const MiniAudioPlaybackComponentConfig& MiniAudioPlaybackComponentController::GetConfiguration() const
- {
- return m_config;
- }
- void MiniAudioPlaybackComponentController::Deactivate()
- {
- m_entityMovedHandler.Disconnect();
- UnloadSound();
- m_config.m_sound.Release();
- MiniAudioPlaybackRequestBus::Handler::BusDisconnect();
- AZ::Data::AssetBus::MultiHandler::BusDisconnect();
- }
- void MiniAudioPlaybackComponentController::Play()
- {
- if (m_sound)
- {
- ma_sound_start(m_sound.get());
- }
- }
- void MiniAudioPlaybackComponentController::Stop()
- {
- if (m_sound)
- {
- ma_sound_stop(m_sound.get());
- ma_sound_seek_to_pcm_frame(m_sound.get(), 0);
- }
- }
- void MiniAudioPlaybackComponentController::Pause()
- {
- if (m_sound)
- {
- ma_sound_stop(m_sound.get());
- }
- }
- float MiniAudioPlaybackComponentController::GetVolumePercentage() const
- {
- return ma_sound_get_volume(m_sound.get()) * 100.f;
- }
- void MiniAudioPlaybackComponentController::SetVolumePercentage(float volume)
- {
- m_config.m_volume = AZ::GetClamp(volume, 0.f, 100.f);
- if (m_sound)
- {
- ma_sound_set_volume(m_sound.get(), (m_config.m_volume / 100.f));
- }
- }
- float MiniAudioPlaybackComponentController::GetVolumeDecibels() const
- {
- return ma_volume_linear_to_db(ma_sound_get_volume(m_sound.get()));
- }
- void MiniAudioPlaybackComponentController::SetVolumeDecibels(float volumeDecibels)
- {
- m_config.m_volume = ma_volume_db_to_linear(volumeDecibels) * 100.f;
- if (m_sound)
- {
- ma_sound_set_volume(m_sound.get(), (m_config.m_volume / 100.f));
- }
- }
- void MiniAudioPlaybackComponentController::SetLooping(bool loop)
- {
- m_config.m_loop = loop;
- if (m_sound)
- {
- ma_sound_set_looping(m_sound.get(), loop);
- }
- }
- bool MiniAudioPlaybackComponentController::IsLooping() const
- {
- if (m_sound)
- {
- return ma_sound_is_looping(m_sound.get());
- }
- return false;
- }
- AZ::Data::Asset<SoundAsset> MiniAudioPlaybackComponentController::GetSoundAsset() const
- {
- return m_config.m_sound;
- }
- void MiniAudioPlaybackComponentController::SetSoundAsset(AZ::Data::Asset<SoundAsset> soundAsset)
- {
- if (m_config.m_sound.GetId() != soundAsset.GetId())
- {
- m_config.m_sound = soundAsset;
- OnConfigurationUpdated();
- }
- }
- SoundAssetRef MiniAudioPlaybackComponentController::GetSoundAssetRef() const
- {
- SoundAssetRef ref;
- ref.SetAsset(GetSoundAsset());
- return ref;
- }
- void MiniAudioPlaybackComponentController::SetSoundAssetRef(const SoundAssetRef& soundAssetRef)
- {
- SetSoundAsset(soundAssetRef.GetAsset());
- }
- float MiniAudioPlaybackComponentController::GetInnerAngleInRadians() const
- {
- return m_config.m_innerAngleInRadians;
- }
- void MiniAudioPlaybackComponentController::SetInnerAngleInRadians(float innerAngleInRadians)
- {
- m_config.m_innerAngleInRadians = innerAngleInRadians;
- m_config.m_innerAngleInDegrees = AZ::RadToDeg(m_config.m_innerAngleInRadians);
- OnConfigurationUpdated();
- }
- float MiniAudioPlaybackComponentController::GetInnerAngleInDegrees() const
- {
- return m_config.m_innerAngleInDegrees;
- }
- void MiniAudioPlaybackComponentController::SetInnerAngleInDegrees(float innerAngleInDegrees)
- {
- m_config.m_innerAngleInDegrees = innerAngleInDegrees;
- m_config.m_innerAngleInRadians = AZ::DegToRad(m_config.m_innerAngleInDegrees);
- OnConfigurationUpdated();
- }
- float MiniAudioPlaybackComponentController::GetOuterAngleInRadians() const
- {
- return m_config.m_outerAngleInRadians;
- }
- void MiniAudioPlaybackComponentController::SetOuterAngleInRadians(float outerAngleInRadians)
- {
- m_config.m_outerAngleInRadians = outerAngleInRadians;
- m_config.m_outerAngleInDegrees = AZ::RadToDeg(m_config.m_outerAngleInRadians);
- OnConfigurationUpdated();
- }
- float MiniAudioPlaybackComponentController::GetOuterAngleInDegrees() const
- {
- return m_config.m_outerAngleInDegrees;
- }
- void MiniAudioPlaybackComponentController::SetOuterAngleInDegrees(float outerAngleInDegrees)
- {
- m_config.m_outerAngleInDegrees = outerAngleInDegrees;
- m_config.m_outerAngleInRadians = AZ::DegToRad(m_config.m_outerAngleInDegrees);
- OnConfigurationUpdated();
- }
- float MiniAudioPlaybackComponentController::GetOuterVolumePercentage() const
- {
- return m_config.m_outerVolume;
- }
- void MiniAudioPlaybackComponentController::SetOuterVolumePercentage(float outerVolume)
- {
- m_config.m_outerVolume = AZ::GetClamp(outerVolume, 0.f, 100.f);
- OnConfigurationUpdated();
- }
- float MiniAudioPlaybackComponentController::GetOuterVolumeDecibels() const
- {
- return ma_volume_linear_to_db(m_config.m_outerVolume / 100.f);
- }
- void MiniAudioPlaybackComponentController::SetOuterVolumeDecibels(float outerVolumeDecibels)
- {
- m_config.m_outerVolume = ma_volume_db_to_linear(outerVolumeDecibels) * 100.f;
- OnConfigurationUpdated();
- }
- bool MiniAudioPlaybackComponentController::GetFixedDirecion() const
- {
- return m_config.m_fixedDirection;
- }
- void MiniAudioPlaybackComponentController::SetFixedDirecion(bool fixedDirection)
- {
- m_config.m_fixedDirection = fixedDirection;
- }
- float MiniAudioPlaybackComponentController::GetDirectionalAttenuationFactor() const
- {
- return ma_sound_get_directional_attenuation_factor(m_sound.get());
- }
- void MiniAudioPlaybackComponentController::SetDirectionalAttenuationFactor(float directionalAttenuationFactor)
- {
- m_config.m_directionalAttenuationFactor = directionalAttenuationFactor;
- OnConfigurationUpdated();
- }
- AZ::Vector3 MiniAudioPlaybackComponentController::GetDirection() const
- {
- ma_vec3f direction = ma_sound_get_direction(m_sound.get());
- return AZ::Vector3(direction.x, direction.y, direction.z);
- }
- void MiniAudioPlaybackComponentController::SetDirection(const AZ::Vector3& direction)
- {
- m_config.m_direction = direction;
- ma_sound_set_direction(m_sound.get(), m_config.m_direction.GetX(), m_config.m_direction.GetY(), m_config.m_direction.GetZ());
- }
- void MiniAudioPlaybackComponentController::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
- {
- AZ::Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId());
- // Re-assign the sound before attempting to load it if it was
- // released and the asset is now ready.
- // This can happen in the Editor when returning from game mode
- if (!m_config.m_sound.IsReady())
- {
- m_config.m_sound = asset;
- }
- LoadSound();
- }
- void MiniAudioPlaybackComponentController::OnWorldTransformChanged(const AZ::Transform& world)
- {
- if (m_sound)
- {
- ma_sound_set_position(
- m_sound.get(), world.GetTranslation().GetX(), world.GetTranslation().GetY(), world.GetTranslation().GetZ());
- // Set the forward direction for the sound source
- if (!m_config.m_fixedDirection)
- {
- AZ::Transform worldTm = AZ::Transform::CreateIdentity();
- AZ::TransformBus::EventResult(worldTm, m_entityComponentIdPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
- ma_sound_set_direction(m_sound.get(), worldTm.GetBasisY().GetX(), worldTm.GetBasisY().GetY(), worldTm.GetBasisY().GetZ());
- }
- }
- }
- void MiniAudioPlaybackComponentController::OnConfigurationUpdated()
- {
- if (m_config.m_sound.IsReady() == false)
- {
- AZ::Data::AssetBus::MultiHandler::BusConnect(m_config.m_sound.GetId());
- m_config.m_sound.QueueLoad();
- }
- else
- {
- LoadSound();
- }
- }
- void MiniAudioPlaybackComponentController::LoadSound()
- {
- UnloadSound();
- if (ma_engine* engine = MiniAudioInterface::Get()->GetSoundEngine())
- {
- if (GetConfiguration().m_sound.IsReady())
- {
- m_soundName = GetConfiguration().m_sound.GetHint();
- const auto& assetBuffer = GetConfiguration().m_sound->m_data;
- if (assetBuffer.empty())
- {
- return;
- }
- ma_result result = ma_resource_manager_register_encoded_data(
- ma_engine_get_resource_manager(engine), m_soundName.c_str(), assetBuffer.data(), assetBuffer.size());
- if (result != MA_SUCCESS)
- {
- // An error occurred.
- return;
- }
- if (m_sound)
- {
- ma_sound_uninit(m_sound.get());
- m_sound.reset();
- }
- m_sound = AZStd::make_unique<ma_sound>();
- const ma_uint32 flags = MA_SOUND_FLAG_DECODE;
- result = ma_sound_init_from_file(engine, m_soundName.c_str(), flags, nullptr, nullptr, m_sound.get());
- if (result != MA_SUCCESS)
- {
- // An error occurred.
- return;
- }
- ma_sound_set_volume(m_sound.get(), (m_config.m_volume / 100.f));
- ma_sound_set_looping(m_sound.get(), m_config.m_loop);
- ma_sound_set_spatialization_enabled(m_sound.get(), m_config.m_enableSpatialization);
- if (m_config.m_enableSpatialization)
- {
- ma_sound_set_min_distance(m_sound.get(), m_config.m_minimumDistance);
- ma_sound_set_max_distance(m_sound.get(), m_config.m_maximumDistance);
- ma_sound_set_attenuation_model(m_sound.get(), static_cast<ma_attenuation_model>(m_config.m_attenuationModel));
- ma_sound_set_directional_attenuation_factor(m_sound.get(), m_config.m_directionalAttenuationFactor);
- // Set the forward direction for the sound source
- if (!m_config.m_fixedDirection)
- {
- AZ::Transform worldTm = AZ::Transform::CreateIdentity();
- AZ::TransformBus::EventResult(
- worldTm, m_entityComponentIdPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
- ma_sound_set_direction(
- m_sound.get(), worldTm.GetBasisY().GetX(), worldTm.GetBasisY().GetY(), worldTm.GetBasisY().GetZ());
- }
- else
- {
- ma_sound_set_direction(
- m_sound.get(), m_config.m_direction.GetX(), m_config.m_direction.GetY(), m_config.m_direction.GetZ());
- }
- ma_sound_set_cone(
- m_sound.get(), m_config.m_innerAngleInRadians, m_config.m_outerAngleInRadians, (m_config.m_outerVolume / 100.f));
- }
- if (m_config.m_autoFollowEntity)
- {
- m_entityMovedHandler.Disconnect();
- AZ::TransformBus::Event(
- m_entityComponentIdPair.GetEntityId(),
- &AZ::TransformBus::Events::BindTransformChangedEventHandler,
- m_entityMovedHandler);
- AZ::Transform worldTm = AZ::Transform::CreateIdentity();
- AZ::TransformBus::EventResult(worldTm, m_entityComponentIdPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
- OnWorldTransformChanged(worldTm);
- }
- else
- {
- m_entityMovedHandler.Disconnect();
- }
- // Automatically play after the sound loads if requested
- // This will play automatically in Editor and Game
- if (m_config.m_autoplayOnActivate)
- {
- Play();
- }
- }
- }
- }
- void MiniAudioPlaybackComponentController::UnloadSound()
- {
- if (ma_engine* engine = MiniAudioInterface::Get()->GetSoundEngine())
- {
- if (m_sound)
- {
- ma_sound_stop(m_sound.get());
- ma_sound_uninit(m_sound.get());
- m_sound.reset();
- }
- if (m_soundName.empty() == false)
- {
- ma_resource_manager_unregister_data(ma_engine_get_resource_manager(engine), m_soundName.c_str());
- m_soundName.clear();
- }
- }
- }
- } // namespace MiniAudio
|