mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
MPE: replaced omniMode (all MIDI channels) by legacyMode which allows to define a custom MIDI channel range. Fixed a few minor MPE bugs.
This commit is contained in:
parent
1fe45f3d41
commit
e0bd51f26c
4 changed files with 236 additions and 75 deletions
|
|
@ -39,8 +39,9 @@ MPEInstrument::MPEInstrument() noexcept
|
|||
pressureDimension.value = &MPENote::pressure;
|
||||
timbreDimension.value = &MPENote::timbre;
|
||||
|
||||
omniMode.isEnabled = false;
|
||||
omniMode.pitchbendRange = 2;
|
||||
legacyMode.isEnabled = false;
|
||||
legacyMode.pitchbendRange = 2;
|
||||
legacyMode.channelRange = Range<int> (1, 17);
|
||||
}
|
||||
|
||||
MPEInstrument::~MPEInstrument()
|
||||
|
|
@ -58,24 +59,53 @@ void MPEInstrument::setZoneLayout (MPEZoneLayout newLayout)
|
|||
releaseAllNotes();
|
||||
|
||||
const ScopedLock sl (lock);
|
||||
omniMode.isEnabled = false;
|
||||
legacyMode.isEnabled = false;
|
||||
zoneLayout = newLayout;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MPEInstrument::enableOmniMode (int pitchbendRange)
|
||||
void MPEInstrument::enableLegacyMode (int pitchbendRange, Range<int> channelRange)
|
||||
{
|
||||
releaseAllNotes();
|
||||
|
||||
const ScopedLock sl (lock);
|
||||
omniMode.isEnabled = true;
|
||||
omniMode.pitchbendRange = pitchbendRange;
|
||||
legacyMode.isEnabled = true;
|
||||
legacyMode.pitchbendRange = pitchbendRange;
|
||||
legacyMode.channelRange = channelRange;
|
||||
zoneLayout.clearAllZones();
|
||||
}
|
||||
|
||||
bool MPEInstrument::isOmniModeEnabled() const noexcept
|
||||
bool MPEInstrument::isLegacyModeEnabled() const noexcept
|
||||
{
|
||||
return omniMode.isEnabled;
|
||||
return legacyMode.isEnabled;
|
||||
}
|
||||
|
||||
Range<int> MPEInstrument::getLegacyModeChannelRange() const noexcept
|
||||
{
|
||||
return legacyMode.channelRange;
|
||||
}
|
||||
|
||||
void MPEInstrument::setLegacyModeChannelRange (Range<int> channelRange)
|
||||
{
|
||||
jassert (Range<int>(1, 17).contains (channelRange));
|
||||
|
||||
releaseAllNotes();
|
||||
const ScopedLock sl (lock);
|
||||
legacyMode.channelRange = channelRange;
|
||||
}
|
||||
|
||||
int MPEInstrument::getLegacyModePitchbendRange() const noexcept
|
||||
{
|
||||
return legacyMode.pitchbendRange;
|
||||
}
|
||||
|
||||
void MPEInstrument::setLegacyModePitchbendRange (int pitchbendRange)
|
||||
{
|
||||
jassert (pitchbendRange >= 0 && pitchbendRange <= 96);
|
||||
|
||||
releaseAllNotes();
|
||||
const ScopedLock sl (lock);
|
||||
legacyMode.pitchbendRange = pitchbendRange;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -187,7 +217,10 @@ void MPEInstrument::processMidiControllerMessage (const MidiMessage& message)
|
|||
//==============================================================================
|
||||
void MPEInstrument::processMidiAllNotesOffMessage (const MidiMessage& message)
|
||||
{
|
||||
if (omniMode.isEnabled)
|
||||
// in MPE mode, "all notes off" is per-zone and expected on the master channel;
|
||||
// in legacy mode, "all notes off" is per MIDI channel (within the channel range used).
|
||||
|
||||
if (legacyMode.isEnabled && legacyMode.channelRange.contains (message.getChannel()))
|
||||
{
|
||||
for (int i = notes.size(); --i >= 0;)
|
||||
{
|
||||
|
|
@ -267,7 +300,7 @@ void MPEInstrument::noteOn (int midiChannel,
|
|||
int midiNoteNumber,
|
||||
MPEValue midiNoteOnVelocity)
|
||||
{
|
||||
if (! isNoteChannel (midiChannel) && ! omniMode.isEnabled)
|
||||
if (! isNoteChannel (midiChannel))
|
||||
return;
|
||||
|
||||
MPENote newNote (midiChannel,
|
||||
|
|
@ -299,7 +332,7 @@ void MPEInstrument::noteOff (int midiChannel,
|
|||
int midiNoteNumber,
|
||||
MPEValue midiNoteOffVelocity)
|
||||
{
|
||||
if (notes.empty() || (! isNoteChannel (midiChannel) && ! omniMode.isEnabled))
|
||||
if (notes.empty() || ! isNoteChannel (midiChannel))
|
||||
return;
|
||||
|
||||
const ScopedLock sl (lock);
|
||||
|
|
@ -357,7 +390,7 @@ void MPEInstrument::updateDimension (int midiChannel, MPEDimension& dimension, M
|
|||
{
|
||||
updateDimensionMaster (*zone, dimension, value);
|
||||
}
|
||||
else if (isNoteChannel (midiChannel) || omniMode.isEnabled)
|
||||
else if (isNoteChannel (midiChannel))
|
||||
{
|
||||
if (dimension.trackingMode == allNotesOnChannel)
|
||||
{
|
||||
|
|
@ -429,9 +462,9 @@ void MPEInstrument::callListenersDimensionChanged (MPENote& note, MPEDimension&
|
|||
//==============================================================================
|
||||
void MPEInstrument::updateNoteTotalPitchbend (MPENote& note)
|
||||
{
|
||||
if (omniMode.isEnabled)
|
||||
if (legacyMode.isEnabled)
|
||||
{
|
||||
note.totalPitchbendInSemitones = note.pitchbend.asSignedFloat() * omniMode.pitchbendRange;
|
||||
note.totalPitchbendInSemitones = note.pitchbend.asSignedFloat() * legacyMode.pitchbendRange;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -465,18 +498,19 @@ void MPEInstrument::sostenutoPedal (int midiChannel, bool isDown)
|
|||
//==============================================================================
|
||||
void MPEInstrument::handleSustainOrSostenuto (int midiChannel, bool isDown, bool isSostenuto)
|
||||
{
|
||||
// in MPE mode, sustain/sostenuto is per-zone and expected on the master channel;
|
||||
// in legacy mode, sustain/sostenuto is per MIDI channel (within the channel range used).
|
||||
|
||||
MPEZone* affectedZone = zoneLayout.getZoneByMasterChannel (midiChannel);
|
||||
|
||||
if (affectedZone == nullptr && ! omniMode.isEnabled)
|
||||
if (legacyMode.isEnabled ? (! legacyMode.channelRange.contains (midiChannel)) : (affectedZone == nullptr))
|
||||
return;
|
||||
|
||||
for (int i = notes.size(); --i >= 0;)
|
||||
{
|
||||
MPENote& note = notes.getReference (i);
|
||||
|
||||
if ((omniMode.isEnabled
|
||||
|| note.midiChannel == midiChannel)
|
||||
|| affectedZone->isUsingChannel (note.midiChannel))
|
||||
if (legacyMode.isEnabled ? (note.midiChannel == midiChannel) : affectedZone->isUsingChannel (note.midiChannel))
|
||||
{
|
||||
if (note.keyState == MPENote::keyDown && isDown)
|
||||
note.keyState = MPENote::keyDownAndSustained;
|
||||
|
|
@ -499,7 +533,7 @@ void MPEInstrument::handleSustainOrSostenuto (int midiChannel, bool isDown, bool
|
|||
|
||||
if (! isSostenuto)
|
||||
{
|
||||
if (omniMode.isEnabled)
|
||||
if (legacyMode.isEnabled)
|
||||
isNoteChannelSustained[midiChannel - 1] = isDown;
|
||||
else
|
||||
for (int i = affectedZone->getFirstNoteChannel(); i <= affectedZone->getLastNoteChannel(); ++i)
|
||||
|
|
@ -510,11 +544,17 @@ void MPEInstrument::handleSustainOrSostenuto (int midiChannel, bool isDown, bool
|
|||
//==============================================================================
|
||||
bool MPEInstrument::isNoteChannel (int midiChannel) const noexcept
|
||||
{
|
||||
if (legacyMode.isEnabled)
|
||||
return legacyMode.channelRange.contains (midiChannel);
|
||||
|
||||
return zoneLayout.getZoneByNoteChannel (midiChannel) != nullptr;
|
||||
}
|
||||
|
||||
bool MPEInstrument::isMasterChannel (int midiChannel) const noexcept
|
||||
{
|
||||
if (legacyMode.isEnabled)
|
||||
return false;
|
||||
|
||||
return zoneLayout.getZoneByMasterChannel (midiChannel) != nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -1672,10 +1712,10 @@ public:
|
|||
expectEquals (test.getNumPlayingNotes(), 0);
|
||||
}
|
||||
|
||||
beginTest ("MIDI all notes off (omni mode)");
|
||||
beginTest ("MIDI all notes off (legacy mode)");
|
||||
{
|
||||
UnitTestInstrument test;
|
||||
test.enableOmniMode();
|
||||
test.enableLegacyMode();
|
||||
test.noteOn (3, 60, MPEValue::from7BitInt (100));
|
||||
test.noteOn (4, 61, MPEValue::from7BitInt (100));
|
||||
test.noteOn (15, 62, MPEValue::from7BitInt (100));
|
||||
|
|
@ -1719,27 +1759,48 @@ public:
|
|||
expectNote (test.getMostRecentNote (3), 100, 33, 4444, 55, MPENote::keyDown);
|
||||
}
|
||||
|
||||
beginTest ("Omni mode");
|
||||
beginTest ("Legacy mode");
|
||||
{
|
||||
{
|
||||
// basic check
|
||||
MPEInstrument test;
|
||||
expect (! test.isOmniModeEnabled());
|
||||
expect (! test.isLegacyModeEnabled());
|
||||
|
||||
test.setZoneLayout (testLayout);
|
||||
expect (! test.isOmniModeEnabled());
|
||||
expect (! test.isLegacyModeEnabled());
|
||||
|
||||
test.enableOmniMode();
|
||||
expect (test.isOmniModeEnabled());
|
||||
test.enableLegacyMode();
|
||||
expect (test.isLegacyModeEnabled());
|
||||
|
||||
test.setZoneLayout (testLayout);
|
||||
expect (! test.isOmniModeEnabled());
|
||||
expect (! test.isLegacyModeEnabled());
|
||||
}
|
||||
{
|
||||
// constructor w/o default arguments
|
||||
MPEInstrument test;
|
||||
test.enableLegacyMode (0, Range<int> (1, 11));
|
||||
expectEquals (test.getLegacyModePitchbendRange(), 0);
|
||||
expect (test.getLegacyModeChannelRange() == Range<int> (1, 11));
|
||||
}
|
||||
{
|
||||
// getters and setters
|
||||
MPEInstrument test;
|
||||
test.enableLegacyMode();
|
||||
|
||||
expectEquals (test.getLegacyModePitchbendRange(), 2);
|
||||
expect (test.getLegacyModeChannelRange() == Range<int> (1, 17));
|
||||
|
||||
test.setLegacyModePitchbendRange (96);
|
||||
expectEquals (test.getLegacyModePitchbendRange(), 96);
|
||||
|
||||
test.setLegacyModeChannelRange (Range<int> (10, 12));
|
||||
expect (test.getLegacyModeChannelRange() == Range<int> (10, 12));
|
||||
}
|
||||
{
|
||||
// note on should trigger notes on all 16 channels
|
||||
|
||||
UnitTestInstrument test;
|
||||
test.enableOmniMode();
|
||||
test.enableLegacyMode();
|
||||
|
||||
test.noteOn (1, 60, MPEValue::from7BitInt (100));
|
||||
test.noteOn (2, 60, MPEValue::from7BitInt (100));
|
||||
|
|
@ -1758,7 +1819,7 @@ public:
|
|||
expectNote (test.getNote (15, 60), 100, 100, 8192, 77, MPENote::keyDown);
|
||||
expectNote (test.getNote (16, 60), 100, 100, 8192, 64, MPENote::keyDown);
|
||||
|
||||
// note off should work in omni mode
|
||||
// note off should work in legacy mode
|
||||
|
||||
test.noteOff (15, 60, MPEValue::from7BitInt (0));
|
||||
test.noteOff (1, 60, MPEValue::from7BitInt (0));
|
||||
|
|
@ -1767,10 +1828,31 @@ public:
|
|||
expectEquals (test.getNumPlayingNotes(), 0);
|
||||
}
|
||||
{
|
||||
// tracking mode in omni mode
|
||||
// legacy mode w/ custom channel range: note on should trigger notes only within range
|
||||
|
||||
UnitTestInstrument test;
|
||||
test.enableLegacyMode (2, Range<int> (3, 8)); // channels 3-7
|
||||
|
||||
test.noteOn (1, 60, MPEValue::from7BitInt (100));
|
||||
test.noteOn (2, 60, MPEValue::from7BitInt (100));
|
||||
test.noteOn (3, 60, MPEValue::from7BitInt (100)); // should trigger
|
||||
test.noteOn (4, 60, MPEValue::from7BitInt (100)); // should trigger
|
||||
test.noteOn (6, 60, MPEValue::from7BitInt (100)); // should trigger
|
||||
test.noteOn (7, 60, MPEValue::from7BitInt (100)); // should trigger
|
||||
test.noteOn (8, 60, MPEValue::from7BitInt (100));
|
||||
test.noteOn (16, 60, MPEValue::from7BitInt (100));
|
||||
|
||||
expectEquals (test.getNumPlayingNotes(), 4);
|
||||
expectNote (test.getNote (3, 60), 100, 100, 8192, 64, MPENote::keyDown);
|
||||
expectNote (test.getNote (4, 60), 100, 100, 8192, 64, MPENote::keyDown);
|
||||
expectNote (test.getNote (6, 60), 100, 100, 8192, 64, MPENote::keyDown);
|
||||
expectNote (test.getNote (7, 60), 100, 100, 8192, 64, MPENote::keyDown);
|
||||
}
|
||||
{
|
||||
// tracking mode in legacy mode
|
||||
{
|
||||
UnitTestInstrument test;
|
||||
test.enableOmniMode();
|
||||
test.enableLegacyMode();
|
||||
|
||||
test.setPitchbendTrackingMode (MPEInstrument::lastNotePlayedOnChannel);
|
||||
test.noteOn (1, 60, MPEValue::from7BitInt (100));
|
||||
|
|
@ -1783,7 +1865,7 @@ public:
|
|||
}
|
||||
{
|
||||
UnitTestInstrument test;
|
||||
test.enableOmniMode();
|
||||
test.enableLegacyMode();
|
||||
|
||||
test.setPitchbendTrackingMode (MPEInstrument::lowestNoteOnChannel);
|
||||
test.noteOn (1, 60, MPEValue::from7BitInt (100));
|
||||
|
|
@ -1796,7 +1878,7 @@ public:
|
|||
}
|
||||
{
|
||||
UnitTestInstrument test;
|
||||
test.enableOmniMode();
|
||||
test.enableLegacyMode();
|
||||
|
||||
test.setPitchbendTrackingMode (MPEInstrument::highestNoteOnChannel);
|
||||
test.noteOn (1, 60, MPEValue::from7BitInt (100));
|
||||
|
|
@ -1809,7 +1891,7 @@ public:
|
|||
}
|
||||
{
|
||||
UnitTestInstrument test;
|
||||
test.enableOmniMode();
|
||||
test.enableLegacyMode();
|
||||
|
||||
test.setPitchbendTrackingMode (MPEInstrument::allNotesOnChannel);
|
||||
test.noteOn (1, 60, MPEValue::from7BitInt (100));
|
||||
|
|
@ -1822,18 +1904,18 @@ public:
|
|||
}
|
||||
}
|
||||
{
|
||||
// custom pitchbend range in omni mode.
|
||||
// custom pitchbend range in legacy mode.
|
||||
UnitTestInstrument test;
|
||||
test.enableOmniMode (11);
|
||||
test.enableLegacyMode (11);
|
||||
|
||||
test.pitchbend (1, MPEValue::from14BitInt (4096));
|
||||
test.noteOn (1, 60, MPEValue::from7BitInt (100));
|
||||
expectDoubleWithinRelativeError (test.getMostRecentNote (1).totalPitchbendInSemitones, -5.5, 0.01);
|
||||
}
|
||||
{
|
||||
// sustain pedal should be per channel in omni mode.
|
||||
// sustain pedal should be per channel in legacy mode.
|
||||
UnitTestInstrument test;
|
||||
test.enableOmniMode();
|
||||
test.enableLegacyMode();
|
||||
|
||||
test.sustainPedal (1, true);
|
||||
test.noteOn (2, 61, MPEValue::from7BitInt (100));
|
||||
|
|
@ -1846,11 +1928,17 @@ public:
|
|||
|
||||
test.sustainPedal (1, false);
|
||||
expectEquals (test.getNumPlayingNotes(), 0);
|
||||
|
||||
test.noteOn (2, 61, MPEValue::from7BitInt (100));
|
||||
test.sustainPedal (1, true);
|
||||
test.noteOff (2, 61, MPEValue::from7BitInt (100));
|
||||
expectEquals (test.getNumPlayingNotes(), 0);
|
||||
|
||||
}
|
||||
{
|
||||
// sostenuto pedal should be per channel in omni mode.
|
||||
// sostenuto pedal should be per channel in legacy mode.
|
||||
UnitTestInstrument test;
|
||||
test.enableOmniMode();
|
||||
test.enableLegacyMode();
|
||||
|
||||
test.noteOn (1, 60, MPEValue::from7BitInt (100));
|
||||
test.sostenutoPedal (1, true);
|
||||
|
|
@ -1863,6 +1951,11 @@ public:
|
|||
|
||||
test.sostenutoPedal (1, false);
|
||||
expectEquals (test.getNumPlayingNotes(), 0);
|
||||
|
||||
test.noteOn (2, 61, MPEValue::from7BitInt (100));
|
||||
test.sostenutoPedal (1, true);
|
||||
test.noteOff (2, 61, MPEValue::from7BitInt (100));
|
||||
expectEquals (test.getNumPlayingNotes(), 0);
|
||||
}
|
||||
{
|
||||
// all notes released when switching layout
|
||||
|
|
@ -1871,7 +1964,7 @@ public:
|
|||
test.noteOn (3, 60, MPEValue::from7BitInt (100));
|
||||
expectEquals (test.getNumPlayingNotes(), 1);
|
||||
|
||||
test.enableOmniMode();
|
||||
test.enableLegacyMode();
|
||||
expectEquals (test.getNumPlayingNotes(), 0);
|
||||
test.noteOn (3, 60, MPEValue::from7BitInt (100));
|
||||
expectEquals (test.getNumPlayingNotes(), 1);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public:
|
|||
This will construct an MPE instrument with initially no MPE zones.
|
||||
|
||||
In order to process incoming MIDI, call setZoneLayout, define the layout
|
||||
via MIDI RPN messages, or set the instrument to omni mode.
|
||||
via MIDI RPN messages, or set the instrument to legacy mode.
|
||||
*/
|
||||
MPEInstrument() noexcept;
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ public:
|
|||
/** Returns the current zone layout of the instrument.
|
||||
This happens by value, to enforce thread-safety and class invariants.
|
||||
|
||||
Note: If the instrument is in Omni mode, the return value of this
|
||||
Note: If the instrument is in legacy mode, the return value of this
|
||||
method is unspecified.
|
||||
*/
|
||||
MPEZoneLayout getZoneLayout() const noexcept;
|
||||
|
|
@ -81,38 +81,23 @@ public:
|
|||
As a side effect, this will discard all currently playing notes,
|
||||
and call noteReleased for all of them.
|
||||
|
||||
This will also disable Omni Mode in case it was enabled previously.
|
||||
This will also disable legacy mode in case it was enabled previously.
|
||||
*/
|
||||
void setZoneLayout (MPEZoneLayout newLayout);
|
||||
|
||||
/** Returns true if the given MIDI channel (1-16) is a note channel in any
|
||||
of the MPEInstrument's MPE zones; false otherwise.
|
||||
When in legacy mode, this will return true if the given channel is
|
||||
contained in the current legacy mode channel range; false otherwise.
|
||||
*/
|
||||
bool isNoteChannel (int midiChannel) const noexcept;
|
||||
|
||||
/** Returns true if the given MIDI channel (1-16) is a master channel in any
|
||||
of the MPEInstrument's MPE zones; false otherwise.
|
||||
When in legacy mode, this will always return false.
|
||||
*/
|
||||
bool isMasterChannel (int midiChannel) const noexcept;
|
||||
|
||||
/** Sets the instrument to Omni Mode.
|
||||
As a side effect, this will discard all currently playing notes,
|
||||
and call noteReleased for all of them.
|
||||
|
||||
This special zone layout mode is for backwards compatibility with
|
||||
non-MPE MIDI devices. In this mode, the instrument will ignore the
|
||||
current zone layout. It will instead treat all 16 MIDI channels as note
|
||||
channels, with no master channel.
|
||||
|
||||
@param pitchbendRange The pitchbend range in semitones that should be
|
||||
used while the instrument is in Omni mode. Must
|
||||
be between 0 and 96, otherwise behaviour is undefined.
|
||||
*/
|
||||
void enableOmniMode (int pitchbendRange = 2);
|
||||
|
||||
/** Returns true if the instrument is in Omni mode, false otherwise. */
|
||||
bool isOmniModeEnabled() const noexcept;
|
||||
|
||||
//==========================================================================
|
||||
/** The MPE note tracking mode. In case there is more than one note playing
|
||||
simultaneously on the same MIDI channel, this determines which of these
|
||||
|
|
@ -300,6 +285,44 @@ public:
|
|||
/** Removes a listener. */
|
||||
void removeListener (Listener* const listenerToRemove) noexcept;
|
||||
|
||||
//==========================================================================
|
||||
/** Puts the instrument into legacy mode.
|
||||
As a side effect, this will discard all currently playing notes,
|
||||
and call noteReleased for all of them.
|
||||
|
||||
This special zone layout mode is for backwards compatibility with
|
||||
non-MPE MIDI devices. In this mode, the instrument will ignore the
|
||||
current MPE zone layout. It will instead take a range of MIDI channels
|
||||
(default: all channels 1-16) and treat them as note channels, with no
|
||||
master channel. MIDI channels outside of this range will be ignored.
|
||||
|
||||
@param pitchbendRange The 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.
|
||||
|
||||
@param channelRange The 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.
|
||||
*/
|
||||
void enableLegacyMode (int pitchbendRange = 2,
|
||||
Range<int> channelRange = Range<int> (1, 17));
|
||||
|
||||
/** Returns true if the instrument is in legacy mode, false otherwise. */
|
||||
bool isLegacyModeEnabled() const noexcept;
|
||||
|
||||
/** Returns the range of MIDI channels (1-16) to be used for notes when in legacy mode. */
|
||||
Range<int> getLegacyModeChannelRange() const noexcept;
|
||||
|
||||
/** Re-sets the range of MIDI channels (1-16) to be used for notes when in legacy mode. */
|
||||
void setLegacyModeChannelRange (Range<int> channelRange);
|
||||
|
||||
/** Returns the pitchbend range in semitones (0-96) to be used for notes when in legacy mode. */
|
||||
int getLegacyModePitchbendRange() const noexcept;
|
||||
|
||||
/** Re-sets the pitchbend range in semitones (0-96) to be used for notes when in legacy mode. */
|
||||
void setLegacyModePitchbendRange (int pitchbendRange);
|
||||
|
||||
protected:
|
||||
//==========================================================================
|
||||
/** This method defines what initial pitchbend value should be used for newly
|
||||
|
|
@ -341,9 +364,10 @@ private:
|
|||
uint8 lastTimbreLowerBitReceivedOnChannel[16];
|
||||
bool isNoteChannelSustained[16];
|
||||
|
||||
struct OmniMode
|
||||
struct LegacyMode
|
||||
{
|
||||
bool isEnabled;
|
||||
Range<int> channelRange;
|
||||
int pitchbendRange;
|
||||
};
|
||||
|
||||
|
|
@ -356,7 +380,7 @@ private:
|
|||
MPEValue& getValue (MPENote& note) noexcept { return note.*(value); }
|
||||
};
|
||||
|
||||
OmniMode omniMode;
|
||||
LegacyMode legacyMode;
|
||||
MPEDimension pitchbendDimension, pressureDimension, timbreDimension;
|
||||
|
||||
void updateDimension (int midiChannel, MPEDimension&, MPEValue);
|
||||
|
|
|
|||
|
|
@ -50,14 +50,35 @@ void MPESynthesiserBase::setZoneLayout (MPEZoneLayout newLayout)
|
|||
instrument->setZoneLayout (newLayout);
|
||||
}
|
||||
|
||||
void MPESynthesiserBase::enableOmniMode (int pitchbendRange)
|
||||
//==============================================================================
|
||||
void MPESynthesiserBase::enableLegacyMode (int pitchbendRange, Range<int> channelRange)
|
||||
{
|
||||
instrument->enableOmniMode (pitchbendRange);
|
||||
instrument->enableLegacyMode (pitchbendRange, channelRange);
|
||||
}
|
||||
|
||||
bool MPESynthesiserBase::isOmniModeEnabled() const noexcept
|
||||
bool MPESynthesiserBase::isLegacyModeEnabled() const noexcept
|
||||
{
|
||||
return instrument->isOmniModeEnabled();
|
||||
return instrument->isLegacyModeEnabled();
|
||||
}
|
||||
|
||||
Range<int> MPESynthesiserBase::getLegacyModeChannelRange() const noexcept
|
||||
{
|
||||
return instrument->getLegacyModeChannelRange();
|
||||
}
|
||||
|
||||
void MPESynthesiserBase::setLegacyModeChannelRange (Range<int> channelRange)
|
||||
{
|
||||
instrument->setLegacyModeChannelRange (channelRange);
|
||||
}
|
||||
|
||||
int MPESynthesiserBase::getLegacyModePitchbendRange() const noexcept
|
||||
{
|
||||
return instrument->getLegacyModePitchbendRange();
|
||||
}
|
||||
|
||||
void MPESynthesiserBase::setLegacyModePitchbendRange (int pitchbendRange)
|
||||
{
|
||||
instrument->setLegacyModePitchbendRange (pitchbendRange);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -69,16 +69,10 @@ public:
|
|||
|
||||
/** 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 Omni mode (if previously enabled).
|
||||
call noteReleased for all of them, and disable legacy mode (if previously enabled).
|
||||
*/
|
||||
void setZoneLayout (MPEZoneLayout newLayout);
|
||||
|
||||
/** Sets the synthesiser to Omni mode. */
|
||||
void enableOmniMode (int pitchbendRange = 2);
|
||||
|
||||
/** Returns true if the synthesiser is currently in Omni mode. */
|
||||
bool isOmniModeEnabled() const noexcept;
|
||||
|
||||
//==========================================================================
|
||||
/** Tells the synthesiser what the sample rate is for the audio it's being
|
||||
used to render.
|
||||
|
|
@ -136,6 +130,35 @@ public:
|
|||
*/
|
||||
void setMinimumRenderingSubdivisionSize (int numSamples) noexcept;
|
||||
|
||||
//==========================================================================
|
||||
/** Puts the synthesiser into legacy mode.
|
||||
|
||||
@param pitchbendRange The 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.
|
||||
@param channelRange The 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.
|
||||
*/
|
||||
void enableLegacyMode (int pitchbendRange = 2,
|
||||
Range<int> channelRange = Range<int> (1, 17));
|
||||
|
||||
/** Returns true if the instrument is in legacy mode, false otherwise. */
|
||||
bool isLegacyModeEnabled() const noexcept;
|
||||
|
||||
/** Returns the range of MIDI channels (1-16) to be used for notes when in legacy mode. */
|
||||
Range<int> getLegacyModeChannelRange() const noexcept;
|
||||
|
||||
/** Re-sets the range of MIDI channels (1-16) to be used for notes when in legacy mode. */
|
||||
void setLegacyModeChannelRange (Range<int> channelRange);
|
||||
|
||||
/** Returns the pitchbend range in semitones (0-96) to be used for notes when in legacy mode. */
|
||||
int getLegacyModePitchbendRange() const noexcept;
|
||||
|
||||
/** Re-sets the pitchbend range in semitones (0-96) to be used for notes when in legacy mode. */
|
||||
void setLegacyModePitchbendRange (int pitchbendRange);
|
||||
|
||||
protected:
|
||||
//==========================================================================
|
||||
/** Implement this method to render your audio inside.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue