git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
386
deps/juce/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp
vendored
Normal file
386
deps/juce/modules/juce_audio_basics/mpe/juce_MPEZoneLayout.cpp
vendored
Normal file
@ -0,0 +1,386 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
MPEZoneLayout::MPEZoneLayout() noexcept {}
|
||||
|
||||
MPEZoneLayout::MPEZoneLayout (const MPEZoneLayout& other)
|
||||
: lowerZone (other.lowerZone),
|
||||
upperZone (other.upperZone)
|
||||
{
|
||||
}
|
||||
|
||||
MPEZoneLayout& MPEZoneLayout::operator= (const MPEZoneLayout& other)
|
||||
{
|
||||
lowerZone = other.lowerZone;
|
||||
upperZone = other.upperZone;
|
||||
|
||||
sendLayoutChangeMessage();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void MPEZoneLayout::sendLayoutChangeMessage()
|
||||
{
|
||||
listeners.call ([this] (Listener& l) { l.zoneLayoutChanged (*this); });
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MPEZoneLayout::setZone (bool isLower, int numMemberChannels, int perNotePitchbendRange, int masterPitchbendRange) noexcept
|
||||
{
|
||||
checkAndLimitZoneParameters (0, 15, numMemberChannels);
|
||||
checkAndLimitZoneParameters (0, 96, perNotePitchbendRange);
|
||||
checkAndLimitZoneParameters (0, 96, masterPitchbendRange);
|
||||
|
||||
if (isLower)
|
||||
lowerZone = { true, numMemberChannels, perNotePitchbendRange, masterPitchbendRange };
|
||||
else
|
||||
upperZone = { false, numMemberChannels, perNotePitchbendRange, masterPitchbendRange };
|
||||
|
||||
if (numMemberChannels > 0)
|
||||
{
|
||||
auto totalChannels = lowerZone.numMemberChannels + upperZone.numMemberChannels;
|
||||
|
||||
if (totalChannels >= 15)
|
||||
{
|
||||
if (isLower)
|
||||
upperZone.numMemberChannels = 14 - numMemberChannels;
|
||||
else
|
||||
lowerZone.numMemberChannels = 14 - numMemberChannels;
|
||||
}
|
||||
}
|
||||
|
||||
sendLayoutChangeMessage();
|
||||
}
|
||||
|
||||
void MPEZoneLayout::setLowerZone (int numMemberChannels, int perNotePitchbendRange, int masterPitchbendRange) noexcept
|
||||
{
|
||||
setZone (true, numMemberChannels, perNotePitchbendRange, masterPitchbendRange);
|
||||
}
|
||||
|
||||
void MPEZoneLayout::setUpperZone (int numMemberChannels, int perNotePitchbendRange, int masterPitchbendRange) noexcept
|
||||
{
|
||||
setZone (false, numMemberChannels, perNotePitchbendRange, masterPitchbendRange);
|
||||
}
|
||||
|
||||
void MPEZoneLayout::clearAllZones()
|
||||
{
|
||||
lowerZone = { true, 0 };
|
||||
upperZone = { false, 0 };
|
||||
|
||||
sendLayoutChangeMessage();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MPEZoneLayout::processNextMidiEvent (const MidiMessage& message)
|
||||
{
|
||||
if (! message.isController())
|
||||
return;
|
||||
|
||||
MidiRPNMessage rpn;
|
||||
|
||||
if (rpnDetector.parseControllerMessage (message.getChannel(),
|
||||
message.getControllerNumber(),
|
||||
message.getControllerValue(),
|
||||
rpn))
|
||||
{
|
||||
processRpnMessage (rpn);
|
||||
}
|
||||
}
|
||||
|
||||
void MPEZoneLayout::processRpnMessage (MidiRPNMessage rpn)
|
||||
{
|
||||
if (rpn.parameterNumber == MPEMessages::zoneLayoutMessagesRpnNumber)
|
||||
processZoneLayoutRpnMessage (rpn);
|
||||
else if (rpn.parameterNumber == 0)
|
||||
processPitchbendRangeRpnMessage (rpn);
|
||||
}
|
||||
|
||||
void MPEZoneLayout::processZoneLayoutRpnMessage (MidiRPNMessage rpn)
|
||||
{
|
||||
if (rpn.value < 16)
|
||||
{
|
||||
if (rpn.channel == 1)
|
||||
setLowerZone (rpn.value);
|
||||
else if (rpn.channel == 16)
|
||||
setUpperZone (rpn.value);
|
||||
}
|
||||
}
|
||||
|
||||
void MPEZoneLayout::updateMasterPitchbend (Zone& zone, int value)
|
||||
{
|
||||
if (zone.masterPitchbendRange != value)
|
||||
{
|
||||
checkAndLimitZoneParameters (0, 96, zone.masterPitchbendRange);
|
||||
zone.masterPitchbendRange = value;
|
||||
sendLayoutChangeMessage();
|
||||
}
|
||||
}
|
||||
|
||||
void MPEZoneLayout::updatePerNotePitchbendRange (Zone& zone, int value)
|
||||
{
|
||||
if (zone.perNotePitchbendRange != value)
|
||||
{
|
||||
checkAndLimitZoneParameters (0, 96, zone.perNotePitchbendRange);
|
||||
zone.perNotePitchbendRange = value;
|
||||
sendLayoutChangeMessage();
|
||||
}
|
||||
}
|
||||
|
||||
void MPEZoneLayout::processPitchbendRangeRpnMessage (MidiRPNMessage rpn)
|
||||
{
|
||||
if (rpn.channel == 1)
|
||||
{
|
||||
updateMasterPitchbend (lowerZone, rpn.value);
|
||||
}
|
||||
else if (rpn.channel == 16)
|
||||
{
|
||||
updateMasterPitchbend (upperZone, rpn.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lowerZone.isUsingChannelAsMemberChannel (rpn.channel))
|
||||
updatePerNotePitchbendRange (lowerZone, rpn.value);
|
||||
else if (upperZone.isUsingChannelAsMemberChannel (rpn.channel))
|
||||
updatePerNotePitchbendRange (upperZone, rpn.value);
|
||||
}
|
||||
}
|
||||
|
||||
void MPEZoneLayout::processNextMidiBuffer (const MidiBuffer& buffer)
|
||||
{
|
||||
for (const auto metadata : buffer)
|
||||
processNextMidiEvent (metadata.getMessage());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MPEZoneLayout::addListener (Listener* const listenerToAdd) noexcept
|
||||
{
|
||||
listeners.add (listenerToAdd);
|
||||
}
|
||||
|
||||
void MPEZoneLayout::removeListener (Listener* const listenerToRemove) noexcept
|
||||
{
|
||||
listeners.remove (listenerToRemove);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void MPEZoneLayout::checkAndLimitZoneParameters (int minValue, int maxValue,
|
||||
int& valueToCheckAndLimit) noexcept
|
||||
{
|
||||
if (valueToCheckAndLimit < minValue || valueToCheckAndLimit > maxValue)
|
||||
{
|
||||
// if you hit this, one of the parameters you supplied for this zone
|
||||
// was not within the allowed range!
|
||||
// we fit this back into the allowed range here to maintain a valid
|
||||
// state for the zone, but probably the resulting zone is not what you
|
||||
// wanted it to be!
|
||||
jassertfalse;
|
||||
|
||||
valueToCheckAndLimit = jlimit (minValue, maxValue, valueToCheckAndLimit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
class MPEZoneLayoutTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
MPEZoneLayoutTests()
|
||||
: UnitTest ("MPEZoneLayout class", UnitTestCategories::midi)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("initialisation");
|
||||
{
|
||||
MPEZoneLayout layout;
|
||||
expect (! layout.getLowerZone().isActive());
|
||||
expect (! layout.getUpperZone().isActive());
|
||||
}
|
||||
|
||||
beginTest ("adding zones");
|
||||
{
|
||||
MPEZoneLayout layout;
|
||||
|
||||
layout.setLowerZone (7);
|
||||
|
||||
expect (layout.getLowerZone().isActive());
|
||||
expect (! layout.getUpperZone().isActive());
|
||||
expectEquals (layout.getLowerZone().getMasterChannel(), 1);
|
||||
expectEquals (layout.getLowerZone().numMemberChannels, 7);
|
||||
|
||||
layout.setUpperZone (7);
|
||||
|
||||
expect (layout.getLowerZone().isActive());
|
||||
expect (layout.getUpperZone().isActive());
|
||||
expectEquals (layout.getLowerZone().getMasterChannel(), 1);
|
||||
expectEquals (layout.getLowerZone().numMemberChannels, 7);
|
||||
expectEquals (layout.getUpperZone().getMasterChannel(), 16);
|
||||
expectEquals (layout.getUpperZone().numMemberChannels, 7);
|
||||
|
||||
layout.setLowerZone (3);
|
||||
|
||||
expect (layout.getLowerZone().isActive());
|
||||
expect (layout.getUpperZone().isActive());
|
||||
expectEquals (layout.getLowerZone().getMasterChannel(), 1);
|
||||
expectEquals (layout.getLowerZone().numMemberChannels, 3);
|
||||
expectEquals (layout.getUpperZone().getMasterChannel(), 16);
|
||||
expectEquals (layout.getUpperZone().numMemberChannels, 7);
|
||||
|
||||
layout.setUpperZone (3);
|
||||
|
||||
expect (layout.getLowerZone().isActive());
|
||||
expect (layout.getUpperZone().isActive());
|
||||
expectEquals (layout.getLowerZone().getMasterChannel(), 1);
|
||||
expectEquals (layout.getLowerZone().numMemberChannels, 3);
|
||||
expectEquals (layout.getUpperZone().getMasterChannel(), 16);
|
||||
expectEquals (layout.getUpperZone().numMemberChannels, 3);
|
||||
|
||||
layout.setLowerZone (15);
|
||||
|
||||
expect (layout.getLowerZone().isActive());
|
||||
expect (! layout.getUpperZone().isActive());
|
||||
expectEquals (layout.getLowerZone().getMasterChannel(), 1);
|
||||
expectEquals (layout.getLowerZone().numMemberChannels, 15);
|
||||
}
|
||||
|
||||
beginTest ("clear all zones");
|
||||
{
|
||||
MPEZoneLayout layout;
|
||||
|
||||
expect (! layout.getLowerZone().isActive());
|
||||
expect (! layout.getUpperZone().isActive());
|
||||
|
||||
layout.setLowerZone (7);
|
||||
layout.setUpperZone (2);
|
||||
|
||||
expect (layout.getLowerZone().isActive());
|
||||
expect (layout.getUpperZone().isActive());
|
||||
|
||||
layout.clearAllZones();
|
||||
|
||||
expect (! layout.getLowerZone().isActive());
|
||||
expect (! layout.getUpperZone().isActive());
|
||||
}
|
||||
|
||||
beginTest ("process MIDI buffers");
|
||||
{
|
||||
MPEZoneLayout layout;
|
||||
MidiBuffer buffer;
|
||||
|
||||
buffer = MPEMessages::setLowerZone (7);
|
||||
layout.processNextMidiBuffer (buffer);
|
||||
|
||||
expect (layout.getLowerZone().isActive());
|
||||
expect (! layout.getUpperZone().isActive());
|
||||
expectEquals (layout.getLowerZone().getMasterChannel(), 1);
|
||||
expectEquals (layout.getLowerZone().numMemberChannels, 7);
|
||||
|
||||
buffer = MPEMessages::setUpperZone (7);
|
||||
layout.processNextMidiBuffer (buffer);
|
||||
|
||||
expect (layout.getLowerZone().isActive());
|
||||
expect (layout.getUpperZone().isActive());
|
||||
expectEquals (layout.getLowerZone().getMasterChannel(), 1);
|
||||
expectEquals (layout.getLowerZone().numMemberChannels, 7);
|
||||
expectEquals (layout.getUpperZone().getMasterChannel(), 16);
|
||||
expectEquals (layout.getUpperZone().numMemberChannels, 7);
|
||||
|
||||
{
|
||||
buffer = MPEMessages::setLowerZone (10);
|
||||
layout.processNextMidiBuffer (buffer);
|
||||
|
||||
expect (layout.getLowerZone().isActive());
|
||||
expect (layout.getUpperZone().isActive());
|
||||
expectEquals (layout.getLowerZone().getMasterChannel(), 1);
|
||||
expectEquals (layout.getLowerZone().numMemberChannels, 10);
|
||||
expectEquals (layout.getUpperZone().getMasterChannel(), 16);
|
||||
expectEquals (layout.getUpperZone().numMemberChannels, 4);
|
||||
|
||||
|
||||
buffer = MPEMessages::setLowerZone (10, 33, 44);
|
||||
layout.processNextMidiBuffer (buffer);
|
||||
|
||||
expectEquals (layout.getLowerZone().numMemberChannels, 10);
|
||||
expectEquals (layout.getLowerZone().perNotePitchbendRange, 33);
|
||||
expectEquals (layout.getLowerZone().masterPitchbendRange, 44);
|
||||
}
|
||||
|
||||
{
|
||||
buffer = MPEMessages::setUpperZone (10);
|
||||
layout.processNextMidiBuffer (buffer);
|
||||
|
||||
expect (layout.getLowerZone().isActive());
|
||||
expect (layout.getUpperZone().isActive());
|
||||
expectEquals (layout.getLowerZone().getMasterChannel(), 1);
|
||||
expectEquals (layout.getLowerZone().numMemberChannels, 4);
|
||||
expectEquals (layout.getUpperZone().getMasterChannel(), 16);
|
||||
expectEquals (layout.getUpperZone().numMemberChannels, 10);
|
||||
|
||||
buffer = MPEMessages::setUpperZone (10, 33, 44);
|
||||
|
||||
layout.processNextMidiBuffer (buffer);
|
||||
|
||||
expectEquals (layout.getUpperZone().numMemberChannels, 10);
|
||||
expectEquals (layout.getUpperZone().perNotePitchbendRange, 33);
|
||||
expectEquals (layout.getUpperZone().masterPitchbendRange, 44);
|
||||
}
|
||||
|
||||
buffer = MPEMessages::clearAllZones();
|
||||
layout.processNextMidiBuffer (buffer);
|
||||
|
||||
expect (! layout.getLowerZone().isActive());
|
||||
expect (! layout.getUpperZone().isActive());
|
||||
}
|
||||
|
||||
beginTest ("process individual MIDI messages");
|
||||
{
|
||||
MPEZoneLayout layout;
|
||||
|
||||
layout.processNextMidiEvent ({ 0x80, 0x59, 0xd0 }); // unrelated note-off msg
|
||||
layout.processNextMidiEvent ({ 0xb0, 0x64, 0x06 }); // RPN part 1
|
||||
layout.processNextMidiEvent ({ 0xb0, 0x65, 0x00 }); // RPN part 2
|
||||
layout.processNextMidiEvent ({ 0xb8, 0x0b, 0x66 }); // unrelated CC msg
|
||||
layout.processNextMidiEvent ({ 0xb0, 0x06, 0x03 }); // RPN part 3
|
||||
layout.processNextMidiEvent ({ 0x90, 0x60, 0x00 }); // unrelated note-on msg
|
||||
|
||||
expect (layout.getLowerZone().isActive());
|
||||
expect (! layout.getUpperZone().isActive());
|
||||
expectEquals (layout.getLowerZone().getMasterChannel(), 1);
|
||||
expectEquals (layout.getLowerZone().numMemberChannels, 3);
|
||||
expectEquals (layout.getLowerZone().perNotePitchbendRange, 48);
|
||||
expectEquals (layout.getLowerZone().masterPitchbendRange, 2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static MPEZoneLayoutTests MPEZoneLayoutUnitTests;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
Reference in New Issue
Block a user