/******************************************************************************* The content of this file includes portions of the proprietary AUDIOKINETIC Wwise Technology released in source code form as part of the game integration package. The content of this file may not be used without valid licenses to the AUDIOKINETIC Wwise Technology. Note that the use of the game engine is subject to the Unreal(R) Engine End User License Agreement at https://www.unrealengine.com/en-US/eula/unreal License Usage Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use this file in accordance with the end user license agreement provided with the software or, alternatively, in accordance with the terms contained in a written agreement between you and Audiokinetic Inc. Copyright (c) 2023 Audiokinetic Inc. *******************************************************************************/ #include "AkWaapiSlate/Widgets/Input/AkSSlider.h" #include "AkAudioDevice.h" #include "Widgets/SBoxPanel.h" #include "Widgets/Input/SSlider.h" #include "Widgets/Text/STextBlock.h" #include "WaapiPicker/SWaapiPicker.h" #include "AkWaapiUMG/Components/WwiseUmgDragDropOp.h" #include "AkWaapiUMG/Components/WwisePropertyDragDropOp.h" #include "AkWaapiUtils.h" #include "Widgets/Input/SNumericEntryBox.h" /*------------------------------------------------------------------------------------ Defines ------------------------------------------------------------------------------------*/ #define LOCTEXT_NAMESPACE "AkWaapiUMG" /*------------------------------------------------------------------------------------ Helpers ------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------ Implementation ------------------------------------------------------------------------------------*/ void AkSSlider::Construct(const AkSSlider::FArguments& InDeclaration) { check(InDeclaration._Style); OnDropDelegate = InDeclaration._OnDrop; this->ChildSlot [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .HAlign(HAlign_Center) .VAlign(VAlign_Center) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .HAlign(HAlign_Center) .VAlign(VAlign_Center) [ SNew(STextBlock) .Text(this, &AkSSlider::GetAkSliderItemControlled) ] + SVerticalBox::Slot() .AutoHeight() .HAlign(HAlign_Center) .VAlign(VAlign_Center) [ SNew(STextBlock) .Text(this, &AkSSlider::GetAkSliderProperty) ] + SVerticalBox::Slot() .AutoHeight() .HAlign(HAlign_Center) .VAlign(VAlign_Center) [ SNew(SNumericEntryBox) .Value(this, &AkSSlider::GetAkSliderValue) .MinValue(this, &AkSSlider::GetAkSliderRangeMin) .MinSliderValue(this, &AkSSlider::GetAkSliderRangeMin) .MaxValue(this, &AkSSlider::GetAkSliderRangeMax) .MaxSliderValue(this, &AkSSlider::GetAkSliderRangeMax) .OnValueCommitted(this, &AkSSlider::OnValueCommitted) ] ] + SVerticalBox::Slot() [ SAssignNew(AkScrubberSSlider, SSlider) .OnValueChanged(this, &AkSSlider::HandleAkSliderValueChanged) .Style(InDeclaration._Style) ] ]; } TSharedPtr AkSSlider::GetAkSilder() const { return AkScrubberSSlider; } TOptional AkSSlider::GetAkSliderValue() const { if (AkScrubberSSlider.IsValid()) return AkScrubberSSlider->GetValue()*(UIMaxValue - UIMinValue) + UIMinValue; return 0.0f; } FText AkSSlider::GetAkSliderProperty() const { return FText::FromString(TEXT("Property : ") + AkSliderItemProperty); } FText AkSSlider::GetAkSliderItemControlled() const { return FText::FromString(TEXT("Item : ") + ItemControlled); } void AkSSlider::HandleAkSliderValueChanged(float NewValue) { if (AkSliderItemId.IsEmpty() || AkSliderItemProperty.IsEmpty()) { UE_LOG(LogAkAudio, Log, TEXT("No item or property to control")); return; } // Construct the arguments Json object" TSharedRef args = MakeShareable(new FJsonObject()); { args->SetStringField(WwiseWaapiHelper::OBJECT, AkSliderItemId); args->SetStringField(WwiseWaapiHelper::PROPERTY, AkSliderItemProperty); args->SetNumberField(WwiseWaapiHelper::VALUE, NewValue*(UIMaxValue - UIMinValue) + UIMinValue); // e.i. This gives us a range of volume from [-96 to 12] for the volume property } // Construct the options Json object; TSharedRef options = MakeShareable(new FJsonObject()); // Connect to Wwise Authoring on localhost. FAkWaapiClient* waapiClient = FAkWaapiClient::Get(); if (waapiClient == nullptr) { return; } #if AK_SUPPORT_WAAPI TSharedPtr outJsonResult; // Request data from Wwise using WAAPI if (!waapiClient->Call(ak::wwise::core::object::setProperty, args, options, outJsonResult)) { UE_LOG(LogAkAudio, Log, TEXT("Failed to set property %s on AKSSlider"), *AkSliderItemProperty); } #endif } FReply AkSSlider::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) { FReply HandledState = FReply::Unhandled(); TSharedPtr Operation = DragDropEvent.GetOperation(); if (Operation.IsValid()) { if (Operation->IsOfType()) { const auto& AssetDragDropOp = StaticCastSharedPtr(Operation); if (AssetDragDropOp.IsValid()) { const auto& WwiseAssets = AssetDragDropOp->GetWiseItems(); if (WwiseAssets.Num() && WwiseAssets[0].IsValid()) { SetAkSliderItemId(WwiseAssets[0]->ItemId.ToString(EGuidFormats::DigitsWithHyphensInBraces)); } if (OnDropDelegate.IsBound()) { HandledState = OnDropDelegate.Execute(MyGeometry, DragDropEvent); } if (!HandledState.IsEventHandled()) { if (WwiseAssets.Num() && WwiseAssets[0].IsValid()) { HandledState = FReply::Handled(); } } } } else if (Operation->IsOfType()) { const auto& AssetDragDropOp = StaticCastSharedPtr(Operation); if (AssetDragDropOp.IsValid()) { const auto& WwiseAssets = AssetDragDropOp->GetWiseProperties(); if (WwiseAssets.Num() && WwiseAssets[0].IsValid()) { SetAkSliderItemProperty(*WwiseAssets[0].Get()); } if (OnDropDelegate.IsBound()) { HandledState = OnDropDelegate.Execute(MyGeometry, DragDropEvent); } if (!HandledState.IsEventHandled()) { if (WwiseAssets.Num() && WwiseAssets[0].IsValid()) { HandledState = FReply::Handled(); } } } } } return HandledState; } void AkSSlider::SetAkSliderItemProperty(const FString& ItemProperty) { if (!ItemProperty.IsEmpty() && (AkSliderItemProperty != ItemProperty)) { AkSliderItemProperty = ItemProperty; UpdateRange(); } } const FString& AkSSlider::GetAkSliderItemProperty() const { return AkSliderItemProperty; } void AkSSlider::SetAkSliderItemId(const FString& ItemId) { if (!ItemId.IsEmpty() && (AkSliderItemId != ItemId)) { AkSliderItemId = ItemId; TSharedPtr getResult; FString itemName = TEXT(""); if (SWaapiPicker::CallWaapiGetInfoFrom(WwiseWaapiHelper::ID, AkSliderItemId, getResult, {})) { // Recover the information from the Json object getResult and use it to get the item name. TArray> StructJsonArray = getResult->GetArrayField(WwiseWaapiHelper::RETURN); if (StructJsonArray.Num() > 0) { const TSharedPtr& ItemInfoObj = StructJsonArray[0]->AsObject(); ItemControlled = ItemInfoObj->GetStringField(WwiseWaapiHelper::NAME); } } UpdateRange(); } } inline void AkSSlider::UpdateRange() { if(AkSliderItemId.IsEmpty()) return; // Construct the arguments Json object. TSharedRef args = MakeShareable(new FJsonObject()); args->SetStringField(WwiseWaapiHelper::OBJECT, AkSliderItemId); args->SetStringField(WwiseWaapiHelper::PROPERTY, AkSliderItemProperty); // Construct the options Json object. TSharedRef options = MakeShareable(new FJsonObject()); TSharedPtr outJsonResult; // Connect to Wwise Authoring on localhost. FAkWaapiClient* waapiClient = FAkWaapiClient::Get(); if (waapiClient) { #if AK_SUPPORT_WAAPI // Request data from Wwise using WAAPI if (waapiClient->Call(ak::wwise::core::object::getPropertyInfo, args, options, outJsonResult)) { // Recover the information from the Json object outJsonResult and use it to get the property state. if (outJsonResult->HasField(WwiseWaapiHelper::UI)) { TSharedPtr uiLimit = outJsonResult->GetObjectField(WwiseWaapiHelper::UI)->GetObjectField(WwiseWaapiHelper::VALUE); UIMinValue = uiLimit->GetNumberField(WwiseWaapiHelper::MIN); UIMaxValue = uiLimit->GetNumberField(WwiseWaapiHelper::MAX); } } #endif } } const FString& AkSSlider::GetAkSliderItemId() const { return AkSliderItemId; } void AkSSlider::SetAkSliderRangeMax(const double in_NewValue) { UIMaxValue = in_NewValue; } void AkSSlider::SetAkSliderRangeMin(const double in_NewValue) { UIMinValue = in_NewValue; } TOptional AkSSlider::GetAkSliderRangeMin() const { return UIMinValue; } TOptional AkSSlider::GetAkSliderRangeMax() const { return UIMaxValue; } void AkSSlider::OnValueCommitted(double InNewValue, ETextCommit::Type Commit) { if (AkSliderItemProperty.IsEmpty() || InNewValue > UIMaxValue || InNewValue < UIMinValue) { return; } const float newValue = (InNewValue - UIMinValue) / (UIMaxValue - UIMinValue); if (AkScrubberSSlider.IsValid()) AkScrubberSSlider->SetValue(newValue); HandleAkSliderValueChanged(newValue); } #undef LOCTEXT_NAMESPACE