/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include "LmbrCentral_precompiled.h" #include "AudioTriggerComponent.h" #include #include #include #include #include #include namespace LmbrCentral { //========================================================================= namespace ClassConverters { extern bool ConvertOldEditorAudioComponent(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); extern bool ConvertOldAudioComponent(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); extern bool ConvertOldAudioTriggerComponent(AZ::SerializeContext&, AZ::SerializeContext::DataElementNode&); } // namespace ClassConverters //========================================================================= // Behavior Context AudioTriggerComponentNotificationBus forwarder class BehaviorAudioTriggerComponentNotificationBusHandler : public AudioTriggerComponentNotificationBus::Handler, public AZ::BehaviorEBusHandler { public: AZ_EBUS_BEHAVIOR_BINDER(BehaviorAudioTriggerComponentNotificationBusHandler, "{ACCB0C42-3752-496B-9B1F-19276925EBB0}", AZ::SystemAllocator, OnTriggerFinished); void OnTriggerFinished(const Audio::TAudioControlID triggerID) override { Call(FN_OnTriggerFinished, triggerID); } }; //========================================================================= void AudioTriggerComponent::Reflect(AZ::ReflectContext* context) { auto serializeContext = azrtti_cast(context); if (serializeContext) { // Any old audio editor components need to be converted to GenericComponentWrapper-wrapped Audio Trigger components. serializeContext->ClassDeprecate("EditorAudioComponent", "{B238217F-1D76-4DEE-AA2B-09B7DFC6BF29}", &ClassConverters::ConvertOldEditorAudioComponent); // Any old audio runtime components need to be converted to Audio Trigger components. serializeContext->ClassDeprecate("AudioComponent", "{53033C2C-EE40-4D19-A7F4-861D6AA820EB}", &ClassConverters::ConvertOldAudioComponent); // Deprecate the old AudioTriggerComponent in favor of a new Editor component. serializeContext->ClassDeprecate("AudioTriggerComponent", "{80089838-4444-4D67-9A89-66B0276BB916}", &ClassConverters::ConvertOldAudioTriggerComponent); serializeContext->Class() ->Version(1) ->Field("Play Trigger", &AudioTriggerComponent::m_defaultPlayTriggerName) ->Field("Stop Trigger", &AudioTriggerComponent::m_defaultStopTriggerName) ->Field("Obstruction Type", &AudioTriggerComponent::m_obstructionType) ->Field("Plays Immediately", &AudioTriggerComponent::m_playsImmediately) ->Field("Send Finished Event", &AudioTriggerComponent::m_notifyWhenTriggerFinishes) ; } if (auto behaviorContext = azrtti_cast(context)) { behaviorContext->Enum(Audio::ObstructionType::Ignore)>("AudioObstructionType_Ignore") ->Enum(Audio::ObstructionType::SingleRay)>("AudioObstructionType_SingleRay") ->Enum(Audio::ObstructionType::MultiRay)>("AudioObstructionType_MultiRay") ; behaviorContext->EBus("AudioTriggerComponentRequestBus") ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview) ->Event("Play", &AudioTriggerComponentRequestBus::Events::Play) ->Event("Stop", &AudioTriggerComponentRequestBus::Events::Stop) ->Event("ExecuteTrigger", &AudioTriggerComponentRequestBus::Events::ExecuteTrigger) ->Event("KillTrigger", &AudioTriggerComponentRequestBus::Events::KillTrigger) ->Event("KillAllTriggers", &AudioTriggerComponentRequestBus::Events::KillAllTriggers) ->Event("SetMovesWithEntity", &AudioTriggerComponentRequestBus::Events::SetMovesWithEntity) ->Event("SetObstructionType", &AudioTriggerComponentRequestBus::Events::SetObstructionType) ; behaviorContext->EBus("AudioTriggerComponentNotificationBus") ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview) ->Handler() ; } } //========================================================================= void AudioTriggerComponent::Activate() { OnPlayTriggerChanged(); OnStopTriggerChanged(); OnObstructionTypeChanged(); if (m_notifyWhenTriggerFinishes) { m_callbackInfo.reset(new Audio::SAudioCallBackInfos( this, static_cast(GetEntityId()), nullptr, (Audio::eARF_PRIORITY_NORMAL | Audio::eARF_SYNC_FINISHED_CALLBACK) )); Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::AddRequestListener, &AudioTriggerComponent::OnAudioEvent, this, Audio::eART_AUDIO_CALLBACK_MANAGER_REQUEST, Audio::eACMRT_REPORT_FINISHED_TRIGGER_INSTANCE); } else { m_callbackInfo.reset(new Audio::SAudioCallBackInfos(Audio::SAudioCallBackInfos::GetEmptyObject())); } AudioTriggerComponentRequestBus::Handler::BusConnect(GetEntityId()); if (m_playsImmediately) { // if requested, play the set trigger at Activation time... Play(); } } //========================================================================= void AudioTriggerComponent::Deactivate() { AudioTriggerComponentRequestBus::Handler::BusDisconnect(GetEntityId()); if (m_notifyWhenTriggerFinishes) { Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::RemoveRequestListener, &AudioTriggerComponent::OnAudioEvent, this); } KillAllTriggers(); m_callbackInfo.reset(); } //========================================================================= AudioTriggerComponent::AudioTriggerComponent(const AZStd::string& playTriggerName, const AZStd::string& stopTriggerName, Audio::ObstructionType obstructionType, bool playsImmediately, bool notifyFinished) : m_defaultPlayTriggerName(playTriggerName) , m_defaultStopTriggerName(stopTriggerName) , m_obstructionType(obstructionType) , m_playsImmediately(playsImmediately) , m_notifyWhenTriggerFinishes(notifyFinished) { } //========================================================================= void AudioTriggerComponent::Play() { if (m_defaultPlayTriggerID != INVALID_AUDIO_CONTROL_ID) { AudioProxyComponentRequestBus::Event(GetEntityId(), &AudioProxyComponentRequestBus::Events::ExecuteTrigger, m_defaultPlayTriggerID, *m_callbackInfo); } } //========================================================================= void AudioTriggerComponent::Stop() { if (m_defaultStopTriggerID == INVALID_AUDIO_CONTROL_ID) { AudioProxyComponentRequestBus::Event(GetEntityId(), &AudioProxyComponentRequestBus::Events::KillTrigger, m_defaultPlayTriggerID); } else { AudioProxyComponentRequestBus::Event(GetEntityId(), &AudioProxyComponentRequestBus::Events::ExecuteTrigger, m_defaultStopTriggerID, *m_callbackInfo); } } //========================================================================= void AudioTriggerComponent::ExecuteTrigger(const char* triggerName) { if (triggerName && triggerName[0] != '\0') { Audio::TAudioControlID triggerID = INVALID_AUDIO_CONTROL_ID; Audio::AudioSystemRequestBus::BroadcastResult(triggerID, &Audio::AudioSystemRequestBus::Events::GetAudioTriggerID, triggerName); if (triggerID != INVALID_AUDIO_CONTROL_ID) { AudioProxyComponentRequestBus::Event(GetEntityId(), &AudioProxyComponentRequestBus::Events::ExecuteTrigger, triggerID, *m_callbackInfo); } } } //========================================================================= void AudioTriggerComponent::KillTrigger(const char* triggerName) { if (triggerName && triggerName[0] != '\0') { Audio::TAudioControlID triggerID = INVALID_AUDIO_CONTROL_ID; Audio::AudioSystemRequestBus::BroadcastResult(triggerID, &Audio::AudioSystemRequestBus::Events::GetAudioTriggerID, triggerName); if (triggerID != INVALID_AUDIO_CONTROL_ID) { AudioProxyComponentRequestBus::Event(GetEntityId(), &AudioProxyComponentRequestBus::Events::KillTrigger, triggerID); } } } //========================================================================= void AudioTriggerComponent::KillAllTriggers() { AudioProxyComponentRequestBus::Event(GetEntityId(), &AudioProxyComponentRequestBus::Events::KillAllTriggers); } //========================================================================= void AudioTriggerComponent::SetMovesWithEntity(bool shouldTrackEntity) { AudioProxyComponentRequestBus::Event(GetEntityId(), &AudioProxyComponentRequestBus::Events::SetMovesWithEntity, shouldTrackEntity); } //========================================================================= void AudioTriggerComponent::SetObstructionType(Audio::ObstructionType obstructionType) { if (m_obstructionType != obstructionType && obstructionType != Audio::ObstructionType::Count) { m_obstructionType = obstructionType; OnObstructionTypeChanged(); } } //========================================================================= // static void AudioTriggerComponent::OnAudioEvent(const Audio::SAudioRequestInfo* const requestInfo) { // look for the 'finished trigger instance' event if (requestInfo->eAudioRequestType == Audio::eART_AUDIO_CALLBACK_MANAGER_REQUEST) { const auto notificationType = static_cast(requestInfo->nSpecificAudioRequest); if (notificationType == Audio::eACMRT_REPORT_FINISHED_TRIGGER_INSTANCE) { if (requestInfo->eResult == Audio::eARR_SUCCESS) { AZ::EntityId entityId(reinterpret_cast(requestInfo->pUserData)); AudioTriggerComponentNotificationBus::Event(entityId, &AudioTriggerComponentNotificationBus::Events::OnTriggerFinished, requestInfo->nAudioControlID); } } } } //========================================================================= void AudioTriggerComponent::OnPlayTriggerChanged() { m_defaultPlayTriggerID = INVALID_AUDIO_CONTROL_ID; if (!m_defaultPlayTriggerName.empty()) { Audio::AudioSystemRequestBus::BroadcastResult(m_defaultPlayTriggerID, &Audio::AudioSystemRequestBus::Events::GetAudioTriggerID, m_defaultPlayTriggerName.c_str()); } // "ChangeNotify" sends callbacks on every key press for a text field! // This results in a lot of failed lookups. } //========================================================================= void AudioTriggerComponent::OnStopTriggerChanged() { m_defaultStopTriggerID = INVALID_AUDIO_CONTROL_ID; if (!m_defaultStopTriggerName.empty()) { Audio::AudioSystemRequestBus::BroadcastResult(m_defaultStopTriggerID, &Audio::AudioSystemRequestBus::Events::GetAudioTriggerID, m_defaultStopTriggerName.c_str()); } } //========================================================================= void AudioTriggerComponent::OnObstructionTypeChanged() { // This conversion to legacy enum will be removed eventually: auto legacyObstructionType = static_cast(m_obstructionType); AudioProxyComponentRequestBus::Event(GetEntityId(), &AudioProxyComponentRequestBus::Events::SetObstructionCalcType, legacyObstructionType); } } // namespace LmbrCentral