1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Added some MIDI controller mapping functionality to VST3, and fixed a couple of VST3 bugs.

This commit is contained in:
jules 2015-08-24 10:14:17 +01:00
parent a6245991e4
commit 5ee02150e1
2 changed files with 86 additions and 10 deletions

View file

@ -271,13 +271,32 @@ public:
}
//==============================================================================
tresult PLUGIN_API getMidiControllerAssignment (Steinberg::int32, Steinberg::int16,
Vst::CtrlNumber,
Vst::ParamID& id) override
tresult PLUGIN_API getMidiControllerAssignment (Steinberg::int32 /*busIndex*/, Steinberg::int16 channel,
Vst::CtrlNumber midiControllerNumber, Vst::ParamID& resultID) override
{
//TODO
id = 0;
return kNotImplemented;
resultID = midiControllerToParameter[channel][midiControllerNumber];
return kResultTrue; // Returning false makes some hosts stop asking for further MIDI Controller Assignments
}
// Converts an incoming parameter index to a MIDI controller:
bool getMidiControllerForParameter (int index, int& channel, int& ctrlNumber)
{
const int mappedIndex = index - parameterToMidiControllerOffset;
if (isPositiveAndBelow (mappedIndex, numElementsInArray (parameterToMidiController)))
{
const MidiController& mc = parameterToMidiController[mappedIndex];
if (mc.channel != -1 && mc.ctrlNumber != -1)
{
channel = jlimit (1, 16, mc.channel + 1);
ctrlNumber = mc.ctrlNumber;
return true;
}
}
return false;
}
//==============================================================================
@ -327,6 +346,18 @@ private:
ComSmartPtr<JuceAudioProcessor> audioProcessor;
ScopedJuceInitialiser_GUI libraryInitialiser;
struct MidiController
{
MidiController() noexcept : channel (-1), ctrlNumber (-1) {}
int channel, ctrlNumber;
};
enum { numMIDIChannels = 16 };
int parameterToMidiControllerOffset;
MidiController parameterToMidiController[numMIDIChannels * Vst::kCountCtrlNumber];
int midiControllerToParameter[numMIDIChannels][Vst::kCountCtrlNumber];
//==============================================================================
void setupParameters()
{
@ -338,10 +369,30 @@ private:
for (int i = 0; i < pluginInstance->getNumParameters(); ++i)
parameters.addParameter (new Param (*pluginInstance, i));
initialiseMidiControllerMappings (pluginInstance->getNumParameters());
audioProcessorChanged (pluginInstance);
}
}
void initialiseMidiControllerMappings (const int numParameters)
{
parameterToMidiControllerOffset = numParameters;
for (int c = 0, p = 0; c < numMIDIChannels; ++c)
{
for (int i = 0; i < Vst::kCountCtrlNumber; ++i, ++p)
{
midiControllerToParameter[c][i] = p + parameterToMidiControllerOffset;
parameterToMidiController[p].channel = c;
parameterToMidiController[p].ctrlNumber = i;
parameters.addParameter (new Vst::Parameter (toString ("MIDI CC " + String (c) + "|" + String (i)),
p + parameterToMidiControllerOffset, 0, 0, 0,
Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId));
}
}
}
void sendIntMessage (const char* idTag, const Steinberg::int64 value)
{
jassert (hostContext != nullptr);
@ -1087,7 +1138,7 @@ public:
bool getCurrentPosition (CurrentPositionInfo& info) override
{
info.timeInSamples = jmax ((juce::int64) 0, processContext.projectTimeSamples);
info.timeInSeconds = processContext.projectTimeMusic;
info.timeInSeconds = processContext.systemTime / 1000000000.0;
info.bpm = jmax (1.0, processContext.tempo);
info.timeSigNumerator = jmax (1, (int) processContext.timeSigNumerator);
info.timeSigDenominator = jmax (1, (int) processContext.timeSigDenominator);
@ -1250,13 +1301,36 @@ public:
if (paramQueue->getPoint (numPoints - 1, offsetSamples, value) == kResultTrue)
{
const int id = (int) paramQueue->getParameterId();
jassert (isPositiveAndBelow (id, pluginInstance->getNumParameters()));
pluginInstance->setParameter (id, (float) value);
if (isPositiveAndBelow (id, pluginInstance->getNumParameters()))
pluginInstance->setParameter (id, (float) value);
else
addParameterChangeToMidiBuffer (offsetSamples, id, value);
}
}
}
}
void addParameterChangeToMidiBuffer (const Steinberg::int32 offsetSamples, const int id, const double value)
{
// If the parameter is mapped to a MIDI CC message then insert it into the midiBuffer.
int channel, ctrlNumber;
if (juceVST3EditController->getMidiControllerForParameter (id, channel, ctrlNumber))
{
if (ctrlNumber == Vst::kAfterTouch)
midiBuffer.addEvent (MidiMessage::channelPressureChange (channel,
jlimit (0, 127, (int) (value * 128.0))), offsetSamples);
else if (ctrlNumber == Vst::kPitchBend)
midiBuffer.addEvent (MidiMessage::pitchWheel (channel,
jlimit (0, 0x3fff, (int) (value * 0x4000))), offsetSamples);
else
midiBuffer.addEvent (MidiMessage::controllerEvent (channel,
jlimit (0, 127, ctrlNumber),
jlimit (0, 127, (int) (value * 128.0))), offsetSamples);
}
}
tresult PLUGIN_API process (Vst::ProcessData& data) override
{
if (pluginInstance == nullptr)
@ -1385,7 +1459,7 @@ private:
void addEventBusTo (Vst::BusList& busList, const juce::String& name)
{
addBusTo (busList, new Vst::EventBus (toString (name), 16, Vst::kMain, Vst::BusInfo::kDefaultActive));
addBusTo (busList, new Vst::EventBus (toString (name), Vst::kMain, Vst::BusInfo::kDefaultActive, 16));
}
Vst::BusList* getBusListFor (Vst::MediaType type, Vst::BusDirection dir)

View file

@ -75,6 +75,7 @@
#include <pluginterfaces/vst/ivstprocesscontext.h>
#include <pluginterfaces/vst/vsttypes.h>
#include <pluginterfaces/vst/ivstunits.h>
#include <pluginterfaces/vst/ivstmidicontrollers.h>
#include <public.sdk/source/common/memorystream.h>
#else
#include <base/source/baseiids.cpp>
@ -92,6 +93,7 @@
#include <pluginterfaces/base/ipluginbase.h>
#include <pluginterfaces/base/ustring.cpp>
#include <pluginterfaces/gui/iplugview.h>
#include <pluginterfaces/vst/ivstmidicontrollers.h>
#include <public.sdk/source/common/memorystream.cpp>
#include <public.sdk/source/common/pluginview.cpp>
#include <public.sdk/source/vst/vsteditcontroller.cpp>