Files
UnrealEngineUWP/Engine/Source/Runtime/SignalProcessing/Private/LFO.cpp
ryan durand 0f0464a30e Updating copyright for Engine Runtime.
#rnx
#rb none


#ROBOMERGE-OWNER: ryan.durand
#ROBOMERGE-AUTHOR: ryan.durand
#ROBOMERGE-SOURCE: CL 10869210 via CL 10869511 via CL 10869900
#ROBOMERGE-BOT: (v613-10869866)

[CL 10870549 by ryan durand in Main branch]
2019-12-26 14:45:42 -05:00

216 lines
4.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DSP/LFO.h"
#include "DSP/Dsp.h"
namespace Audio
{
FLFO::FLFO()
: LFOType(ELFO::Sine)
, LFOMode(ELFOMode::Sync)
, ExponentialFactor(3.5f)
, RSHCounter(INDEX_NONE)
, RSHValue(0.0f)
, ModScale(1.0f)
, ModAdd(0.0f)
, LastOutput(0.0f)
, QuadLastOutput(0.0f)
{
}
FLFO::~FLFO()
{
}
void FLFO::Init(const float InSampleRate, const int32 InVoiceId, FModulationMatrix* InMatrix, const int32 ModMatrixStage)
{
IOscBase::Init(InSampleRate, InVoiceId, InMatrix, ModMatrixStage);
if (ModMatrix)
{
ModNormalPhase = ModMatrix->CreatePatchSource(InVoiceId);
ModQuadPhase = ModMatrix->CreatePatchSource(InVoiceId);
#if MOD_MATRIX_DEBUG_NAMES
ModNormalPhase.Name = TEXT("ModNormalPhase");
ModQuadPhase.Name = TEXT("ModQuadPhase");
#endif
}
}
void FLFO::Start()
{
if (LFOMode == ELFOMode::Sync || LFOMode == ELFOMode::OneShot)
{
Reset();
}
bIsPlaying = true;
}
void FLFO::Stop()
{
bIsPlaying = false;
}
void FLFO::Reset()
{
// reset base class first
IOscBase::Reset();
RSHValue = 0.0f;
RSHCounter = INDEX_NONE;
}
float FLFO::Generate(float* QuadPhaseOutput)
{
// If the LFO isn't playing, return 0.0 for quad phase and for normal output
if (!bIsPlaying)
{
if (QuadPhaseOutput)
{
*QuadPhaseOutput = QuadLastOutput;
}
return LastOutput;
}
const bool bWrapped = WrapPhase();
// If we're in the oneshot mode, check if we've wrapped
// and if so, turn the LFO off and return 0.0s
if (LFOMode == ELFOMode::OneShot && bWrapped)
{
bIsPlaying = false;
if (QuadPhaseOutput)
{
*QuadPhaseOutput = QuadLastOutput;
}
return LastOutput;
}
LastOutput = ComputeLFO(GetPhase(), QuadPhaseOutput);
// Update the LFO phase after computing LFO values
UpdatePhase();
// Return the output
return LastOutput;
}
float FLFO::ComputeLFO(const float InPhase, float* OutQuad)
{
float Output = 0.0f;
float QuadOutput = 0.0f;
float QuadPhase = InPhase + 0.25f;
if (QuadPhase >= 1.0f)
{
QuadPhase -= 1.0f;
}
switch (LFOType)
{
case ELFO::Sine:
{
float Angle = 2.0f * InPhase * PI - PI;
Output = Audio::FastSin(Angle);
Angle = 2.0f * QuadPhase * PI - PI;
QuadOutput = Audio::FastSin(Angle);
}
break;
case ELFO::UpSaw:
{
Output = GetBipolar(InPhase);
QuadOutput = GetBipolar(QuadPhase);
}
break;
case ELFO::DownSaw:
{
Output = -1.0f * GetBipolar(InPhase);
QuadOutput = -1.0f * GetBipolar(QuadPhase);
}
break;
case ELFO::Square:
{
Output = InPhase > PulseWidth ? -1.0f : 1.0f;
QuadOutput = QuadPhase > PulseWidth ? -1.0f : 1.0f;
}
break;
case ELFO::Triangle:
{
Output = FMath::Abs(GetBipolar(InPhase));
QuadOutput = FMath::Abs(GetBipolar(QuadPhase));;
// If not one-shot, we need to convert to bipolar
if (LFOMode != ELFOMode::OneShot)
{
Output = GetBipolar(Output);
QuadOutput = GetBipolar(QuadOutput);
}
}
break;
case ELFO::Exponential:
{
Output = FMath::Pow(InPhase, ExponentialFactor);
QuadOutput = FMath::Pow(QuadPhase, ExponentialFactor);
}
break;
case ELFO::RandomSampleHold:
{
const float FrequencyThreshold = SampleRate / Freq;
if (RSHCounter > (uint32)FrequencyThreshold)
{
RSHCounter = 0;
RSHValue = FMath::FRandRange(-1.0f, 1.0f);
}
else
{
++RSHCounter;
}
Output = RSHValue;
QuadOutput = RSHValue;
}
break;
}
const float MaxGain = Gain * ExternalGainMod;
Output = Output * MaxGain;
QuadOutput = QuadOutput * MaxGain;
// If we have a mod matrix, then mix in the destination data
// This allows LFO's (or envelopes, etc) to modulation this LFO
if (ModMatrix)
{
ModMatrix->GetDestinationValue(VoiceId, ModScaleDest, ModAdd);
ModMatrix->GetDestinationValue(VoiceId, ModAddDest, ModScale);
Output = Output * ModScale + ModAdd;
QuadOutput = QuadOutput * ModScale + ModAdd;
// Write out the modulations
ModMatrix->SetSourceValue(VoiceId, ModNormalPhase, Output);
ModMatrix->SetSourceValue(VoiceId, ModQuadPhase, QuadOutput);
}
QuadLastOutput = QuadOutput;
if (OutQuad)
{
*OutQuad = QuadOutput;
}
return Output;
}
}