Example implementation of glide/legato/portamento?

Hi, I’m trying to implement some nice glide into my bass synthesiser, but havent found any good resources or examples of people that have done the same. My approach (doesn’t work) so far has been to derive from dsp::MPESynthesiser:

//==============================================================================
class Synth  : public juce::MPESynthesiser
{
public:
    static constexpr auto maxNumVoices = 1; // Monophonic 
    Synth()
    {
        for (auto i = 0; i < maxNumVoices; ++i)
            addVoice (new Voice);
        
        setVoiceStealingEnabled (true);
    }

Then in the Voice class:

    void noteStarted() override
    {
        auto velocity = getCurrentlyPlayingNote().noteOnVelocity.asUnsignedFloat();
        auto freqHz = (float) getCurrentlyPlayingNote().getFrequencyInHertz();
        
        auto& osc = processorChain.get<oscIndex>();
        //check if the envelope is finished
        if (processorChain.get<envIndex>().getState() == Envelope::Idle)
        {
            processorChain.get<oscIndex>().reset();
        }
        
        osc.setFrequency (freqHz, true);
        osc.setVelocity (velocity);
        //retrigger envelope
        processorChain.get<envIndex>().gate(true);
    }

Every time a new buffer is asked for I update the parameters:

    void updateParams()
    {
        .....
        auto& osc = processorChain.get<oscIndex>();
        osc.setGlide(glideParam->get() * 0.001); //glide in MS so convert to seconds
        .....
    }

And then in order to implement the glide I copy and pasted the source code from juce::dsp::Oscillator in order to have a member variable glide:

template <typename SampleType>
class OscillatorWithGlide
{
public:
    /** Creates an uninitialised oscillator. Call initialise before first use. */
    OscillatorWithGlide() = default;
    .....
    void setGlide(float newGlideInSecs)
    {
        glideInSecs = newGlideInSecs;
        frequency.reset(sampleRate, glideInSecs);
    }
   .....
private:
    float glideInSecs = 0.01;
};

I have tested this and the glide is getting updated properly in the OscillatorWithGlide class, but it is not audible when I actually test. Does anyone know why this might be? Or can you point me to an existing example of a synthesiser implementing monophonic glide?

Many thanks.

Check out my synth Example in Gin: https://github.com/FigBug/Gin/tree/master/examples/Synth/Source

It’s based on the juce MPESynthesiser but I reworked the voice handling to support mono, legato, portamento etc out of the box.

Inherit from gin::Synthesiser instead and then you have the following functions to setup the synth how you’d like:

    void setMono (bool m)           { mono = m;         }
    void setNumVoices (int v)       { numVoices = v;    }
    void setLegato (bool l)         { legato = l;       }
    void setGlissando (bool g)      { glissando = g;    }
    void setPortamento (bool p)     { portamento = p;   }
    void setGlideRate (float r )    { glideRate = r;    }

Then in gin::SynthesiserVoice there is a new function to override, noteRetriggered() which is where you should slide to the new note.

void SynthVoice::noteRetriggered()
{
    auto note = getCurrentlyPlayingNote();
    
    if (glideInfo.fromNote != -1 && (glideInfo.glissando || glideInfo.portamento))
    {
        noteSmoother.setTime (glideInfo.rate);
        noteSmoother.setValue (note.initialNote / 127.0f);
    }
    else
    {
        noteSmoother.setValueUnsmoothed (note.initialNote / 127.0f);
    }

I’ve been meaning to write blog post on how my synth engine works, it also has a mod matrix. Maybe you’ll find it useful.

2 Likes

Amazing :slight_smile: Thank you, I will try to implement it and dig a bit to see how it works. :+1:
I’m unsure why this is not natively supported in the base dsp::MPESynthesiser

Hi, So I have basically completely implemented your synthesiser. However I am struggling to successfully turn off glide. I’m not sure whether to call setLegato(glideParam->get()) Or setPortamento(glideParam->get()) . And when I do, any new notes added to the note stack do not play. i.e. If I have a C held down, and then press the octave, there will be no output, compared to if glide is on where the note would jump to this new note. I hope that makes sense :smiley:

setPortamento(false) should be enough to turn it off. You only want to enable one of glissando or portamento at a time. If one of them is enabled, then legato should also have an effect. When you turn off portamento, is your noteRetriggered still getting called?

Yeah thats what I’ve been doing.

No, noteRetriggered isn’t getting called. Basically if portamento is off and I add a second note to the one already playing, I expect it to switch instantly to the new note, but for some reason neither noteStarted() nor noteRetriggered() get called when I press a second note. notStopped() does get called, but I can’t see a way to check if there is already a voice on the stack.

Ah, you need to add multiple voice objects to your synth even though it is mono. The playing voice will be fastKilled and the new voice will start. They will slightly overlap for a few ms.

I need to document this, it’s pretty complex how it works.

Hmm, I’m wondering if I’m overcomplicating it for myself, I am making a very specific, simple synth so I might try to go back to the standard juce::MPESynthesiser and override some of the note handling functions to enable Mono glide.