STK 4.5.0 modules

How can I do that and where?
In prepare to play or in the constructor?

Just before the for (int channel) in the processing code :

if (inputChannels > 0)
        buffer.copyFrom(1, 0, buffer, 0, 0, buffer.getNumSamples());

So basically, by doing so you delete the content of the right input channel, you replace it with the left channel content, and then you can process it like you would process your first channel through your second chorus object.

It is not very clear for me… i need to have a buffer.getWritePointer(0) in one chorus and (1) in the second chorus…

Can you say me the value of the stk::PitShift in semitones?
What value from 0 to 1 represent -7 semitones for example?

EDIT: Solved…

0.5 is -12
1 is 0
ecc…

@IvanC Thank you very much for the snippet of code, it works perfectly with stk pitch reverb and chorus, but not with the delay…
Here is the code that work for example in chorus:

void DigiFexAudioProcessor::applyChorus2(AudioSampleBuffer &buffer, int inputChannels)
{
    const int numSamples = buffer.getNumSamples();
    
    const float chorusDepth = params[14];
    const float chorusRate = params[15];
    const float chorusMix = params[16];
    
    chorus2.setModDepth(chorusDepth);
    chorus2.setModFrequency(chorusRate);
    chorus2.setEffectMix(chorusMix);
    
    if (inputChannels > 0)
        buffer.copyFrom(1, 0, buffer, 0, 0, buffer.getNumSamples());
    
    float* channelData = buffer.getWritePointer(1);
    
    for (int i = 0; i < numSamples; ++i)
    {
        channelData[i] = chorus2.tick(channelData[i]);
    }
} 

and here is the code that doesn’t work on delay:

void DigiFexAudioProcessor::applyDelay2(AudioSampleBuffer &buffer, AudioSampleBuffer &delayBuffer, int inputChannels)
{
    const int numSamples = buffer.getNumSamples();
    
    const float delayTime = params[25];
    const float delayGain = params[26];
    
    delay2.setDelay(delayTime);
    delay2.setEffectMix(delayGain);
    
    if (inputChannels > 0)
    {
        buffer.copyFrom(1, 0, buffer, 0, 0, buffer.getNumSamples());
        delayBuffer.copyFrom(1, 0, delayBuffer, 0, 0, delayBuffer.getNumSamples());
    }

    float* channelData = buffer.getWritePointer(1);
    float* delayData = delayBuffer.getWritePointer(1);
    
    for (int i = 0; i < numSamples; ++i)
    {
        float in = channelData[i];
        channelData[i] += delayData[i];
        delayData[i] = delay1.tick(delayData[i]) + in;
    }
}

If I change the pointers to 0 it works but same on both channels…

The delayBuffer is a private member of Processor.h and is set up in preppareToPlay(); with 2 channels and 12000 samples.

Hi @danlin, I’m using your stk filters in a project.
A FIlterDelay vst. I wrote a custom class for handling Delay and BiQuad that I instantiate in prepareToPlay and set in processBlock.
My custom class has a method for panning the effect between left and right audio channels. I use 2 instances of the class in pluginprocessor.cpp, the lFilter and rFilter.
I have this problem: the first instance (lFilter) doesn’t change pan (even if the slider knob sets the values) bitwise the second instance (rFiletr) works well. Do you have an idea of what is wrong?

FilterDelay.h

#include <math.h>

class FilterDelay
{
public:

    FilterDelay()
    {
        lBiQuad = stk::BiQuad();
        rBiQuad = stk::BiQuad();
        lDelay = stk::DelayA(22050.0, 44100.0);
        rDelay = stk::DelayA(22050.0, 44100.0);
    }

    void clear()
    {
        lBiQuad.clear();
        rBiQuad.clear();
        lDelay.clear();
        rDelay.clear();
    }
    
    void process(AudioSampleBuffer& buffer, AudioSampleBuffer& lDelayBuffer, AudioSampleBuffer& rDelayBuffer)
    {
        // Filter
        A = pow((db / 40), 10);
        
        w0 = 2 * M_PI * f0 / 44100.0;
        
        alpha = sin(w0) / (2 * Q);
        
        switch ( (int)type )
        {
            case 0:
                b0 =  (1 - cos(w0)) / 2;
                b1 =   1 - cos(w0);
                b2 =  (1 - cos(w0)) / 2;
                a0 =   1 + alpha;
                a1 =  -2 * cos(w0);
                a2 =   1 - alpha;
                break;
                
            case 1:
                b0 =  (1 + cos(w0)) / 2;
                b1 = -(1 + cos(w0));
                b2 =  (1 + cos(w0)) / 2;
                a0 =   1 + alpha;
                a1 =  -2 * cos(w0);
                a2 =   1 - alpha;
                break;
                
            case 2:
                b0 =   Q * alpha;
                b1 =   0;
                b2 =  -Q * alpha;
                a0 =   1 + alpha;
                a1 =  -2 * cos(w0);
                a2 =   1 - alpha;
                break;
                
            case 3:
                b0 =   alpha;
                b1 =   0;
                b2 =  -alpha;
                a0 =   1 + alpha;
                a1 =  -2 * cos(w0);
                a2 =   1 - alpha;
                break;
                
            case 4:
                b0 =   1;
                b1 =  -2 * cos(w0);
                b2 =   1;
                a0 =   1 + alpha;
                a1 =  -2 * cos(w0);
                a2 =   1 - alpha;
                break;
                
            case 5:
                b0 =   1 - alpha;
                b1 =  -2 * cos(w0);
                b2 =   1 + alpha;
                a0 =   1 + alpha;
                a1 =  -2 * cos(w0);
                a2 =   1 - alpha;
                break;

            case 6:
                b0 =   1 + alpha * A;
                b1 =  -2 * cos(w0);
                b2 =   1 - alpha * A;
                a0 =   1 + alpha / A;
                a1 =  -2 * cos(w0);
                a2 =   1 - alpha / A;
                break;
                
            case 7:
                b0 =  A * ((A+1) - (A-1) * cos(w0) + 2 * sqrt(A) * alpha);
                b1 =  2 * A * ((A-1) - (A+1) * cos(w0));
                b2 =  A * ((A+1) - (A-1) * cos(w0) - 2 * sqrt(A) * alpha);
                a0 =  (A+1) + (A-1) * cos(w0) + 2 * sqrt(A) * alpha;
                a1 =  -2 * ((A-1) + (A+1) * cos(w0));
                a2 =  (A+1) + (A-1) * cos(w0) - 2 * sqrt(A) * alpha;
                break;
                
            case 8:
                b0 =  A * ((A+1) + (A-1) * cos(w0) + 2 * sqrt(A) * alpha);
                b1 = -2 * A * ((A-1) + (A+1) * cos(w0));
                b2 =  A * ((A+1) + (A-1) * cos(w0) - 2 * sqrt(A) * alpha);
                a0 =  (A+1) - (A-1) * cos(w0) + 2 * sqrt(A) * alpha;
                a1 =  2 * ((A-1) - (A+1) * cos(w0));
                a2 =  (A+1) - (A-1) * cos(w0) - 2 * sqrt(A) * alpha;
                break;
        }
        
        b0 = b0 / a0;
        b1 = b1 / a0;
        b2 = b2 / a0;
        a1 = a1 / a0;
        a2 = a2 / a0;
        
        lBiQuad.setCoefficients(b0, b1, b2, a1, a2);
        //lBiQuad.setGain(lGain);
        
        rBiQuad.setCoefficients(b0, b1, b2, a1, a2);
        //rBiQuad.setGain(rGain);
        
        // Delay
        lDelay.setDelay(delayTime);
        lDelay.setGain(lGain);
        
        rDelay.setDelay(delayTime);
        rDelay.setGain(rGain);
        
        // Process Audio
        const int numSamples = buffer.getNumSamples();
        buffer.copyFrom(1, 0, buffer, 0, 0, numSamples);
        
        for (int i = 0; i < numSamples; ++i)
        {
            float* lBuf = buffer.getWritePointer(0);
            float* delayLBuf = lDelayBuffer.getWritePointer(0);
            
            float inL = lBuf[i];
            lBuf[i] += delayLBuf[i];
            delayLBuf[i] = lDelay.tick(delayLBuf[i] * delayFeedback) + lBiQuad.tick(inL) * delayLevel;
            
            float* rBuf = buffer.getWritePointer(1);
            float* delayRBuf = rDelayBuffer.getWritePointer(0);
            
            float inR = rBuf[i];
            rBuf[i] += delayRBuf[i];
            delayRBuf[i] = rDelay.tick(delayRBuf[i] * delayFeedback) + rBiQuad.tick(inR) * delayLevel;
        }
    }
    
    void setFilterType(float value)
    {
        type = value;
    }
    
    void setFilterFrequency (float value)
    {
        f0 = value;
    }
    
    void setFilterGain (float value)
    {
        db = value;
    }
    
    void setFilterQ (float value)
    {
        Q = value;
    }
    
    void setGlobalPan (float pan)
    {
        if (pan < 0.0)
        {
            lGain = 0.5;
            rGain = 0.5 - fabsf(pan / 2);
        }
        
        if (pan == 0.0)
        {
            lGain = 0.5;
            rGain = 0.5;
        }
        
        if (pan > 0.0)
        {
            lGain = 0.5 - fabsf(pan / 2);
            rGain = 0.5;
        }
    }
    
    void setDelayTime(float value)
    {
        delayTime = value;
    }
    
    void setDelayFeedback(float value)
    {
        delayFeedback = value;
    }
    
    void setDelayLevel(float value)
    {
        delayLevel = value;
    }
    
private:
    
    // Filter
    float type;
    
    float f0, db, Q;

    float lGain, rGain;

    float A, w0, alpha;
    float a0, a1, a2, b0, b1, b2;
  
    stk::BiQuad lBiQuad, rBiQuad;
    
    // Delay
    float delayTime, delayFeedback, delayLevel;
    
    stk::DelayA lDelay, rDelay;
};

PluginProcessor.cpp

void FilterDelayAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    // Audio Buffers

    lDelayBufferA.setSize(1, 12000);
    lDelayBufferA.clear();
    lDelayBufferB.setSize(1, 12000);
    lDelayBufferB.clear();

    rDelayBufferA.setSize(1, 12000);
    rDelayBufferA.clear();
    rDelayBufferB.setSize(1, 12000);
    rDelayBufferB.clear();

    // Left Filter
    lFilter = FilterDelay();

    const float ltype = *parameters.getRawParameterValue("lType");
    
    lFilter.setFilterType(ltype);
    
    const float ldb = *parameters.getRawParameterValue("lGain");
    
    lFilter.setFilterGain(ldb);
    
    const float lf0 = *parameters.getRawParameterValue("lFreq");
    
    lFilter.setFilterFrequency(lf0);
    
    const float lQ = *parameters.getRawParameterValue("lQ");
    
    lFilter.setFilterQ(lQ);
    
    const float lpan = *parameters.getRawParameterValue("lPan");
    
    lFilter.setGlobalPan(lpan);
    
    const float ltime = *parameters.getRawParameterValue("lTime");

    lFilter.setDelayTime(ltime);
    
    const float lfeedback = *parameters.getRawParameterValue("lFeedback");
    
    lFilter.setDelayFeedback(lfeedback);
    
    const float llevel = *parameters.getRawParameterValue("lLevel");
    
    lFilter.setDelayLevel(llevel);

    lFilter.clear();

    // Right Filter
    rFilter = FilterDelay();
    
    const float rtype = *parameters.getRawParameterValue("rType");
    
    rFilter.setFilterType(rtype);
    
    const float rdb = *parameters.getRawParameterValue("rGain");
    
    rFilter.setFilterGain(rdb);
    
    const float rf0 = *parameters.getRawParameterValue("rFreq");
    
    rFilter.setFilterFrequency(rf0);
    
    const float rQ = *parameters.getRawParameterValue("rQ");
    
    rFilter.setFilterQ(rQ);
    
    const float rpan = *parameters.getRawParameterValue("rPan");
    
    rFilter.setGlobalPan(rpan);
    
    const float rtime = *parameters.getRawParameterValue("rTime");
    
    rFilter.setDelayTime(rtime);
    
    const float rfeedback = *parameters.getRawParameterValue("rFeedback");
    
    rFilter.setDelayFeedback(rfeedback);
    
    const float rlevel = *parameters.getRawParameterValue("rLevel");
    
    rFilter.setDelayLevel(rlevel);
    
    rFilter.clear();
}

void FilterDelayAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
{
    // Left Filter
    const float ltype = *parameters.getRawParameterValue("lType");
    
    lFilter.setFilterType(ltype);
    
    lGraphType = ltype;
    
    if (ltype < 5.0) { showLFrequency = true; showLGain = false; showLQ = true; }
    else if (ltype == 5.0) { showLFrequency = false; showLGain = false; showLQ = false; }
    else if (ltype > 5.0) { showLFrequency = true; showLGain = true; showLQ = true; }

    const float ldb = *parameters.getRawParameterValue("lGain");
    
    lFilter.setFilterGain(ldb);
    
    const float lf0 = *parameters.getRawParameterValue("lFreq");
    
    lFilter.setFilterFrequency(lf0);
    
    const float lQ = *parameters.getRawParameterValue("lQ");
    
    lFilter.setFilterQ(lQ);
    
    const float lpan = *parameters.getRawParameterValue("lPan");
    
    lFilter.setGlobalPan(lpan);
    
    DBG(lpan);
    
    const float ltime = *parameters.getRawParameterValue("lTime");
    
    lFilter.setDelayTime(ltime);
    
    const float lfeedback = *parameters.getRawParameterValue("lFeedback");
    
    lFilter.setDelayFeedback(lfeedback);
    
    const float llevel = *parameters.getRawParameterValue("lLevel");
    
    lFilter.setDelayLevel(llevel);
    
    lFilter.process(buffer, lDelayBufferA, rDelayBufferA);
    
    // Right Filter
    const float rtype = *parameters.getRawParameterValue("rType");
    
    rFilter.setFilterType(rtype);
    
    rGraphType = rtype;

    if (rtype < 5.0) { showRFrequency = true; showRGain = false; showRQ = true; }
    else if (rtype == 5.0) { showRFrequency = false; showRGain = false; showRQ = false; }
    else if (rtype > 5.0) { showRFrequency = true; showRGain = true; showRQ = true; }
    
    const float rdb = *parameters.getRawParameterValue("rGain");
    
    rFilter.setFilterGain(rdb);
    
    const float rf0 = *parameters.getRawParameterValue("rFreq");
    
    rFilter.setFilterFrequency(rf0);
    
    const float rQ = *parameters.getRawParameterValue("rQ");
    
    rFilter.setFilterQ(rQ);
    
    const float rpan = *parameters.getRawParameterValue("rPan");
    
    rFilter.setGlobalPan(rpan);
    
    const float rtime = *parameters.getRawParameterValue("rTime");
    
    rFilter.setDelayTime(rtime);
    
    const float rfeedback = *parameters.getRawParameterValue("rFeedback");
    
    rFilter.setDelayFeedback(rfeedback);
    
    const float rlevel = *parameters.getRawParameterValue("rLevel");
    
    rFilter.setDelayLevel(rlevel);
    
    rFilter.process(buffer, lDelayBufferB, rDelayBufferB);
}

For what it’s worth, here’s how I got the STK Chorus module to work:

void ChorusTesterAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
{
    ScopedNoDenormals noDenormals;
    auto totalNumInputChannels  = getTotalNumInputChannels();
    auto totalNumOutputChannels = getTotalNumOutputChannels();

    for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
        buffer.clear (i, 0, buffer.getNumSamples());

    
    for (int i = 0; i < buffer.getNumSamples(); i++) {
        for (int channel = 0; channel < totalNumInputChannels; ++channel)
        {
            auto* channelData = buffer.getWritePointer (channel);
            if(channel == 0) {
                // Inputs the left channel (mono input) sample and retrieves the left-channel output sample
                channelData[i] = chorusEffect.tick(channelData[i], channel);
            } else {
                // Retrieves the right channel output sample
                channelData[i] = chorusEffect.lastOut(channel);
            }
        }
    }
}
1 Like