SynthLab SDK
SynthLFO

Start with the SynthLab::LFO object that is derived from SynthModule. This object is usually part of a synth so we will pretend that is the case here, and setup the LFO and use it with a fake MIDI event to test it - then, you may connect it to your own plugin framework project and test it with real MIDI.

You will need to add the following files for the SynthLFO:

Looking at the class documentation, you can see that the LFO:

  • uses a LFOParameter structure for control, both GUI and programatically
  • renders values into the ModulationOutput array
  • includes 2 LFO cores: LFOCore and FMLFOCore
  • for standalone mode, it tells us which constructor arguments to set as nullptr

We'll go with the default LFOCore object and jump to its documentation. There we can find the module strings and mod knob assignments (see class documentation - the "more..." text)

Module Strings, zero-indexed for your GUI Control:

  • triangle, sine, ramp_up, ramp_dn, exp_up, exp_dn, exp_tri, square, rand_SH1, pluck

We will choose the ramp_up waveform, which as a zero-indexed string entry is [2]. Next; look at the documentation to find the output data (render) location

From the docs on LFOCore:

  • kLFONormalOutput normal LFO output value
  • kLFOInvertedOutput 180 degrees out of phase with normal output
  • kUnipolarFromMax unipolar version of the waveform that sits at +1 when the output amplitude is at 0, and descends from +1 downward as the output amplitude is increases; specialized and used for tremolo
  • kUnipolarFromMin unipolar version of the waveform that sits at 0 when the output amplitude is at 0, and ascends from 0 upward as the output amplitude is increased; the ordinary unipolar version almost all modulators

This code shows you how to create the LFO object with a shared pointer that will auto-delete when not needed. This is the way objects are shared in SynthLab. First, look at the LFO constructor to see its shared database arguments:

// --- LFO constructor
SynthLFO(std::shared_ptr<MidiInputData> _midiInputData, /* MIDI shared data */
std::shared_ptr<LFOParameters> _parameters, /* Parameter shared data */
uint32_t blockSize = 64); /* blocksize default is 64 */
// ---

So, we will do the following:

  1. create the LFO and pass nullptr for the MIDI input and parameters arguments
  2. reset it with the sample rate
  3. use getParameters: set the waveform index (2 for ramp_up) and oscillator frequency (440.0 for fun)
  4. create a MIDI event and call the note-on handler
  5. call the render function repeatedly to render a new output value, get the outout from the ModulationOutput array
  6. call the note-off handler when event is done
#include "lfo.h"
// --- create a LFO via shared pointer; here is the definition
std::unique_ptr<SynthLab::SynthLFO> lfo = nullptr;
// --- here is the creation
lfo.reset(new SynthLab::SynthLFO(nullptr, /* MIDI input data */
nullptr, /* LFO parameters */
1)); /* process individual samples (block size = 1)*/
// --- initialize
lfo->reset(44100.0); // <- get from your framework
// --- get the parameter struct pointer;
// it was synthesized when we passed a nullptr into the constructor
std::shared_ptr<SynthLab::LFOParameters> parameters = lfo->getParameters();
if (parameters) // should never fail
{
// --- set the variable
parameters->frequency_Hz = 440.0;
// --- call the update function (only needs to be done once per render cycle)
lfo->update();
}
// ---

Now, in response to a MIDI note-on message, we setup a MIDIEvent structure and call the member function:

// --- prepare a MIDI event for note-on
midiEvent.midiNoteNumber = 60; // <- get from your framework
midiEvent.midiNoteVelocity = 127; // <- get from your framework
// --- send note event
lfo->doNoteOn(midiEvent);
// ---

At this point, we can start to render values from the LFO and grab them from the ModulationOutput array for the normal LFO output:

// --- render LFO output
lfo->render();
// --- here is the normal output value - do something with it!
double lfoNormOut = lfo->getModulationOutput()->getModValue(lfoNormOut);
// ---

From here you can keep rendering until the note-off message arrives:

// --- prepare a MIDI event for note-off
midiEvent.midiNoteNumber = 60; // <- get from your framework
midiEvent.midiNoteVelocity = 0; // <- get from your framework
// --- send note event
lfo->doNoteOff(midiEvent);
// ---

Now, experiment with changing the LFO parameters (see the LFOParameter documentation to see what you can change). Also, try experimenting with the mod knobs. These all take unipolar values from [0.0, +1.0]. You set them along with the other parameters whenever you update the object. Here, we will select the waveform at index location [8] which is the random sample and hold LFO. And, we will adjust the shape control (mod knob A) to 0.25 which will distort the waveform a bit:

// --- get parameters
std::shared_ptr<SynthLab::LFOParameters> parameters = lfo->getParameters();
if (parameters) // should never fail
{
// --- set the variable
parameters->waveformIndex = 8; //<- select the random S&H
parameters->modKnobValue[SynthLab::MOD_KNOB_A] = 0.25; //<- apply shape change
// --- call the update function
lfo->update();
}
// ---


synthlab_4.png