1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-28 02:30:05 +00:00

VST3: Fix issue where aftertouch messages from the host were incorrectly converted to LegacyMIDICCOut messages

This commit is contained in:
reuk 2020-09-23 17:50:26 +01:00
parent a32b3e7f23
commit 90664b42df
4 changed files with 90 additions and 22 deletions

View file

@ -401,7 +401,7 @@ public:
/** Returns true if the message is an aftertouch event.
For aftertouch events, use the getNoteNumber() method to find out the key
that it applies to, and getAftertouchValue() to find out the amount. Use
that it applies to, and getAfterTouchValue() to find out the amount. Use
getChannel() to find out the channel.
@see getAftertouchValue, getNoteNumber

View file

@ -2657,7 +2657,7 @@ public:
#if JucePlugin_ProducesMidiOutput
if (isMidiOutputBusEnabled && data.outputEvents != nullptr)
MidiEventList::toEventList (*data.outputEvents, midiBuffer);
MidiEventList::pluginToHostEventList (*data.outputEvents, midiBuffer);
#endif
return kResultTrue;

View file

@ -401,8 +401,8 @@ private:
class MidiEventList : public Steinberg::Vst::IEventList
{
public:
MidiEventList() {}
virtual ~MidiEventList() {}
MidiEventList() = default;
virtual ~MidiEventList() = default;
JUCE_DECLARE_VST3_COM_REF_METHODS
JUCE_DECLARE_VST3_COM_QUERY_METHODS
@ -455,9 +455,43 @@ public:
}
}
static void hostToPluginEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer,
Steinberg::Vst::IParameterChanges* parameterChanges,
Steinberg::Vst::IMidiMapping* midiMapping)
{
toEventList (result,
midiBuffer,
parameterChanges,
midiMapping,
EventConversionKind::hostToPlugin);
}
static void pluginToHostEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer)
{
toEventList (result,
midiBuffer,
nullptr,
nullptr,
EventConversionKind::pluginToHost);
}
private:
enum class EventConversionKind
{
// Hosted plugins don't expect to receive LegacyMIDICCEvents messages from the host,
// so if we're converting midi from the host to an eventlist, this mode will avoid
// converting to Legacy events where possible.
hostToPlugin,
// If plugins generate MIDI internally, then where possible we should preserve
// these messages as LegacyMIDICCOut events.
pluginToHost
};
static void toEventList (Steinberg::Vst::IEventList& result, MidiBuffer& midiBuffer,
Steinberg::Vst::IParameterChanges* parameterChanges = nullptr,
Steinberg::Vst::IMidiMapping* midiMapping = nullptr)
Steinberg::Vst::IParameterChanges* parameterChanges,
Steinberg::Vst::IMidiMapping* midiMapping,
EventConversionKind kind)
{
enum { maxNumEvents = 2048 }; // Steinberg's Host Checker states that no more than 2048 events are allowed at once
int numEvents = 0;
@ -491,7 +525,7 @@ public:
}
}
auto maybeEvent = createVstEvent (msg, metadata.data);
auto maybeEvent = createVstEvent (msg, metadata.data, kind);
if (! maybeEvent.isValid)
continue;
@ -503,7 +537,6 @@ public:
}
}
private:
Array<Steinberg::Vst::Event, CriticalSection> events;
Atomic<int> refCount;
@ -562,6 +595,17 @@ private:
return e;
}
static Steinberg::Vst::Event createPolyPressureEvent (const MidiMessage& msg)
{
Steinberg::Vst::Event e{};
e.type = Steinberg::Vst::Event::kPolyPressureEvent;
e.polyPressure.channel = createSafeChannel (msg.getChannel());
e.polyPressure.pitch = createSafeNote (msg.getNoteNumber());
e.polyPressure.pressure = normaliseMidiValue (msg.getAfterTouchValue());
e.polyPressure.noteId = -1;
return e;
}
static Steinberg::Vst::Event createChannelPressureEvent (const MidiMessage& msg) noexcept
{
return createLegacyMIDIEvent (msg.getChannel(),
@ -617,7 +661,8 @@ private:
};
static BasicOptional<Steinberg::Vst::Event> createVstEvent (const MidiMessage& msg,
const uint8* midiEventData) noexcept
const uint8* midiEventData,
EventConversionKind kind) noexcept
{
if (msg.isNoteOn())
return createNoteOnEvent (msg);
@ -643,11 +688,20 @@ private:
if (msg.isQuarterFrame())
return createCtrlQuarterFrameEvent (msg);
// VST3 gives us two ways to communicate poly pressure changes.
// There's a dedicated PolyPressureEvent, and also a LegacyMIDICCOutEvent with a
// `controlNumber` of `kCtrlPolyPressure`. We're sending the LegacyMIDI version.
if (msg.isAftertouch())
return createCtrlPolyPressureEvent (msg);
{
switch (kind)
{
case EventConversionKind::hostToPlugin:
return createPolyPressureEvent (msg);
case EventConversionKind::pluginToHost:
return createCtrlPolyPressureEvent (msg);
}
jassertfalse;
return {};
}
return {};
}
@ -738,13 +792,26 @@ private:
static bool toVst3ControlEvent (const MidiMessage& msg, Vst3MidiControlEvent& result)
{
if (msg.isController())
{
result = { (Steinberg::Vst::CtrlNumber) msg.getControllerNumber(), msg.getControllerValue() / 127.0};
return true;
}
if (msg.isPitchWheel())
{
result = { Steinberg::Vst::kPitchBend, msg.getPitchWheelValue() / 16383.0};
return true;
}
if (msg.isChannelPressure())
{
result = { Steinberg::Vst::kAfterTouch, msg.getChannelPressureValue() / 127.0};
return true;
}
result.controllerNumber = -1;
if (msg.isController()) result = { (Steinberg::Vst::CtrlNumber) msg.getControllerNumber(), msg.getControllerValue() / 127.0};
else if (msg.isPitchWheel()) result = { Steinberg::Vst::kPitchBend, msg.getPitchWheelValue() / 16383.0};
else if (msg.isAftertouch()) result = { Steinberg::Vst::kAfterTouch, msg.getAfterTouchValue() / 127.0};
return (result.controllerNumber != -1);
return false;
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiEventList)

View file

@ -2970,9 +2970,10 @@ private:
midiOutputs->clear();
if (acceptsMidi())
MidiEventList::toEventList (*midiInputs, midiBuffer,
destination.inputParameterChanges,
midiMapping);
MidiEventList::hostToPluginEventList (*midiInputs,
midiBuffer,
destination.inputParameterChanges,
midiMapping);
destination.inputEvents = midiInputs;
destination.outputEvents = midiOutputs;