JUCE  v6.1.6 (6.0.8-1114)
JUCE API
Looking for a senior C++ dev?
I'm looking for work. Hire me!
juce::MPESynthesiser Class Reference

Base class for an MPE-compatible musical device that can play sounds. More...

#include <juce_MPESynthesiser.h>

Inheritance diagram for juce::MPESynthesiser:
Collaboration diagram for juce::MPESynthesiser:

Public Types

using TrackingMode = MPEInstrument::TrackingMode
 

Public Member Functions

 MPESynthesiser ()
 Constructor. More...
 
 MPESynthesiser (MPEInstrument &instrumentToUse)
 Constructor to pass to the synthesiser a custom MPEInstrument object to handle the MPE note state, MIDI channel assignment etc. More...
 
 ~MPESynthesiser () override
 Destructor. More...
 
void addVoice (MPESynthesiserVoice *newVoice)
 Adds a new voice to the synth. More...
 
void clearVoices ()
 Deletes all voices. More...
 
void enableLegacyMode (int pitchbendRange=2, Range< int > channelRange=Range< int >(1, 17))
 Puts the synthesiser into legacy mode. More...
 
Range< intgetLegacyModeChannelRange () const noexcept
 Returns the range of MIDI channels (1-16) to be used for notes when in legacy mode. More...
 
int getLegacyModePitchbendRange () const noexcept
 Returns the pitchbend range in semitones (0-96) to be used for notes when in legacy mode. More...
 
int getNumVoices () const noexcept
 Returns the number of voices that have been added. More...
 
double getSampleRate () const noexcept
 Returns the current target sample rate at which rendering is being done. More...
 
MPESynthesiserVoicegetVoice (int index) const
 Returns one of the voices that have been added. More...
 
MPEZoneLayout getZoneLayout () const noexcept
 Returns the synthesiser's internal MPE zone layout. More...
 
virtual void handleController (int, int, int)
 Callback for MIDI controller messages. More...
 
void handleMidiEvent (const MidiMessage &) override
 Handle incoming MIDI events. More...
 
virtual void handleProgramChange (int, int)
 Callback for MIDI program change messages. More...
 
bool isLegacyModeEnabled () const noexcept
 Returns true if the instrument is in legacy mode, false otherwise. More...
 
bool isVoiceStealingEnabled () const noexcept
 Returns true if note-stealing is enabled. More...
 
void reduceNumVoices (int newNumVoices)
 Reduces the number of voices to newNumVoices. More...
 
void removeVoice (int index)
 Deletes one of the voices. More...
 
template<typename floatType >
void renderNextBlock (AudioBuffer< floatType > &outputAudio, const MidiBuffer &inputMidi, int startSample, int numSamples)
 Creates the next block of audio output. More...
 
void setCurrentPlaybackSampleRate (double newRate) override
 Tells the synthesiser what the sample rate is for the audio it's being used to render. More...
 
void setLegacyModeChannelRange (Range< int > channelRange)
 Re-sets the range of MIDI channels (1-16) to be used for notes when in legacy mode. More...
 
void setLegacyModePitchbendRange (int pitchbendRange)
 Re-sets the pitchbend range in semitones (0-96) to be used for notes when in legacy mode. More...
 
void setMinimumRenderingSubdivisionSize (int numSamples, bool shouldBeStrict=false) noexcept
 Sets a minimum limit on the size to which audio sub-blocks will be divided when rendering. More...
 
void setPitchbendTrackingMode (TrackingMode modeToUse)
 Set the MPE tracking mode for the pitchbend dimension. More...
 
void setPressureTrackingMode (TrackingMode modeToUse)
 Set the MPE tracking mode for the pressure dimension. More...
 
void setTimbreTrackingMode (TrackingMode modeToUse)
 Set the MPE tracking mode for the timbre dimension. More...
 
void setVoiceStealingEnabled (bool shouldSteal) noexcept
 If set to true, then the synth will try to take over an existing voice if it runs out and needs to play another note. More...
 
void setZoneLayout (MPEZoneLayout newLayout)
 Re-sets the synthesiser's internal MPE zone layout to the one passed in. More...
 
virtual void turnOffAllVoices (bool allowTailOff)
 Release all MPE notes and turn off all voices. More...
 
virtual void zoneLayoutChanged ()
 Implement this callback to be informed whenever the MPE zone layout or legacy mode settings of this instrument have been changed. More...
 

Protected Member Functions

virtual MPESynthesiserVoicefindFreeVoice (MPENote noteToFindVoiceFor, bool stealIfNoneAvailable) const
 Searches through the voices to find one that's not currently playing, and which can play the given MPE note. More...
 
virtual MPESynthesiserVoicefindVoiceToSteal (MPENote noteToStealVoiceFor=MPENote()) const
 Chooses a voice that is most suitable for being re-used to play a new note, or for being deleted by reduceNumVoices. More...
 
void noteAdded (MPENote newNote) override
 Attempts to start playing a new note. More...
 
void noteKeyStateChanged (MPENote changedNote) override
 Will find any voice that is currently playing changedNote, update its currently playing note, and call its noteKeyStateChanged method. More...
 
void notePitchbendChanged (MPENote changedNote) override
 Will find any voice that is currently playing changedNote, update its currently playing note, and call its notePitchbendChanged method. More...
 
void notePressureChanged (MPENote changedNote) override
 Will find any voice that is currently playing changedNote, update its currently playing note, and call its notePressureChanged method. More...
 
void noteReleased (MPENote finishedNote) override
 Stops playing a note. More...
 
void noteTimbreChanged (MPENote changedNote) override
 Will find any voice that is currently playing changedNote, update its currently playing note, and call its noteTimbreChanged method. More...
 
void renderNextSubBlock (AudioBuffer< double > &outputAudio, int startSample, int numSamples) override
 This will simply call renderNextBlock for each currently active voice and fill the buffer with the sum. More...
 
void renderNextSubBlock (AudioBuffer< float > &outputAudio, int startSample, int numSamples) override
 This will simply call renderNextBlock for each currently active voice and fill the buffer with the sum. More...
 
void startVoice (MPESynthesiserVoice *voice, MPENote noteToStart)
 Starts a specified voice and tells it to play a particular MPENote. More...
 
void stopVoice (MPESynthesiserVoice *voice, MPENote noteToStop, bool allowTailOff)
 Stops a given voice and tells it to stop playing a particular MPENote (which should be the same note it is actually playing). More...
 

Protected Attributes

MPEInstrumentinstrument
 
OwnedArray< MPESynthesiserVoicevoices
 
CriticalSection voicesLock
 

Private Attributes

MPEInstrument defaultInstrument { MPEZone (MPEZone::Type::lower, 15) }
 
uint32 lastNoteOnCounter = 0
 
int minimumSubBlockSize = 32
 
CriticalSection noteStateLock
 
double sampleRate = 0.0
 
std::atomic< boolshouldStealVoices { false }
 
bool subBlockSubdivisionIsStrict = false
 

Detailed Description

Base class for an MPE-compatible musical device that can play sounds.

This class extends MPESynthesiserBase by adding the concept of voices, each of which can play a sound triggered by a MPENote that can be modulated by MPE dimensions like pressure, pitchbend, and timbre, while the note is sounding.

To create a synthesiser, you'll need to create a subclass of MPESynthesiserVoice which can play back one of these sounds at a time.

Then you can use the addVoice() methods to give the synthesiser a set of voices it can use to play notes. If you only give it one voice it will be monophonic - the more voices it has, the more polyphony it'll have available.

Then repeatedly call the renderNextBlock() method to produce the audio (inherited from MPESynthesiserBase). The voices will be started, stopped, and modulated automatically, based on the MPE/MIDI messages that the synthesiser receives.

Before rendering, be sure to call the setCurrentPlaybackSampleRate() to tell it what the target playback rate is. This value is passed on to the voices so that they can pitch their output correctly.

See also
MPESynthesiserBase, MPESynthesiserVoice, MPENote, MPEInstrument

@tags{Audio}

Member Typedef Documentation

◆ TrackingMode

Constructor & Destructor Documentation

◆ MPESynthesiser() [1/2]

juce::MPESynthesiser::MPESynthesiser ( )

Constructor.

You'll need to add some voices before it'll make any sound.

See also
addVoice

◆ MPESynthesiser() [2/2]

juce::MPESynthesiser::MPESynthesiser ( MPEInstrument instrumentToUse)

Constructor to pass to the synthesiser a custom MPEInstrument object to handle the MPE note state, MIDI channel assignment etc.

(in case you need custom logic for this that goes beyond MIDI and MPE).

See also
MPESynthesiserBase, MPEInstrument

◆ ~MPESynthesiser()

juce::MPESynthesiser::~MPESynthesiser ( )
override

Destructor.

Member Function Documentation

◆ addVoice()

void juce::MPESynthesiser::addVoice ( MPESynthesiserVoice newVoice)

Adds a new voice to the synth.

All the voices should be the same class of object and are treated equally.

The object passed in will be managed by the synthesiser, which will delete it later on when no longer needed. The caller should not retain a pointer to the voice.

◆ clearVoices()

void juce::MPESynthesiser::clearVoices ( )

Deletes all voices.

◆ enableLegacyMode()

void juce::MPESynthesiserBase::enableLegacyMode ( int  pitchbendRange = 2,
Range< int channelRange = Rangeint >(1, 17) 
)
inherited

Puts the synthesiser into legacy mode.

Parameters
pitchbendRangeThe note pitchbend range in semitones to use when in legacy mode. Must be between 0 and 96, otherwise behaviour is undefined. The default pitchbend range in legacy mode is +/- 2 semitones.
channelRangeThe range of MIDI channels to use for notes when in legacy mode. The default is to use all MIDI channels (1-16).

To get out of legacy mode, set a new MPE zone layout using setZoneLayout.

◆ findFreeVoice()

virtual MPESynthesiserVoice* juce::MPESynthesiser::findFreeVoice ( MPENote  noteToFindVoiceFor,
bool  stealIfNoneAvailable 
) const
protectedvirtual

Searches through the voices to find one that's not currently playing, and which can play the given MPE note.

If all voices are active and stealIfNoneAvailable is false, this returns a nullptr. If all voices are active and stealIfNoneAvailable is true, this will call findVoiceToSteal() to find a voice.

If you need to find a free voice for something else than playing a note (e.g. for deleting it), you can pass an invalid (default-constructed) MPENote.

◆ findVoiceToSteal()

virtual MPESynthesiserVoice* juce::MPESynthesiser::findVoiceToSteal ( MPENote  noteToStealVoiceFor = MPENote()) const
protectedvirtual

Chooses a voice that is most suitable for being re-used to play a new note, or for being deleted by reduceNumVoices.

The default method will attempt to find the oldest voice that isn't the bottom or top note being played. If that's not suitable for your synth, you can override this method and do something more cunning instead.

If you pass a valid MPENote for the optional argument, then the note number of that note will be taken into account for finding the ideal voice to steal. If you pass an invalid (default-constructed) MPENote instead, this part of the algorithm will be ignored.

◆ getLegacyModeChannelRange()

Range<int> juce::MPESynthesiserBase::getLegacyModeChannelRange ( ) const
noexceptinherited

Returns the range of MIDI channels (1-16) to be used for notes when in legacy mode.

◆ getLegacyModePitchbendRange()

int juce::MPESynthesiserBase::getLegacyModePitchbendRange ( ) const
noexceptinherited

Returns the pitchbend range in semitones (0-96) to be used for notes when in legacy mode.

◆ getNumVoices()

int juce::MPESynthesiser::getNumVoices ( ) const
inlinenoexcept

Returns the number of voices that have been added.

◆ getSampleRate()

double juce::MPESynthesiserBase::getSampleRate ( ) const
inlinenoexceptinherited

Returns the current target sample rate at which rendering is being done.

Subclasses may need to know this so that they can pitch things correctly.

◆ getVoice()

MPESynthesiserVoice* juce::MPESynthesiser::getVoice ( int  index) const

Returns one of the voices that have been added.

◆ getZoneLayout()

MPEZoneLayout juce::MPESynthesiserBase::getZoneLayout ( ) const
noexceptinherited

Returns the synthesiser's internal MPE zone layout.

This happens by value, to enforce thread-safety and class invariants.

◆ handleController()

virtual void juce::MPESynthesiser::handleController ( int  ,
int  ,
int   
)
inlinevirtual

Callback for MIDI controller messages.

The default implementation provided here does nothing; override this method if you need custom MIDI controller handling on top of MPE.

This method will be called automatically according to the midi data passed into renderNextBlock().

◆ handleMidiEvent()

void juce::MPESynthesiser::handleMidiEvent ( const MidiMessage )
overridevirtual

Handle incoming MIDI events.

This method will be called automatically according to the MIDI data passed into renderNextBlock(), but you can also call it yourself to manually inject MIDI events.

This implementation forwards program change messages and non-MPE-related controller messages to handleProgramChange and handleController, respectively, and then simply calls through to MPESynthesiserBase::handleMidiEvent to deal with MPE-related MIDI messages used for MPE notes, zones etc.

This method can be overridden further if you need to do custom MIDI handling on top of what is provided here.

Reimplemented from juce::MPESynthesiserBase.

◆ handleProgramChange()

virtual void juce::MPESynthesiser::handleProgramChange ( int  ,
int   
)
inlinevirtual

Callback for MIDI program change messages.

The default implementation provided here does nothing; override this method if you need to handle those messages.

This method will be called automatically according to the midi data passed into renderNextBlock().

◆ isLegacyModeEnabled()

bool juce::MPESynthesiserBase::isLegacyModeEnabled ( ) const
noexceptinherited

Returns true if the instrument is in legacy mode, false otherwise.

◆ isVoiceStealingEnabled()

bool juce::MPESynthesiser::isVoiceStealingEnabled ( ) const
inlinenoexcept

Returns true if note-stealing is enabled.

◆ noteAdded()

void juce::MPESynthesiser::noteAdded ( MPENote  newNote)
overrideprotectedvirtual

Attempts to start playing a new note.

The default method here will find a free voice that is appropriate for playing the given MPENote, and use that voice to start playing the sound. If isNoteStealingEnabled returns true (set this by calling setNoteStealingEnabled), the synthesiser will use the voice stealing algorithm to find a free voice for the note (if no voices are free otherwise).

This method will be called automatically according to the midi data passed into renderNextBlock(). Do not call it yourself, otherwise the internal MPE note state will become inconsistent.

Reimplemented from juce::MPEInstrument::Listener.

◆ noteKeyStateChanged()

void juce::MPESynthesiser::noteKeyStateChanged ( MPENote  changedNote)
overrideprotectedvirtual

Will find any voice that is currently playing changedNote, update its currently playing note, and call its noteKeyStateChanged method.

This method will be called automatically according to the midi data passed into renderNextBlock(). Do not call it yourself.

Reimplemented from juce::MPEInstrument::Listener.

◆ notePitchbendChanged()

void juce::MPESynthesiser::notePitchbendChanged ( MPENote  changedNote)
overrideprotectedvirtual

Will find any voice that is currently playing changedNote, update its currently playing note, and call its notePitchbendChanged method.

This method will be called automatically according to the midi data passed into renderNextBlock(). Do not call it yourself.

Reimplemented from juce::MPEInstrument::Listener.

◆ notePressureChanged()

void juce::MPESynthesiser::notePressureChanged ( MPENote  changedNote)
overrideprotectedvirtual

Will find any voice that is currently playing changedNote, update its currently playing note, and call its notePressureChanged method.

This method will be called automatically according to the midi data passed into renderNextBlock(). Do not call it yourself.

Reimplemented from juce::MPEInstrument::Listener.

◆ noteReleased()

void juce::MPESynthesiser::noteReleased ( MPENote  finishedNote)
overrideprotectedvirtual

Stops playing a note.

This will be called whenever an MPE note is released (either by a note-off message, or by a sustain/sostenuto pedal release for a note that already received a note-off), and should therefore stop playing.

This will find any voice that is currently playing finishedNote, turn its currently playing note off, and call its noteStopped callback.

This method will be called automatically according to the midi data passed into renderNextBlock(). Do not call it yourself, otherwise the internal MPE note state will become inconsistent.

Reimplemented from juce::MPEInstrument::Listener.

◆ noteTimbreChanged()

void juce::MPESynthesiser::noteTimbreChanged ( MPENote  changedNote)
overrideprotectedvirtual

Will find any voice that is currently playing changedNote, update its currently playing note, and call its noteTimbreChanged method.

This method will be called automatically according to the midi data passed into renderNextBlock(). Do not call it yourself.

Reimplemented from juce::MPEInstrument::Listener.

◆ reduceNumVoices()

void juce::MPESynthesiser::reduceNumVoices ( int  newNumVoices)

Reduces the number of voices to newNumVoices.

This will repeatedly call findVoiceToSteal() and remove that voice, until the total number of voices equals newNumVoices. If newNumVoices is greater than or equal to the current number of voices, this method does nothing.

◆ removeVoice()

void juce::MPESynthesiser::removeVoice ( int  index)

Deletes one of the voices.

◆ renderNextBlock()

template<typename floatType >
void juce::MPESynthesiserBase::renderNextBlock ( AudioBuffer< floatType > &  outputAudio,
const MidiBuffer inputMidi,
int  startSample,
int  numSamples 
)
inherited

Creates the next block of audio output.

Call this to make sound. This will chop up the AudioBuffer into subBlock pieces separated by events in the MIDI buffer, and then call renderNextSubBlock on each one of them. In between you will get calls to noteAdded/Changed/Finished, where you can update parameters that depend on those notes to use for your audio rendering.

Parameters
outputAudioBuffer into which audio will be rendered
inputMidiMIDI events to process
startSampleThe first sample to process in both buffers
numSamplesThe number of samples to process

◆ renderNextSubBlock() [1/2]

void juce::MPESynthesiser::renderNextSubBlock ( AudioBuffer< double > &  outputAudio,
int  startSample,
int  numSamples 
)
overrideprotectedvirtual

This will simply call renderNextBlock for each currently active voice and fill the buffer with the sum.

(double-precision version) Override this method if you need to do more work to render your audio.

Reimplemented from juce::MPESynthesiserBase.

◆ renderNextSubBlock() [2/2]

void juce::MPESynthesiser::renderNextSubBlock ( AudioBuffer< float > &  outputAudio,
int  startSample,
int  numSamples 
)
overrideprotectedvirtual

This will simply call renderNextBlock for each currently active voice and fill the buffer with the sum.

Override this method if you need to do more work to render your audio.

Implements juce::MPESynthesiserBase.

◆ setCurrentPlaybackSampleRate()

void juce::MPESynthesiser::setCurrentPlaybackSampleRate ( double  newRate)
overridevirtual

Tells the synthesiser what the sample rate is for the audio it's being used to render.

This overrides the implementation in MPESynthesiserBase, to additionally propagate the new value to the voices so that they can use it to render the correct pitches.

Reimplemented from juce::MPESynthesiserBase.

◆ setLegacyModeChannelRange()

void juce::MPESynthesiserBase::setLegacyModeChannelRange ( Range< int channelRange)
inherited

Re-sets the range of MIDI channels (1-16) to be used for notes when in legacy mode.

◆ setLegacyModePitchbendRange()

void juce::MPESynthesiserBase::setLegacyModePitchbendRange ( int  pitchbendRange)
inherited

Re-sets the pitchbend range in semitones (0-96) to be used for notes when in legacy mode.

◆ setMinimumRenderingSubdivisionSize()

void juce::MPESynthesiserBase::setMinimumRenderingSubdivisionSize ( int  numSamples,
bool  shouldBeStrict = false 
)
noexceptinherited

Sets a minimum limit on the size to which audio sub-blocks will be divided when rendering.

When rendering, the audio blocks that are passed into renderNextBlock() will be split up into smaller blocks that lie between all the incoming midi messages, and it is these smaller sub-blocks that are rendered with multiple calls to renderVoices().

Obviously in a pathological case where there are midi messages on every sample, then renderVoices() could be called once per sample and lead to poor performance, so this setting allows you to set a lower limit on the block size.

The default setting is 32, which means that midi messages are accurate to about < 1ms accuracy, which is probably fine for most purposes, but you may want to increase or decrease this value for your synth.

If shouldBeStrict is true, the audio sub-blocks will strictly never be smaller than numSamples.

If shouldBeStrict is false (default), the first audio sub-block in the buffer is allowed to be smaller, to make sure that the first MIDI event in a buffer will always be sample-accurate (this can sometimes help to avoid quantisation or phasing issues).

◆ setPitchbendTrackingMode()

void juce::MPESynthesiserBase::setPitchbendTrackingMode ( TrackingMode  modeToUse)
inherited

Set the MPE tracking mode for the pitchbend dimension.

◆ setPressureTrackingMode()

void juce::MPESynthesiserBase::setPressureTrackingMode ( TrackingMode  modeToUse)
inherited

Set the MPE tracking mode for the pressure dimension.

◆ setTimbreTrackingMode()

void juce::MPESynthesiserBase::setTimbreTrackingMode ( TrackingMode  modeToUse)
inherited

Set the MPE tracking mode for the timbre dimension.

◆ setVoiceStealingEnabled()

void juce::MPESynthesiser::setVoiceStealingEnabled ( bool  shouldSteal)
inlinenoexcept

If set to true, then the synth will try to take over an existing voice if it runs out and needs to play another note.

The value of this boolean is passed into findFreeVoice(), so the result will depend on the implementation of this method.

◆ setZoneLayout()

void juce::MPESynthesiserBase::setZoneLayout ( MPEZoneLayout  newLayout)
inherited

Re-sets the synthesiser's internal MPE zone layout to the one passed in.

As a side effect, this will discard all currently playing notes, call noteReleased for all of them, and disable legacy mode (if previously enabled).

◆ startVoice()

void juce::MPESynthesiser::startVoice ( MPESynthesiserVoice voice,
MPENote  noteToStart 
)
protected

Starts a specified voice and tells it to play a particular MPENote.

You should never need to call this, it's called internally by MPESynthesiserBase::instrument via the noteStarted callback, but is protected in case it's useful for some custom subclasses.

◆ stopVoice()

void juce::MPESynthesiser::stopVoice ( MPESynthesiserVoice voice,
MPENote  noteToStop,
bool  allowTailOff 
)
protected

Stops a given voice and tells it to stop playing a particular MPENote (which should be the same note it is actually playing).

You should never need to call this, it's called internally by MPESynthesiserBase::instrument via the noteReleased callback, but is protected in case it's useful for some custom subclasses.

◆ turnOffAllVoices()

virtual void juce::MPESynthesiser::turnOffAllVoices ( bool  allowTailOff)
virtual

Release all MPE notes and turn off all voices.

If allowTailOff is true, the voices will be allowed to fade out the notes gracefully (if they can do). If this is false, the notes will all be cut off immediately.

This method is meant to be called by the user, for example to implement a MIDI panic button in a synth.

◆ zoneLayoutChanged()

virtual void juce::MPEInstrument::Listener::zoneLayoutChanged ( )
inlinevirtualinherited

Implement this callback to be informed whenever the MPE zone layout or legacy mode settings of this instrument have been changed.

Reimplemented in juce::MPEKeyboardComponent.

Member Data Documentation

◆ defaultInstrument

MPEInstrument juce::MPESynthesiserBase::defaultInstrument { MPEZone (MPEZone::Type::lower, 15) }
privateinherited

◆ instrument

MPEInstrument& juce::MPESynthesiserBase::instrument
protectedinherited

◆ lastNoteOnCounter

uint32 juce::MPESynthesiser::lastNoteOnCounter = 0
private

◆ minimumSubBlockSize

int juce::MPESynthesiserBase::minimumSubBlockSize = 32
privateinherited

◆ noteStateLock

CriticalSection juce::MPESynthesiserBase::noteStateLock
privateinherited

◆ sampleRate

double juce::MPESynthesiserBase::sampleRate = 0.0
privateinherited

◆ shouldStealVoices

std::atomic<bool> juce::MPESynthesiser::shouldStealVoices { false }
private

◆ subBlockSubdivisionIsStrict

bool juce::MPESynthesiserBase::subBlockSubdivisionIsStrict = false
privateinherited

◆ voices

OwnedArray<MPESynthesiserVoice> juce::MPESynthesiser::voices
protected

◆ voicesLock

CriticalSection juce::MPESynthesiser::voicesLock
protected

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