// Copyright Epic Games, Inc. All Rights Reserved. #include "AudioImpulseResponseAsset.h" #include "Algo/AnyOf.h" #include "EffectConvolutionReverb.h" #include "ToolMenus.h" #include "ContentBrowserMenuContexts.h" #include "Misc/PackageName.h" #include "Sound/SoundWaveProcedural.h" #include "ToolMenu.h" #include "ToolMenuSection.h" #include "DSP/FloatArrayMath.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(AudioImpulseResponseAsset) #define LOCTEXT_NAMESPACE "AssetTypeActions" UClass* FAssetTypeActions_AudioImpulseResponse::GetSupportedClass() const { return UAudioImpulseResponse::StaticClass(); } void FAudioImpulseResponseExtension::RegisterMenus() { UToolMenu* Menu = UToolMenus::Get()->ExtendMenu("ContentBrowser.AssetContextMenu.SoundWave"); FToolMenuSection& Section = Menu->FindOrAddSection("GetAssetActions"); Section.AddDynamicEntry("SoundWaveAssetConversion_CreateImpulseResponse", FNewToolMenuSectionDelegate::CreateLambda([](FToolMenuSection& InSection) { if (const UContentBrowserAssetContextMenuContext* Context = InSection.FindContext()) { if (!Algo::AnyOf(Context->SelectedAssets, [](const FAssetData& AssetData){ return AssetData.IsInstanceOf(); })) { const TAttribute Label = LOCTEXT("SoundWave_CreateImpulseResponse", "Create Impulse Response"); const TAttribute ToolTip = LOCTEXT("SoundWave_CreateImpulseResponseTooltip", "Creates an impulse response asset using the selected sound wave."); const FSlateIcon Icon = FSlateIcon(FAppStyle::GetAppStyleSetName(), "ClassIcon.ImpulseResponse"); const FToolMenuExecuteAction UIAction = FToolMenuExecuteAction::CreateStatic(&FAudioImpulseResponseExtension::ExecuteCreateImpulseResponse); InSection.AddMenuEntry("SoundWave_CreateImpulseResponse", Label, ToolTip, Icon, UIAction); } } })); } void FAudioImpulseResponseExtension::ExecuteCreateImpulseResponse(const FToolMenuContext& MenuContext) { const FString DefaultSuffix = TEXT("_IR"); FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked("AssetTools"); // Create the factory used to generate the asset UAudioImpulseResponseFactory* Factory = NewObject(); // only converts 0th selected object for now (see return statement) if (const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(MenuContext)) { for (USoundWave* Wave : Context->LoadSelectedObjectsIf([](const FAssetData& AssetData) { return !AssetData.IsInstanceOf(); })) { Factory->StagedSoundWave = Wave; // WeakPtr gets reset by the Factory after it is consumed // Determine an appropriate name FString Name; FString PackagePath; AssetToolsModule.Get().CreateUniqueAssetName(Wave->GetOutermost()->GetName(), DefaultSuffix, PackagePath, Name); // create new asset AssetToolsModule.Get().CreateAsset(Name, FPackageName::GetLongPackagePath(PackagePath), UAudioImpulseResponse::StaticClass(), Factory); } } } UAudioImpulseResponseFactory::UAudioImpulseResponseFactory(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { SupportedClass = UAudioImpulseResponse::StaticClass(); bCreateNew = false; bEditorImport = false; bEditAfterNew = true; } UObject* UAudioImpulseResponseFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) { UAudioImpulseResponse* NewAsset = NewObject(InParent, InName, Flags); if (StagedSoundWave.IsValid()) { USoundWave* Wave = StagedSoundWave.Get(); TArray ImportedSoundWaveData; uint32 ImportedSampleRate; uint16 ImportedChannelCount; Wave->GetImportedSoundWaveData(ImportedSoundWaveData, ImportedSampleRate, ImportedChannelCount); NewAsset->NumChannels = ImportedChannelCount; NewAsset->SampleRate = ImportedSampleRate; NewAsset->ImpulseResponse.Reset(); int32 NumSamples = ImportedSoundWaveData.Num() / sizeof(int16); if (NumSamples > 0) { NewAsset->ImpulseResponse.AddUninitialized(NumSamples); // Convert to float. const int16* InputBuffer = (int16*)ImportedSoundWaveData.GetData(); float* OutputBuffer = NewAsset->ImpulseResponse.GetData(); Audio::ArrayPcm16ToFloat(MakeArrayView(InputBuffer, NumSamples), MakeArrayView(OutputBuffer, NumSamples)); } #if WITH_EDITORONLY_DATA NewAsset->bIsEvenChannelCount = NewAsset->NumChannels % 2 == 0; #endif StagedSoundWave.Reset(); } return NewAsset; } #undef LOCTEXT_NAMESPACE