Files
UnrealEngine/Engine/Plugins/Runtime/Harmonix/Source/HarmonixDspTests/Private/Effects/DelayTests.cpp
2025-05-18 13:04:45 +08:00

219 lines
5.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Containers/Array.h"
#include "HarmonixDsp/AudioBuffer.h"
#include "HarmonixDsp/Effects/Delay.h"
#include "Misc/AutomationTest.h"
#if 0 // WITH_DEV_AUTOMATION_TESTS
namespace Harmonix::Dsp::Effects::Delay::Tests
{
using namespace Harmonix::Dsp::Effects;
class FTestDelay : public FAutomationTestBase
{
public:
FTestDelay(const FString& InName, const bool bInComplexTask)
: FAutomationTestBase(InName, bInComplexTask) {};
FTestDelay(const FString& InName)
: FAutomationTestBase(InName, false) {};
// simple struct to test input Sample with output OutDelay
struct FTestCase
{
float Sample;
float OutDelay;
};
struct FParameters
{
float SampleRate = 4;
int32 NumChannels = 1;
float MaxDelayTime = 1000.0f;
float DelayInSamples = 1.0f;
float WetGain = 1.0f;
float Feedback = 0.0f;
TArray<FTestCase> Cases;
FString ToString() const
{
return FString::Printf(TEXT("Delay In Samples = %.2f\n"
"Wet Gain = %.2f\n"
"Feedback = %.2f\n"),
DelayInSamples,
WetGain,
Feedback);
};
};
protected:
bool RunTest_ProcessInternal(const FString& Parameters, const FParameters& Test)
{
FDelay Delay;
Delay.Prepare(Test.SampleRate, Test.NumChannels, Test.MaxDelayTime);
float DelayInSeconds = Test.DelayInSamples / Test.SampleRate;
Delay.Clear();
Delay.SetTimeSyncOption(ETimeSyncOption::SpeedScale);
Delay.SetFeedbackGain(Test.Feedback);
Delay.SetWetGain(Test.WetGain);
Delay.SetDelaySeconds(DelayInSeconds);
Delay.ApplyNewParams();
TArray<FDelay::FDelayOutput> Outputs;
Outputs.SetNumUninitialized(Test.Cases.Num());
float* DelayLine = Delay.DelayLine.GetValidChannelData(0);
for (int TestIdx = 0; TestIdx < Test.Cases.Num(); ++TestIdx)
{
const FTestCase& Case = Test.Cases[TestIdx];
FDelay::FDelayOutput& Output = Outputs[TestIdx];
uint32 DelayLinePos = TestIdx % Delay.Length;
Delay.ProcessInternal(Case.Sample, DelayLinePos, DelayLine, Test.DelayInSamples, Test.Feedback, Output);
DelayLine[DelayLinePos] = Output.Feedback;
};
UTEST_TRUE(*PrintTestCases(Test.ToString(), Test.Cases, Outputs), CheckAll(Test.Cases, Outputs));
return true;
};
bool CheckAll(const TArray<FTestCase> Cases, const TArray<FDelay::FDelayOutput> Outputs)
{
if (Cases.Num() != Outputs.Num())
return false;
for (int Idx = 0; Idx < Cases.Num(); ++Idx)
{
if (Cases[Idx].OutDelay != Outputs[Idx].Delay)
return false;
}
// all tests passed
return true;
};
FString PrintTestCases(const FString& What, const TArray<FTestCase> Cases, const TArray<FDelay::FDelayOutput> Outputs)
{
TArray<FString> Expected;
Expected.Reset(Cases.Num());
TArray<FString> Actual;
Actual.Reset(Outputs.Num());
for (const FTestCase& Case : Cases)
{
Expected.Add(FString::SanitizeFloat(Case.OutDelay, 2));
};
for (const FDelay::FDelayOutput& Output : Outputs)
{
Actual.Add(FString::SanitizeFloat(Output.Delay, 2));
};
return FString::Printf(TEXT("Expected outputs to be equal:\n"
"Case: %s\n"
"Expected: {%s}\n"
"Actual: {%s}\n"),
*What, *FString::Join(Expected, TEXT(", ")), *FString::Join(Actual, TEXT(", ")));
};
};
IMPLEMENT_CUSTOM_SIMPLE_AUTOMATION_TEST(
FTestDelay2,
FTestDelay,
"Harmonix.Dsp.Effects.Delay.ProcessInternal_DelayInSamples=2.0_Feeback=1.0",
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FTestDelay2::RunTest(const FString& Parameters)
{
FParameters Test;
Test.SampleRate = 4;
Test.NumChannels = 1;
Test.MaxDelayTime = 1000.0f;
Test.DelayInSamples = 2.0f;
Test.WetGain = 1.0f;
Test.Feedback = 1.0f;
Test.Cases = {
{1.0f, 0.0f},
{0.0f, 0.0f},
{0.0f, 1.0f},
{0.0f, 0.0f},
{0.0f, 1.0f},
{0.0f, 0.0f},
{0.0f, 1.0f}
};
return RunTest_ProcessInternal(Parameters, Test);
};
IMPLEMENT_CUSTOM_SIMPLE_AUTOMATION_TEST(
FTestDelay1,
FTestDelay,
"Harmonix.Dsp.Effects.Delay.ProcessInternal_DelayInSamples=3.0",
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)
bool FTestDelay1::RunTest(const FString& Parameters)
{
FParameters Test;
Test.SampleRate = 4;
Test.NumChannels = 1;
Test.MaxDelayTime = 1000.0f;
Test.DelayInSamples = 3.0f;
Test.WetGain = 1.0f;
Test.Feedback = 0.0f;
Test.Cases = {
{1.0f, 0.0f},
{2.0f, 0.0f},
{4.0f, 0.0f},
{0.0f, 1.0f},
{0.0f, 2.0f},
{0.0f, 4.0f}
};
return RunTest_ProcessInternal(Parameters, Test);
};
IMPLEMENT_CUSTOM_SIMPLE_AUTOMATION_TEST(
FTestDelay0,
FTestDelay,
"Harmonix.Dsp.Effects.Delay.ProcessInternal_DelayInSamples=1.5",
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter
)
bool FTestDelay0::RunTest(const FString& Parameters)
{
FParameters Test;
Test.SampleRate = 4;
Test.NumChannels = 1;
Test.MaxDelayTime = 1000.0f;
Test.DelayInSamples = 1.5f;
Test.WetGain = 1.0f;
Test.Feedback = 0.0f;
Test.Cases = {
{1.0f, 0.0f},
{0.0f, 0.5f},
{2.0f, 0.5f},
{0.0f, 1.0f},
{4.0f, 1.0f},
{8.0f, 2.0f},
{2.0f, 6.0f},
{1.0f, 5.0f},
{0.0f, 1.5f},
{0.0f, 0.5f},
{0.0f, 0.0f}
};
return RunTest_ProcessInternal(Parameters, Test);
};
};
#endif