Applying panning to USynthComponent

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!