SynthLab SDK
SynthLab::SynthVoice Class Reference

This is the voice object for a software synth. More...

#include <synthvoice.h>

Public Member Functions

 SynthVoice (std::shared_ptr< MidiInputData > _midiInputData, std::shared_ptr< MidiOutputData > _midiOutputData, std::shared_ptr< SynthVoiceParameters > _parameters, std::shared_ptr< WavetableDatabase > _wavetableDatabase, std::shared_ptr< PCMSampleDatabase > _sampleDatabase, uint32_t _blockSize=64)
 This is a template file with a minimal implementation. More...
 
virtual ~SynthVoice ()
 empty destructor
 
virtual bool reset (double _sampleRate)
 Reset all SynthModules on init or when sample rate changes. More...
 
virtual bool update ()
 Update voice specific stuff. More...
 
virtual bool render (SynthProcessInfo &synthProcessInfo)
 Render a block of audio data for an active note event. More...
 
virtual bool processMIDIEvent (midiEvent &event)
 MIDI Event handler. More...
 
virtual bool initialize (const char *dllPath=nullptr)
 Initialize the voice sub-components; this really only applies to PCM oscillators that need DLL path BUT, DLL path is avaialble for all modules and may be used in clever ways. More...
 
virtual bool doNoteOn (midiEvent &event)
 Note-on handler for voice. More...
 
virtual bool doNoteOff (midiEvent &event)
 Note-off handler for voice. More...
 
bool isVoiceActive ()
 
voiceState getVoiceState ()
 
uint32_t getTimestamp ()
 get current timestamp, the higher the value, the older the voice has been running
 
void incrementTimestamp ()
 increment timestamp when a new note is triggered
 
void clearTimestamp ()
 reset timestamp after voice is turned off
 
unsigned int getMIDINoteNumber ()
 note is data byte 1, velocity is byte 2
 
unsigned int getStealMIDINoteNumber ()
 note is data byte 1, velocity is byte 2
 
bool voiceIsStealing ()
 trur if voice will be stolen
 
void setAllCustomUpdateCodes ()
 one of many ways to keep track of what needs updating; this will likely be very dependent on your GUI system and plugin framework More...
 
 SynthVoice (std::shared_ptr< MidiInputData > _midiInputData, std::shared_ptr< MidiOutputData > _midiOutputData, std::shared_ptr< SynthVoiceParameters > _parameters, std::shared_ptr< WavetableDatabase > _wavetableDatabase, std::shared_ptr< PCMSampleDatabase > _sampleDatabase, uint32_t _blockSize=64)
 
virtual ~SynthVoice ()
 empty destructor
 
virtual bool reset (double _sampleRate)
 
virtual bool update ()
 
virtual bool render (SynthProcessInfo &synthProcessInfo)
 
virtual bool processMIDIEvent (midiEvent &event)
 
virtual bool initialize (const char *dllPath=nullptr)
 
virtual bool doNoteOn (midiEvent &event)
 
virtual bool doNoteOff (midiEvent &event)
 
bool isVoiceActive ()
 
voiceState getVoiceState ()
 
uint32_t getTimestamp ()
 get current timestamp, the higher the value, the older the voice has been running
 
void incrementTimestamp ()
 increment timestamp when a new note is triggered
 
void clearTimestamp ()
 reset timestamp after voice is turned off
 
uint32_t getMIDINoteNumber ()
 note is data byte 1, velocity is byte 2
 
uint32_t getStealMIDINoteNumber ()
 note is data byte 1, velocity is byte 2
 
bool voiceIsStealing ()
 trur if voice will be stolen
 
std::vector< std::string > getModuleCoreNames (uint32_t moduleType)
 only for dynamic string loading More...
 
std::vector< std::string > getModuleStrings (uint32_t mask, bool modKnobs)
 only for dynamic string loading More...
 
void setAllCustomUpdateCodes ()
 one of many ways to keep track of what needs updating; this will likely be very dependent on your GUI system and plugin framework
 
void loadLFOCore (uint32_t lfoIndex, uint32_t index)
 load a new LFO core More...
 
void loadFilterCore (uint32_t filterIndex, uint32_t index)
 load a new filter core More...
 
void loadOscCore (uint32_t oscIndex, uint32_t index)
 load a new oscillator core More...
 
void loadEGCore (uint32_t egIndex, uint32_t index)
 load a new EG core More...
 
void setDynamicModules (std::vector< std::shared_ptr< SynthLab::ModuleCore >> modules)
 add dynamically loaded DLL modules to existing cores More...
 
 SynthVoice (std::shared_ptr< MidiInputData > _midiInputData, std::shared_ptr< MidiOutputData > _midiOutputData, std::shared_ptr< SynthVoiceParameters > _parameters, std::shared_ptr< WavetableDatabase > _wavetableDatabase, std::shared_ptr< PCMSampleDatabase > _sampleDatabase, uint32_t _blockSize=64)
 
virtual ~SynthVoice ()
 empty destructor
 
virtual bool reset (double _sampleRate)
 
virtual bool update ()
 
virtual bool render (SynthProcessInfo &synthProcessInfo)
 
virtual bool processMIDIEvent (midiEvent &event)
 
virtual bool initialize (const char *dllPath=nullptr)
 
virtual bool doNoteOn (midiEvent &event)
 
virtual bool doNoteOff (midiEvent &event)
 
bool isVoiceActive ()
 
voiceState getVoiceState ()
 
uint32_t getTimestamp ()
 get current timestamp, the higher the value, the older the voice has been running
 
void incrementTimestamp ()
 increment timestamp when a new note is triggered
 
void clearTimestamp ()
 reset timestamp after voice is turned off
 
unsigned int getMIDINoteNumber ()
 note is data byte 1, velocity is byte 2
 
unsigned int getStealMIDINoteNumber ()
 note is data byte 1, velocity is byte 2
 
bool voiceIsStealing ()
 trur if voice will be stolen
 

Protected Member Functions

void accumulateToMixBuffer (std::shared_ptr< AudioBuffer > oscBuffers, uint32_t samplesInBlock, double scaling)
 accumulating voice audio data More...
 
void writeToMixBuffer (std::shared_ptr< AudioBuffer > oscBuffers, uint32_t samplesInBlock, double scaling)
 write to final mix buffer More...
 
void accumulateToMixBuffer (std::shared_ptr< AudioBuffer > oscBuffers, uint32_t samplesInBlock, double scaling)
 accumulating voice audio data
 
void writeToMixBuffer (std::shared_ptr< AudioBuffer > oscBuffers, uint32_t samplesInBlock, double scaling=1.0)
 write to final mix buffer
 
void removeMixBufferDC (uint32_t blockSize)
 
void accumulateToMixBuffer (std::shared_ptr< AudioBuffer > oscBuffers, uint32_t samplesInBlock, double scaling)
 accumulating voice audio data
 
void writeToMixBuffer (std::shared_ptr< AudioBuffer > oscBuffers, uint32_t samplesInBlock, double scaling)
 write to final mix buffer
 

Protected Attributes

std::shared_ptr< SynthVoiceParametersparameters = nullptr
 
std::unique_ptr< SynthLab::SynthLFOlfo = nullptr
 
std::unique_ptr< SynthLab::EnvelopeGeneratorampEG = nullptr
 
std::unique_ptr< SynthLab::WTOscillatorwtOsc = nullptr
 
std::unique_ptr< SynthLab::SynthFilterfilter = nullptr
 
std::unique_ptr< SynthLab::DCAdca = nullptr
 
std::unique_ptr< SynthLab::ModMatrixmodMatrix = nullptr
 
double sampleRate = 0.0
 
uint32_t blockSize = 64
 
std::shared_ptr< MidiInputDatamidiInputData = nullptr
 shared MIDI input data
 
std::shared_ptr< MidiOutputDatamidiOutputData = nullptr
 shared MIDI output data (not used in SynthLab)
 
std::shared_ptr< WavetableDatabasewavetableDatabase = nullptr
 shared wavetable database
 
std::shared_ptr< PCMSampleDatabasesampleDatabase = nullptr
 shared PCM database
 
std::shared_ptr< AudioBuffermixBuffers = nullptr
 buffers for mixing audio and procesisng the voice digital audio engine
 
uint32_t timestamp = 0
 voice timestamp, for knowing the age of a voice
 
int32_t currentMIDINote = -1
 voice timestamp, for knowing the age of a voice
 
voiceState voiceNoteState = voiceState::kNoteOffState
 state variable
 
bool voiceIsActive = false
 activity flag
 
midiEvent voiceMIDIEvent
 MIDI note event for current voice.
 
bool stealPending = false
 stealing is inevitible
 
midiEvent voiceStealMIDIEvent
 MIDI note event for the new (stolen) voice.
 
std::unique_ptr< ModMatrixmodMatrix
 mod matrix for this voice
 
std::unique_ptr< SynthModuleoscillator [NUM_OSC]
 oscillators
 
std::unique_ptr< SynthLFOlfo [NUM_LFO]
 LFOs.
 
std::unique_ptr< SynthFilterfilter [NUM_FILTER]
 filters
 
std::unique_ptr< EnvelopeGeneratorampEG
 amp EG
 
std::unique_ptr< EnvelopeGeneratorfilterEG
 filter EG
 
std::unique_ptr< EnvelopeGeneratorauxEG
 auxEG
 
std::unique_ptr< DCAdca
 one and only DCA
 
DCRemovalFilter dcFilter [STEREO_CHANNELS]
 DC removal for short term random bias. More...
 

Detailed Description

This is the voice object for a software synth.

The voice performs three tasks during the synth’s operation:

  • initialization
  • responding to MIDI note-on and note-off messages
  • controlling the audio signal flow through a set of member objects called modules.

The voice object’s central responsibility is maintaining this set of SynthModule objects that make up the synthesizer components such as oscillators and filters. I designed the SynthVoice object to expose simple functions that service these three areas of operation. The voice object also processes incoming MIDI data for note-on and note-off events, which it uses to control its set of modules.

  1. Initialization: the voice calls the module’s reset function
  2. Note-on and Note-off: the voice calls the doNoteOn and doNoteOff methods on its set of modules
  3. Controlling Audio Signal Flow: the voice calls the module’s update and render functions during each block processing cycle, and delivers the rendered audio back to the engine

Base Class: None

  • This object has no base class. It may be used as a base class for your own implementaitons, so several functions are declared as virtual.

GUI Parameters: SynthVoiceParameters

  • getParameters() function allows direct access to std::shared_ptr<SynthVoiceParameters>

std::shared_ptr<SynthVoiceParameters> getParameters()

  • call the getParameters() function
  • set the parameters in the SynthVoiceParameters structure with new values, typically from a GUI
  • the parameters will be applied to the underlying module during the render cycle.

Construction:

(1) For use within a synth project, the constructor is specialized to use shared recources for:

The owning object (SynthEngine for the SynthLab projects) must pass these valid pointers to the object at construction time. Typically the engine will be the primary synthesizers of these resources. See the 2nd Edition Synth Book for more information.

(2) Standalone:

To use in standalone mode, call the constructor with the shared resoure pointers as null:

SynthVoice(nullptr, nullptr, nullptr, nullptr, nullptr, 64);

In standalone mode, the object creates and maintains these resources:

  • SynthVoiceParameters: in standalone mode only, these are synthesized locally on the object, and then the owning object may obtain a shared pointer to them to read/write the parameters directly.

Render:

Author
Will Pirkle http://www.willpirkle.com
Remarks
This object is included and described in further detail in Designing Software Synthesizer Plugins in C++ 2nd Ed. by Will Pirkle
Version
Revision : 1.0
Date
Date : 2021 / 04 / 26

Constructor & Destructor Documentation

◆ SynthVoice()

SynthLab::SynthVoice::SynthVoice ( std::shared_ptr< MidiInputData _midiInputData,
std::shared_ptr< MidiOutputData _midiOutputData,
std::shared_ptr< SynthVoiceParameters _parameters,
std::shared_ptr< WavetableDatabase _wavetableDatabase,
std::shared_ptr< PCMSampleDatabase _sampleDatabase,
uint32_t  _blockSize = 64 
)

This is a template file with a minimal implementation.

Construction:

Construction:

  • constructs each of its SynthModule objects and uses one of the members of the voice parameter structure as the shared parameter pointers
  • supplies wavetable database to oscillators that need it
  • supplies PCM sample database to oscillators that need it
  • sets up the modulation matrix source and destinations using the SynthModule components
  • sets up hard-wired modulation matrix routings
  • supports standalone operation using nullptrs (see documentation)
Parameters
_midiInputDatashared pointer to MIDI input data; created on SynthEngine
_midiOutputDatashared pointer to MIDI input data; not used
_parametersshared pointer to voice parameter structure; shared with all other voices
_wavetableDatabaseshared pointer to wavetable database; created on SynthEngine
_sampleDatabaseshared pointer to PCM sample database; created on SynthEngine
blockSizethe block size to be used for the lifetime of operation; OK if arriving blocks are smaller than this value, NOT OK if larger
Returns
the newly constructed object
  • constructs each of its SynthModule objects and uses one of the members of the voice parameter structure as the shared parameter pointers
  • supplies wavetable database to oscillators that need it
  • supplies PCM sample database to oscillators that need it
  • sets up the modulation matrix source and destinations using the SynthModule components
  • sets up hard-wired modulation matrix routings
  • supports standalone operation using nullptrs (see documentation)
Parameters
_midiInputDatashared pointer to MIDI input data; created on SynthEngine
_midiOutputDatashared pointer to MIDI input data; not used
_parametersshared pointer to voice parameter structure; shared with all other voices
_wavetableDatabaseshared pointer to wavetable database; created on SynthEngine
_sampleDatabaseshared pointer to PCM sample database; created on SynthEngine
blockSizethe block size to be used for the lifetime of operation; OK if arriving blocks are smaller than this value, NOT OK if larger
Returns
the newly constructed object

Member Function Documentation

◆ accumulateToMixBuffer()

void SynthLab::SynthVoice::accumulateToMixBuffer ( std::shared_ptr< AudioBuffer oscBuffers,
uint32_t  samplesInBlock,
double  scaling 
)
protected

accumulating voice audio data

Accumulate buffers into voice's mix buffers.

Parameters
oscBuffersbuffers to add to the mix buffer
samplesInBlocksamples in this block to accumulate
scalingscaling mix coefficient if needed

◆ doNoteOff()

bool SynthLab::SynthVoice::doNoteOff ( midiEvent event)
virtual

Note-off handler for voice.

  • just forwards note-off handling to sub-objects
Parameters
eventMIDI note event

◆ doNoteOn()

bool SynthLab::SynthVoice::doNoteOn ( midiEvent event)
virtual

Note-on handler for voice.

  • For oscillators: start glide modulators then call note-on handlers
  • For all others: call note-on handlers
  • set and save voice state information
Parameters
eventMIDI note event

◆ getModuleCoreNames()

std::vector< std::string > SynthLab::SynthVoice::getModuleCoreNames ( uint32_t  moduleType)

only for dynamic string loading

Get function that returns module core NAMES for a given type of module.

  • optional: only needed if you allow dynamic loading of strings
  • will be very dependent on your framework's GUI
  • only need to query the first item in any set since they have the same attributes
Parameters
moduleTypeenumerated unsigned int that encodes the type of module for the query

◆ getModuleStrings()

std::vector< std::string > SynthLab::SynthVoice::getModuleStrings ( uint32_t  mask,
bool  modKnobs 
)

only for dynamic string loading

Get function that returns module core Strings for a given type of module.

  • optional: only needed if you allow dynamic loading of strings
  • will be very dependent on your framework's GUI
  • only need to query the first item in any set since they have the same attributes
Parameters
maskmask variable for decoding the type of query
modKnobstrue if querying for mod knob label strings

◆ getVoiceState() [1/3]

voiceState SynthLab::SynthVoice::getVoiceState ( )
inline

returns voice state; it is either note-on or note-off

◆ getVoiceState() [2/3]

voiceState SynthLab::SynthVoice::getVoiceState ( )
inline

returns voice state; it is either note-on or note-off

◆ getVoiceState() [3/3]

voiceState SynthLab::SynthVoice::getVoiceState ( )
inline

returns voice state; it is either note-on or note-off

◆ initialize()

bool SynthLab::SynthVoice::initialize ( const char *  dllPath = nullptr)
virtual

Initialize the voice sub-components; this really only applies to PCM oscillators that need DLL path BUT, DLL path is avaialble for all modules and may be used in clever ways.

Parameters
dllPathpath to folder containing this DLL
Returns
true if sucessful

◆ isVoiceActive() [1/3]

bool SynthLab::SynthVoice::isVoiceActive ( )
inline

returns voice activity; it is active if playing a note event

◆ isVoiceActive() [2/3]

bool SynthLab::SynthVoice::isVoiceActive ( )
inline

returns voice activity; it is active if playing a note event

◆ isVoiceActive() [3/3]

bool SynthLab::SynthVoice::isVoiceActive ( )
inline

returns voice activity; it is active if playing a note event

◆ loadEGCore()

void SynthLab::SynthVoice::loadEGCore ( uint32_t  egIndex,
uint32_t  index 
)

load a new EG core

Function to load a new EG Core.

  • optional, only for systems that allow dynamic GUIs
Parameters
egIndexindex of EG (0 or 1 as there are 2 EGs)
indexCore index parameter (0, 1, 2 or 3 as there are 4 cores)

◆ loadFilterCore()

void SynthLab::SynthVoice::loadFilterCore ( uint32_t  filterIndex,
uint32_t  index 
)

load a new filter core

Function to load a new filter Core.

  • optional, only for systems that allow dynamic GUIs
Parameters
filterIndexindex of filter (0 or 1 as there are 2 filters)
indexCore index parameter (0, 1, 2 or 3 as there are 4 cores)

◆ loadLFOCore()

void SynthLab::SynthVoice::loadLFOCore ( uint32_t  lfoIndex,
uint32_t  index 
)

load a new LFO core

Function to load a new LFO Core.

  • optional, only for systems that allow dynamic GUIs
Parameters
lfoIndexindex of LFO (0 or 1 as there are 2 LFOs)
indexCore index parameter (0, 1, 2 or 3 as there are 4 cores)

◆ loadOscCore()

void SynthLab::SynthVoice::loadOscCore ( uint32_t  oscIndex,
uint32_t  index 
)

load a new oscillator core

Function to load a new oscillator Core.

  • optional, only for systems that allow dynamic GUIs
Parameters
oscIndexindex of oscillator (0, 1, 2 or 3 as there are 4 oscillators)
indexCore index parameter (0, 1, 2 or 3 as there are 4 cores)

◆ processMIDIEvent()

bool SynthLab::SynthVoice::processMIDIEvent ( midiEvent event)
virtual

MIDI Event handler.

  • decodes MIDI message and processes note-on and note-off events only
  • all other MIDI messages are decoded and data stored in Synth Engine prior to calling this function
Parameters
eventMIDI note event

◆ render()

bool SynthLab::SynthVoice::render ( SynthProcessInfo synthProcessInfo)
virtual

Render a block of audio data for an active note event.

  • call the render function on modulators
  • run the modulation matrix
  • call the render function on mod targets
  • move audio output from oscillators to filters
  • move audio output from filters to DCA
  • move audio output from DCA to main mix buffers
  • check the status of the Amp EG object to see if note has expired
  • set steal-pending flag if voice is to be taken for next event
Parameters
synthProcessInfostructure of data needed for rendering this block.

◆ reset() [1/3]

virtual bool SynthLab::SynthVoice::reset ( double  _sampleRate)
virtual

main functions, declared as virtual so you can use as as base class if needed

◆ reset() [2/3]

virtual bool SynthLab::SynthVoice::reset ( double  _sampleRate)
virtual

main functions, declared as virtual so you can use as as base class if needed

◆ reset() [3/3]

bool SynthLab::SynthVoice::reset ( double  _sampleRate)
virtual

Reset all SynthModules on init or when sample rate changes.

main functions, declared as virtual so you can use as as base class if needed

Parameters
_sampleRatesample rate
Returns
true if sucessful

◆ setAllCustomUpdateCodes()

void SynthLab::SynthVoice::setAllCustomUpdateCodes ( )
inline

one of many ways to keep track of what needs updating; this will likely be very dependent on your GUI system and plugin framework

Update custom GUI codes; this is optional and only used as an example for keeping track of custom GUI events and needs. Use at your own risk:

  • will be very dependent on your coding style
  • will be very dependent on your framework's GUI
Parameters
eventMIDI note event

◆ setDynamicModules()

void SynthLab::SynthVoice::setDynamicModules ( std::vector< std::shared_ptr< SynthLab::ModuleCore >>  modules)

add dynamically loaded DLL modules to existing cores

Function to add dynamically loaded cores (DLLs) at load-time. These are added to the SynthModule's core array.

Parameters
modulesa vector of freshly created ModuleCores that were parsed at load-time

◆ update()

bool SynthLab::SynthVoice::update ( )
virtual

Update voice specific stuff.

  • the main thing this does is to load new cores as user selects them
Returns
true if sucessful

◆ writeToMixBuffer()

void SynthLab::SynthVoice::writeToMixBuffer ( std::shared_ptr< AudioBuffer oscBuffers,
uint32_t  samplesInBlock,
double  scaling = 1.0 
)
protected

write to final mix buffer

Write buffer into voice's mix buffers; unlike accumulate, this overwrites the audio data.

Parameters
oscBuffersbuffers to overwrite into the mix buffer
samplesInBlocksamples in this block to accumulate
scalingscaling mix coefficient if needed

Member Data Documentation

◆ dcFilter

DCRemovalFilter SynthLab::SynthVoice::dcFilter[STEREO_CHANNELS]
protected

DC removal for short term random bias.

remove DC offsets - many wavetables contain DC offsets when cobbled together

◆ parameters

std::shared_ptr< SynthVoiceParameters > SynthLab::SynthVoice::parameters = nullptr
protected

standalone operation only


The documentation for this class was generated from the following files: