Files
UnrealEngine/Engine/Source/Runtime/SignalProcessing/Public/DSP/Osc.h
2025-05-18 13:04:45 +08:00

293 lines
7.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "DSP/Dsp.h"
#include "DSP/ModulationMatrix.h"
#include "DSP/Noise.h"
namespace Audio
{
// Struct which wraps all factors which contribute to pitch of the oscillator
struct FOscFrequencyMod
{
// A factor which directly scales the frequency output (used for FM modulation)
float Scale;
// External modulation source
float ExternalMod;
// The modulated frequency value
float Mod;
// Exponential frequency modulation
float Detune;
// Pitch bend modulation (i.e. from mod wheel)
float PitchBend;
// Octave frequency modulation
float Octave;
// Semitones frequency modulation
float Semitones;
// cents frequency modulation
float Cents;
FOscFrequencyMod()
: Scale(1.0f)
, ExternalMod(0.0f)
, Mod(0.0f)
, Detune(0.0f)
, PitchBend(0.0f)
, Octave(0.0f)
, Semitones(0.0f)
, Cents(0.0f)
{}
};
// Oscillator base class
class IOscBase
{
public:
SIGNALPROCESSING_API IOscBase();
SIGNALPROCESSING_API IOscBase(const IOscBase&);
SIGNALPROCESSING_API virtual ~IOscBase();
// Initializes the oscillator
SIGNALPROCESSING_API virtual void Init(const float InSampleRate, const int32 InVoiceId = 0, FModulationMatrix* InMatrix = nullptr, const int32 ModMatrixStage = 1);
// Starts the oscillator
virtual void Start() = 0;
// Stops the oscillator
virtual void Stop() = 0;
// Generates the next sample of audio, optionally passes out the auxillary output (supported in some oscillators)
virtual float Generate(float* AuxOutput = nullptr) = 0;
// Updates oscillator state
SIGNALPROCESSING_API virtual void Update();
// Resets the oscillator
SIGNALPROCESSING_API virtual void Reset();
// Resets the phase of this oscillator to 0.0f
SIGNALPROCESSING_API virtual void ResetPhase();
// Sets the gain of the oscillator
void SetGain(const float InGain) { Gain = InGain; }
// Sets the gain modulator of the oscillator
void SetGainMod(const float InGainMod) { ExternalGainMod = InGainMod; }
// Sets the base frequency of the oscillator
SIGNALPROCESSING_API void SetFrequency(const float InFreqBase);
// Sets a frequency modulation value
SIGNALPROCESSING_API void SetFrequencyMod(const float InFreqMod);
// Sets the base frequency of the oscillator from the midi note number
SIGNALPROCESSING_API void SetNote(const float InNote);
// Returns the frequency of the oscillator
float GetFrequency() const { return BaseFreq; }
// Returns the frequency of the oscillator
float GetGain() const { return Gain; }
SIGNALPROCESSING_API void SetCents(const float InCents);
SIGNALPROCESSING_API void SetOctave(const float InOctave);
SIGNALPROCESSING_API void SetSampleRate(const float InSampleRate);
SIGNALPROCESSING_API void SetSemitones(const float InSemiTone);
SIGNALPROCESSING_API void SetDetune(const float InDetune);
SIGNALPROCESSING_API void SetPitchBend(const float InPitchBend);
SIGNALPROCESSING_API void SetFreqScale(const float InFreqScale);
// Sets the LFO pulse width for square-wave type oscillators
SIGNALPROCESSING_API void SetPulseWidth(const float InPulseWidth);
// Returns whether or not this oscillator is playing
bool IsPlaying() const { return bIsPlaying; }
// Returns if this oscillator should be synced to a leader oscillator
bool IsSync() const { return bIsSync; }
// Sets whether or not this oscillator should be synced to a leader oscillator. leader oscillator needs to have set this oscillator as its follower.
void SetSync(const bool bInSync) { bIsSync = bInSync; }
// Deprecated: use SetFollowerOsc
UE_DEPRECATED(5.1, "SetSlaveOsc is deprecated, please use SetFollowerOsc instead.")
SIGNALPROCESSING_API void SetSlaveOsc(IOscBase* InSlaveOsc);
// Sets the input oscillator as the follower of this oscillator
SIGNALPROCESSING_API void SetFollowerOsc(IOscBase* InFollowerOsc);
// Return patch destinations for various modulatable parameters
FPatchDestination GetModDestFrequency() const { return ModFrequencyDest; }
FPatchDestination GetModDestPulseWidth() const { return ModPulseWidthDest; }
FPatchDestination GetModDestGain() const { return ModGainDest; }
FPatchDestination GetModDestAdd() const { return ModAddDest; }
FPatchDestination GetModDestScale() const { return ModScaleDest; }
protected:
// Updates the phase based on the phase increment
void UpdatePhase()
{
Phase += PhaseInc;
}
// Returns true if there was a phase wrap this update
bool WrapPhase()
{
bool Result = false;
if (PhaseInc > 0.0f && Phase >= 1.0f)
{
Phase = FMath::Fmod(Phase, 1.0f);
Result = true;
}
else if (PhaseInc < 0.0f && Phase <= 0.0f)
{
Phase = FMath::Fmod(Phase, 1.0f) + 1.0f;
Result = true;
}
if (Result && FollowerOsc && FollowerOsc->IsSync())
{
FollowerOsc->ResetPhase();
}
return Result;
}
// Returns the current phase of the oscillator
FORCEINLINE float GetPhase() const
{
return Phase;
}
// Returns the quadrature phase, wrapped
FORCEINLINE float GetQuadPhase() const
{
return FMath::Fmod(Phase + 0.25f, 1.0f);
}
protected:
// The voice ID that this oscillator belongs to
int32 VoiceId;
// Sample rate of the oscillator
float SampleRate;
// Maximum frequency allowed
float Nyquist;
// The final frequency of the oscillator after computing all factors contributing to frequency
float Freq;
// The base frequency of the oscillator
float BaseFreq;
// Holds all frequency data
FOscFrequencyMod FreqData;
// Linear gain of the oscillator
float Gain;
// Linear gain modulation of the oscillator (used in amplitude modulation)
float ExternalGainMod;
// The current phase of oscillator (between 0.0 and 1.0)
float Phase;
// How much to increment the phase each update
float PhaseInc;
// Pulse width used in square LFOs
float PulseWidthBase;
// Pulse width modulator factor
float PulseWidthMod;
// The final pulse width
float PulseWidth;
// Modulation matrix to use for this oscillator
FModulationMatrix* ModMatrix;
FPatchDestination ModFrequencyDest;
FPatchDestination ModPulseWidthDest;
FPatchDestination ModGainDest;
FPatchDestination ModScaleDest;
FPatchDestination ModAddDest;
// Ptr to a follower oscillator that can be triggered to 0 phase if it is synced.
IOscBase* FollowerOsc;
// Whether or not the oscillator is on or off
bool bIsPlaying;
bool bChanged;
bool bIsSync;
};
namespace EOsc
{
enum Type
{
Sine,
Saw,
Triangle,
Square,
Noise,
NumOscTypes
};
}
// Pitched oscillator
class FOsc : public IOscBase
{
public:
SIGNALPROCESSING_API FOsc();
SIGNALPROCESSING_API virtual ~FOsc();
//~ Begin FOscBase
SIGNALPROCESSING_API virtual void Start() override;
SIGNALPROCESSING_API virtual void Stop() override;
SIGNALPROCESSING_API virtual void Reset() override;
SIGNALPROCESSING_API virtual void Update() override;
SIGNALPROCESSING_API virtual float Generate(float* AuxOutput = nullptr) override;
//~ End FOscBase
// Sets the oscillator type
void SetType(const EOsc::Type InType) { OscType = InType; }
// Gets the oscillator type
EOsc::Type GetType() const { return OscType; }
protected:
// Smooth out the saw-tooth discontinuities to improve aliasing
SIGNALPROCESSING_API float PolySmooth(const float InPhase, const float InPhaseInc);
// Current sign of the square mod, used for triangle wave generation
float TriangleSign;
// Used to store state for triangular differentiator
float DPW_z1;
// The pulse width base lerped
FExponentialEase PulseWidthLerped;
// The type of the oscillator
EOsc::Type OscType;
// a noise generator
FWhiteNoise Noise;
};
}