SynthLab SDK
Oscillator Pitch Modulation

Now you can add the code to do the pitch modulation in the new additive oscillator's update() function. There are multiple pitch modultion sources and a couple of different ways of handling the modulation functions. The setup below follows the synth book and uses the same modulation array input slots as the other oscillators in SynthLab. It also uses the same GUI parameter controls as discussed in the book and these documents. You can find very similar code througout the oscillator cores and you can find different mechanisms for manipulating the rendered waveforms including shape (phase distortion) and hard sync. Also note that each SynthLab oscillator has a special modulation called the "Unique Modulation" and these vary a bit with the type of oscillator. Reading and digesting these other object's example code will help you see how to do more modulations – and of course the synth book is highly recommended.

All SynthLab oscillators implement an update function that is nearly identical because the majority of the function involves pitch modulation. The pitch shift calculation creates a scalar value that you multiply with the MIDI note pitch value in Hz. Chapter 6 in the synth book contains the modulation equation and explains the theory. SynthLab pitched oscillators have numerous pitch shift sources that will need to be applied together.

Pitched oscillators expose the following GUI controls and modulation inputs via the parameters structure:
GUI Controls

  • octaveDetune
  • coarseDetune (semitones)
  • fineDetune (cents)
  • unisonDetune (cents)


  • bipolar pitch modulation (vibrato)
  • glide modulation (portamento)
  • MIDI pitch bend
  • Global Tuning

Here is the new update function that implements the moduation and that you may use for pitch modulation; test it with your MinSynth voice or within your own test project.

bool AddOscCore::update(CoreProcData& processInfo)
// --- Get Parameters (will use in next module)
OscParameters* parameters = static_cast<OscParameters*>(processInfo.moduleParameters);
// --- get the pitch bend value in semitones
double midiPitchBend = calculatePitchBend(processInfo.midiInputData);
// --- get the master tuning multiplier in semitones
double masterTuning = calculateMasterTuning(processInfo.midiInputData);
// --- calculate combined tuning offsets by simply adding values in semitones
double freqMod = processInfo.modulationInputs->getModValue(kBipolarMod) * kOscBipolarModRangeSemitones;
// --- do the portamento
double glideMod = glideModulator->getNextModulationValue();
// --- calculate combined tuning offsets by simply adding values in semitones
double currentPitchModSemitones = glideMod +
freqMod +
midiPitchBend +
masterTuning +
(parameters->oscSpecificDetune) + /* semitones */
(parameters->octaveDetune * 12) + /* octaves = semitones*12 */
(parameters->coarseDetune) + /* semitones */
(parameters->fineDetune / 100.0) + /* cents/100 = semitones */
(processInfo.unisonDetuneCents / 100.0); /* cents/100 = semitones */
// --- lookup the pitch shift modifier (fraction)
//double pitchShift = pitchShiftTableLookup(currentPitchModSemitones); <--- commented out!
// --- direct calculation version 2^(n/12) - note that this is equal temperatment
double pitchShift = pow(2.0, currentPitchModSemitones / 12.0);
// --- calculate the moduated pitch value
double oscillatorFrequency = midiPitch*pitchShift;
// --- BOUND the value to our range - in theory, we would bound this to any NYQUIST
boundValue(oscillatorFrequency, OSC_FMIN, OSC_FMAX);
// --- phase inc = fo/fs this sets it
oscClock.setFrequency(oscillatorFrequency, sampleRate);
return true;

Test your object again with pitch modulation from the LFO in MinSynth.