I think I’m missing something fairly fundamental about the right way to use Audio::FAmp to manage the panning of the Audio::FOsc in a simple USynthComponent child class:
I’ve set something up similar to what I saw being done in the modular synth and the granular synth but I think I’ve missed something fairly basic - would love some further insight.
Test class header:
UCLASS(ClassGroup = Synth, meta = (BlueprintSpawnableComponent))
class TESTPROJECT_API UTestSynthComponent : public USynthComponent
{
GENERATED_BODY()
// Called when synth is created
virtual bool Init(int32& SampleRate) override;
// Called to generate more audio
virtual int32 OnGenerateAudio(float* OutAudio, int32 NumSamples) override;
// Sets the oscillator's frequency
UFUNCTION(BlueprintCallable, Category = "Synth|Components|Audio")
void SetFrequency(const float FrequencyHz = 440.0f);
// Sets the pan of the synth -1.0, 1.0].
UFUNCTION(BlueprintCallable, Category = "Synth|Components|Audio")
void SetPan(float Pan);
protected:
// A simple oscillator class. Can also generate Saw/Square/Tri/Noise.
Audio::FOsc Osc;
Audio::FAmp Amp;
};
And its implementation:
bool UTestSynthComponent::Init(int32& SampleRate)
{
NumChannels = 1;
// Initialize the DSP objects
const int32 VoiceID{ 0 };
Osc.Init(SampleRate, VoiceID);
Amp.Init(VoiceID);
Osc.SetFrequency(440.0f);
Osc.Start();
return true;
}
int32 UTestSynthComponent::OnGenerateAudio(float* OutAudio, int32 NumSamples)
{
// Perform DSP operations here
for (int32 Sample = 0; Sample < NumSamples; ++Sample)
{
OutAudio[Sample] = Osc.Generate();
const int32 SampleIndex = 2 * Sample;
float* FrameBuffer = &OutAudio[SampleIndex];
Amp.Update();
Amp.ProcessAudio(FrameBuffer[0], FrameBuffer[1], &FrameBuffer[0], &FrameBuffer[1]);
}
return NumSamples;
}
void UTestSynthComponent::SetFrequency(const float InFrequencyHz)
{
// Use this protected base class method to push a lambda function which will safely execute in the audio render thread.
SynthCommand([this, InFrequencyHz]()
{
Osc.SetFrequency(InFrequencyHz);
Osc.Update();
});
}
void UTestSynthComponent::SetPan(float Pan)
{
SynthCommand([this, Pan]()
{
Amp.SetPan(Pan);
});
}
The oscillator generates audio as expected when activated through Blueprint, but the SetPan() method has no apparent effect. Thoughts on what I’ve missed?
Thanks!