Vst 2 mono input -> true stereo output

I’ve tried my plugin in StudioOne also, and it behaves like in Cubase…
Do anyone knows why?

Hi, I’ve noticed that if I set the plugin like you tell me, in the PluginHost if I bypass all effects, I ear only the left channel from the plugin.
I used all your code…
Why?

because there is no default behaviour implemented for bypass, it simply does nothing.
If you want your plugin to copy left to the right channel, you have to implement AudioProcessor::processBlockBypassed(…)

void MyProcessor::processBlockBypassed (AudioSampleBuffer& buffer, MidiBuffer&)
{
    const int numSamples = buffer.getNumSamples();
    buffer.copyFrom(1, 0, buffer, 0, 0, numSamples);
}

Remember, before your plugin the right channel didn’t exist, so it is natural that it is empty…

1 Like

I have another big problem…
I have this code on an object class:

class PanPitch
{
public:
    
    PanPitch ()
    {
        pitchLeft = stk::PitShift();
        pitchLeft.setShift(pitchVal);
        pitchLeft.setEffectMix(pitchLeftMix);
        pitchLeft.clear();

        pitchRight = stk::PitShift();
        pitchRight.setShift(pitchVal);
        pitchRight.setEffectMix(pitchRightMix);
        pitchRight.clear();
    }
    
    void clear ()
    {
        pitchLeft.clear();
        pitchRight.clear();
    }
    
    void process (AudioSampleBuffer& buffer)
    {
        const int numSamples = buffer.getNumSamples();
        buffer.copyFrom(1, 0, buffer, 0, 0, numSamples);
        
        pitchLeft.setShift(pitchVal);
        pitchLeft.setEffectMix(pitchLeftMix);
        
        pitchRight.setShift(pitchVal);
        pitchRight.setEffectMix(pitchRightMix);
        
        for (int i = 0; i < numSamples; ++i)
        {
            const float* inBuf = buffer.getReadPointer(0);
            float* lBuf = buffer.getWritePointer(0);
            float* rBuf = buffer.getWritePointer(1);
            
            lBuf[i] = pitchLeft.tick(inBuf[i]);
            rBuf[i] = pitchRight.tick(inBuf[i]);
        }
    }
    
    void setPitchVal (float value)
    {
        pitchVal = value;
    }
    
    void setPan (float pan)
    {
        pitchLeftMix = (1.0 - pan) * pitchMix;
        pitchRightMix = pan * pitchMix;
    }
    
    void setMix (float value)
    {
        pitchMix = value;
    }
    
private:
    
    float pitchVal;
    float pitchMix;
    float pitchLeftMix;
    float pitchRightMix;
    
    stk::PitShift pitchLeft;
    stk::PitShift pitchRight;
    
};

I call that object in the processBlock() method in this way:

    panPitch1.setPitchVal(params[3]);
    panPitch1.setPan(params[4]);
    panPitch1.setMix(params[5]);
    panPitch1.process(buffer);

But the object listen only to the left channel… it ignores the

buffer.copyFrom(1, 0, buffer, 0, 0, numSamples);

I also have in the processBlock():

const int numSamples = buffer.getNumSamples();
buffer.copyFrom(1, 0, buffer, 0, 0, numSamples);

May be they are in conflict?

SOLVED!

The object PanPitch should be like this:

class PanPitch
{
public:
    
    PanPitch ()
    {
        pitchLeft = stk::PitShift();
        pitchRight = stk::PitShift();
    }
    
    void clear ()
    {
        pitchLeft.clear();
        pitchRight.clear();
    }
    
    void process (AudioSampleBuffer& buffer)
    {
        const int numSamples = buffer.getNumSamples();
        buffer.copyFrom(1, 0, buffer, 0, 0, numSamples);
        
        pitchLeft.setShift(pitchVal);
        pitchLeft.setEffectMix(pitchLeftMix);
        
        pitchRight.setShift(pitchVal);
        pitchRight.setEffectMix(pitchRightMix);
        
        for (int i = 0; i < numSamples; ++i)
        {
            float* lBuf = buffer.getWritePointer(0);
            float* rBuf = buffer.getWritePointer(1);
            
            lBuf[i] = pitchLeft.tick(lBuf[i]);
            rBuf[i] = pitchRight.tick(rBuf[i]);
        }
    }
    
    void setPitchVal (float value)
    {
        pitchVal = value;
    }
    
    void setPan (float pan)
    {
        pitchLeftMix = (1.0 - pan) * pitchMix;
        pitchRightMix = pan * pitchMix;
    }
    
    void setMix (float value)
    {
        pitchMix = value;
    }
    
private:
    
    float pitchVal;
    float pitchMix;
    float pitchLeftMix;
    float pitchRightMix;
    
    stk::PitShift pitchLeft;
    stk::PitShift pitchRight;
    
};

The prepareToPlay() is:

panPitch1 = PanPitch();
panPitch1.setPitchVal(params[3]);
panPitch1.setPan(params[4]);
panPitch1.setMix(params[5]);
panPitch1.clear();

The call in processBlock() is:

if (params[5] > 0)
{
    panPitch1.setPitchVal(params[3]);
    panPitch1.setPan(params[4]);
    panPitch1.setMix(params[5]);
    panPitch1.process(buffer);
}

And always in processBlock() the first line must be:

const int numSamples = buffer.getNumSamples();
buffer.copyFrom(1, 0, buffer, 0, 0, numSamples);

And the isBusesLayoutSupported() like this:

const AudioChannelSet& mainInput  = layouts.getMainInputChannelSet();
const AudioChannelSet& mainOutput = layouts.getMainOutputChannelSet();

return mainInput.size() == 1 && mainOutput.size() == 2;

And finally the constructor of the AudioProcessor:

 : AudioProcessor (BusesProperties()
                   .withInput  ("Input",  AudioChannelSet::mono(), true)
                   .withOutput ("Output", AudioChannelSet::stereo(), true))

Et voilà!