HISE Docs

ModulatorSynth

The base class for all sound generators in HISE.
It is a extension of the juce::Synthesiser class with the following additions:


If you're know your way around writing a sound generator based on the juce::Synthesiser class, the adaption to this class should be very straight forward.

Class Hierarchy

Base Classes

Derived Classes

Public types

enum Parameters

Name Description
Gain the volume as gain factor from 0...1
Balance the stereo balance from -100 to 100
VoiceLimit the amount of voices
KillFadeTime the fade time when voices are killed module_list

Class methods

exportAsValueTree

ValueTree exportAsValueTree() const override

This saves the Processor .
It saves the ID, the bypassed state and the fold state. It also saves all child processors. You can overwrite this function and add more properties and their child processors but make sure you call the base class method.
For primitive values, you can use the macro saveAttribute(name, nameAsString):
You don't need to save the editor states, as the first 32 bits of EditorState is saved.

ValueTree exportAsValueTree() const override
{
    // must be named 'v' for the macros
    ValueTree v = BaseClass::exportAsValueTree(); 

    saveAttribute(attributeName, "AttributeName");

    // ...

    if(useTable) saveTable(tableVariableName, "TableVariableNameData");

    return v;
};


restoreFromValueTree()

restoreFromValueTree

void restoreFromValueTree(const ValueTree &v) override

Restores a previously saved ValueTree.
The value tree must be created with exportAsValueTree or it will be unpredictable. The child processors are created automatically (both for chains and processors with fixed internal chains, but you should overwrite this method if your Processor uses parameters.
There is a handy macro saveAttribute(name, nameAsString) for this purpose.

restoreFromValueTree(const ValueTree &v) override // parameter must be named 'v' for the macros
{
    // replace BaseClass with the class name of the immediate base class
    BaseClass::restoreFromValueTree(v); 
    
    loadAttribute(attributeName, "AttributeName");
    // ...
    
    // If your Processor uses tables: 
    if(useTable) loadTable(tableVariableName, "TableVariableData");
}


exportAsValueTree()

getAttribute

float getAttribute(int parameterIndex) const override

returns the attribute with the specified index (use a enum in the derived class).

setInternalAttribute

void setInternalAttribute(int parameterIndex, float newValue) override

Changes a Processor parameter.
Overwrite this method to do your handling. Call the overloaded method with the notification type parameter for external changes.
parameterIndexthe parameter index (use a enum from the derived class)
newValuethe new value between 0.0 and 1.0

getDefaultValue

float getDefaultValue(int parameterIndex) const override

Overwrite this and return the default value.

getChildProcessor

Processor * getChildProcessor(int processorIndex) override

This must be overriden by every Processor and return the Chain with the Chain index.
You can either:- return nullptr, if the Processor uses no internal chains


getNumChildProcessors

int getNumChildProcessors() const override

This must return the number of Child processors.
If this Processor is a Chain , you can use it's getHandler()->getNumProcessor() method.

getNumInternalChains

int getNumInternalChains() const override

If your processor uses internal chains, you can return the number here.
This is used by the ProcessorEditor to make the chain button bar.

createEditor

ProcessorEditorBody * createEditor(ProcessorEditor *parentEditor) override

Creates a ProcessorEditor for this Processor and returns the pointer.
If you subclass this, just allocate a ProcessorEditor of the desired type on the heap and return it. Remember to pass the Processor as parameter to allow asynchronous GUI notification. The concept between Processor and ProcessorEditor is the same as AudioProcessor and AudioProcessorEditor.

renderNextBlockWithModulators

void renderNextBlockWithModulators(AudioSampleBuffer &outputAudio, const HiseEventBuffer &inputMidi)

Call this instead of Synthesiser::renderNextBlock to let the ModulatorChains to their work.
This only renders the TimeVariantModulators (like a master effect) and calculates the voice modulation, so make sure you actually apply the voice modulation in the subclassed ModulatorSynthVoice callback.

preVoiceRendering

void preVoiceRendering(int startSample, int numThisTime)

This method is called to handle all modulatorchains just before the voice rendering.

renderVoice

void renderVoice(int startSample, int numThisTime)

This method is called to actually render all voices. It operates on the internal buffer of the ModulatorSynth.

postVoiceRendering

void postVoiceRendering(int startSample, int numThisTime)

This method is called to handle all modulatorchains after the voice rendering and handles the GUI metering. It assumes stereo mode.
The rendered buffer is supplied as reference to be able to apply changes here after all voices are rendered (eg. gain).

getColour

Colour getColour() const override

Overwrite this method if you want a special colour.
This colour will be used in the debug console and in the editor.

handleHiseEvent

void handleHiseEvent(const HiseEvent &e)

Same functionality as Synthesiser::handleMidiEvent(), but sends the midi event to all Modulators in the chains.

prepareToPlay

void prepareToPlay(double sampleRate, int samplesPerBlock)

This sets up the synth and the ModulatorChains.
Call this instead of Synthesiser::setCurrentPlaybackSampleRate(). It also sets the ModulatorChain 's voice amount, so be sure you add all SynthesiserVoices before you call this function.

setBypassed

void setBypassed(bool shouldBeBypassed, NotificationType notifyChangeHandler=dontSendNotification) noexcept override

This bypasses the processor. You don't have to check in the processors logic itself, normally the chain should do that for you.

killAllVoicesWithNoteNumber

void killAllVoicesWithNoteNumber(int noteNumber)

Kills the note with the specified note number.
This stops the note with a small fade out (instead of noteoff which can result in very long release times if the envelope says so

killLastVoice

int killLastVoice(bool allowTailOff=true)

Kills the voice that is playing for the longest time.

areVoicesActive

bool areVoicesActive() const

Call this from the message thread and it'll kill all voices at the next buffer.
Pass in a lambda and it will execute this asynchronously as soon as all voices are killed
@functionToExecuteWhenKilled: a lambda that will be executed as soon as the voices are killed @executeOnAudioThread: if true, the lambda will be synchronously called on the audio thread

soundCanBePlayed

bool soundCanBePlayed(ModulatorSynthSound *sound, int midiChannel, int midiNoteNumber, float velocity)

Checks if the message fits the sound, but can be overriden to implement other group start logic.

noteOn

void noteOn(const HiseEvent &m)

Same functionality as Synthesiser::noteOn(), but calls calculateVoiceStartValue() if a new voice is started.

collectSoundsToBeStarted

int collectSoundsToBeStarted(const HiseEvent &m)

This method should go through all sounds that are playable and fill the soundsToBeStarted array.

getVoiceIndex

int getVoiceIndex(const SynthesiserVoice *v) const

Returns the voice index for the voice (the index in the internal voice array). This is needed for the ModulatorChains to know which voice is started.

addProcessorsWhenEmpty

void addProcessorsWhenEmpty()

Adds a SimpleEnvelope to a empty ModulatorSynth to prevent clicks.

initRenderCallback

void initRenderCallback()

Clears the internal buffer. This must be called by subclasses for every renderNextBlockWithModulators.

setGain

void setGain(float newGain)

sets the gain of the ModulatorSynth from 0.0 to 1.0.

setBalance

void setBalance(float newBalance)

sets the balance from -1.0 (left) to 1.0 (right) and applies a equal power pan rule.

getBalance

float getBalance(bool getRightChannelGain) const

Returns the calculated (equal power) pan value for either the left or the right channel.

getGain

float getGain() const

Returns the gain of the ModulatorSynth from 0.0 to 1.0.

setGroup

void setGroup(ModulatorSynthGroup *parent)

Sets the parent group. This can only be called once, since synths are not supposed to change their parents.

getGroup

ModulatorSynthGroup * getGroup() const

Returns the ModulatorSynthGroup that this ModulatorSynth belongs to.

isInGroup

bool isInGroup() const

Checks if the Synth was added to a group.

getIndexInGroup

int getIndexInGroup() const

Returns the index of the child synth if it resides in a group and -1 if not.

getPlayingSynth

ModulatorSynth * getPlayingSynth()

Returns either itself or the group that is playing its voices.

setClockSpeed

void setClockSpeed(ClockSpeed newClockSpeed)

Sets the interval for the internal clock callback.

getConstantPitchValues

const float * getConstantPitchValues() const

Returns the pointer to the calculated pitch buffers for the ModulatorSynthVoice's render callback.

handleRetriggeredNote

void handleRetriggeredNote(ModulatorSynthVoice *voice)

specifies the behaviour when a note is started that is already ringing. By default, it is killed, but you can overwrite it to make something else.

getPitchValuesForVoice

float * getPitchValuesForVoice() const

Returns a read pointer to the calculated pitch values.

getFreeVoice

ModulatorSynthVoice * getFreeVoice(SynthesiserSound *s, int midiChannel, int midiNoteNumber)

Returns a read pointer to the calculated pitch values. Used by Synthgroups to render their pitch values on the voice value.