Trigger MIDI bindings.
This commit is contained in:
+9
-3
@@ -305,6 +305,7 @@ void Lv2Effect::PreparePortIndices()
|
||||
size_t nPorts = info->ports().size();
|
||||
isInputControlPort.resize(nPorts);
|
||||
this->defaultInputControlValues.resize(nPorts);
|
||||
this->isInputTriggerControlPort.resize(nPorts);
|
||||
|
||||
for (int i = 0; i < info->ports().size(); ++i)
|
||||
{
|
||||
@@ -343,11 +344,16 @@ void Lv2Effect::PreparePortIndices()
|
||||
}
|
||||
else if (port->is_control_port())
|
||||
{
|
||||
controlIndex[port->symbol()] = port->index();
|
||||
controlIndex[port->symbol()] = portIndex;
|
||||
if (port->is_input())
|
||||
{
|
||||
this->isInputControlPort[i] = true;
|
||||
this->defaultInputControlValues[i] = port->default_value();
|
||||
this->isInputControlPort[portIndex] = true;
|
||||
this->defaultInputControlValues[portIndex] = port->default_value();
|
||||
if (port->trigger_property())
|
||||
{
|
||||
this->isInputTriggerControlPort[portIndex] = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ namespace pipedal
|
||||
uint64_t maxInputControlPort = 0;
|
||||
std::vector<bool> isInputControlPort;
|
||||
std::vector<float> defaultInputControlValues;
|
||||
std::vector<bool> isInputTriggerControlPort;;
|
||||
|
||||
virtual std::string GetUri() const { return info->uri(); }
|
||||
|
||||
|
||||
+124
-27
@@ -169,6 +169,33 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
|
||||
{
|
||||
pLv2Effect->Run(frames, this->ringBufferWriter);
|
||||
});
|
||||
|
||||
// Reset any trigger controls to default state after processing
|
||||
if (pLv2Effect->IsLv2Effect())
|
||||
{
|
||||
Lv2Effect*lv2Effect = (Lv2Effect*)pLv2Effect;
|
||||
auto pluginInfo = pHost->GetPluginInfo(item.uri());
|
||||
if (pluginInfo) {
|
||||
for (auto control: pluginInfo->ports())
|
||||
{
|
||||
if (control->trigger_property() && control->is_input() && control->is_control_port())
|
||||
{
|
||||
int controlIndex = lv2Effect->GetControlIndex(control->symbol());
|
||||
if (controlIndex >= 0)
|
||||
{
|
||||
float defaultValue = control->default_value();
|
||||
this->processActions.push_back(
|
||||
[pLv2Effect,controlIndex,defaultValue](int32_t frames) {
|
||||
pLv2Effect->SetControl(controlIndex,defaultValue);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pEffect)
|
||||
@@ -287,13 +314,21 @@ void Lv2Pedalboard::PrepareMidiMap(const PedalboardItem &pedalboardItem)
|
||||
mapping.controlIndex = controlIndex;
|
||||
mapping.midiBinding = binding;
|
||||
mapping.instanceId = pedalboardItem.instanceId();
|
||||
if (pPortInfo->IsSwitch())
|
||||
|
||||
if (pPortInfo->trigger_property())
|
||||
{
|
||||
mapping.mappingType = binding.switchControlType() == LATCH_CONTROL_TYPE ? MappingType::Latched : MappingType::Momentary;
|
||||
mapping.mappingType = MidiControlType::Trigger;
|
||||
} else if (pPortInfo->IsSwitch())
|
||||
{
|
||||
mapping.mappingType = MidiControlType::Toggle;
|
||||
}
|
||||
else
|
||||
else if (pPortInfo->enumeration_property())
|
||||
{
|
||||
mapping.mappingType = binding.linearControlType() == LATCH_CONTROL_TYPE ? MappingType::Linear : MappingType::Circular;
|
||||
mapping.mappingType = MidiControlType::Select;
|
||||
}
|
||||
else
|
||||
{
|
||||
mapping.mappingType = MidiControlType::Dial;
|
||||
}
|
||||
if (binding.bindingType() == BINDING_TYPE_NOTE)
|
||||
{
|
||||
@@ -651,46 +686,108 @@ void Lv2Pedalboard::OnMidiMessage(size_t size, uint8_t *message,
|
||||
{
|
||||
switch (mapping.mappingType)
|
||||
{
|
||||
case MappingType::Circular:
|
||||
case MappingType::Linear:
|
||||
case MidiControlType::Trigger:
|
||||
{
|
||||
float thisRange = (mapping.midiBinding.maxValue() - mapping.midiBinding.minValue()) * range + mapping.midiBinding.minValue();
|
||||
float value = mapping.pPortInfo->rangeToValue(thisRange);
|
||||
this->SetControlValue(mapping.effectIndex, mapping.controlIndex, value);
|
||||
pfnCallback(callbackHandle, mapping.instanceId, mapping.pPortInfo->index(), value);
|
||||
break;
|
||||
}
|
||||
case MappingType::Latched:
|
||||
{
|
||||
range = std::round(range);
|
||||
|
||||
if (!mapping.hasLastValue)
|
||||
bool triggered = false;
|
||||
if (mapping.midiBinding.switchControlType() == SwitchControlTypeT::TRIGGER_ON_RISING_EDGE
|
||||
|| mapping.midiBinding.bindingType() == BINDING_TYPE_NOTE
|
||||
)
|
||||
{
|
||||
mapping.lastValue = 0;
|
||||
mapping.hasLastValue = true;
|
||||
if (mapping.lastValue < range)
|
||||
{
|
||||
if (!mapping.lastValueIncreasing) {
|
||||
triggered = true;
|
||||
}
|
||||
mapping.lastValueIncreasing = true;
|
||||
mapping.lastValue = range;
|
||||
} else {
|
||||
mapping.lastValueIncreasing = false;
|
||||
mapping.lastValue = range;
|
||||
}
|
||||
} else {
|
||||
triggered = true;
|
||||
}
|
||||
if (range != mapping.lastValue && range == 1)
|
||||
if (triggered)
|
||||
{
|
||||
IEffect *pEffect = this->realtimeEffects[mapping.effectIndex];
|
||||
float value = mapping.pPortInfo->max_value();
|
||||
if (value == mapping.pPortInfo->default_value())
|
||||
{
|
||||
value = mapping.pPortInfo->min_value();
|
||||
}
|
||||
this->SetControlValue(mapping.effectIndex, mapping.controlIndex, value);
|
||||
// do NOT notify anyone!
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MidiControlType::Toggle:
|
||||
{
|
||||
bool triggered = false;
|
||||
|
||||
range = std::round(range);
|
||||
|
||||
if (mapping.midiBinding.switchControlType() == SwitchControlTypeT::TOGGLE_ON_RISING_EDGE)
|
||||
{
|
||||
if (range > mapping.lastValue)
|
||||
{
|
||||
if (!mapping.lastValueIncreasing) {
|
||||
triggered = true;
|
||||
}
|
||||
mapping.lastValueIncreasing = true;
|
||||
mapping.lastValue = range;
|
||||
} else {
|
||||
mapping.lastValueIncreasing = false;
|
||||
mapping.lastValue = range;
|
||||
}
|
||||
if (triggered)
|
||||
{
|
||||
IEffect *pEffect = this->realtimeEffects[mapping.effectIndex];
|
||||
float currentValue = pEffect->GetControlValue(mapping.controlIndex);
|
||||
|
||||
currentValue = currentValue == 0 ? 1 : 0;
|
||||
pEffect->SetControl(mapping.controlIndex, currentValue);
|
||||
pfnCallback(callbackHandle, mapping.instanceId, mapping.pPortInfo->index(), currentValue);
|
||||
}
|
||||
} else if (mapping.midiBinding.switchControlType() == SwitchControlTypeT::TOGGLE_ON_VALUE)
|
||||
{
|
||||
triggered = true;
|
||||
mapping.lastValue = range;
|
||||
IEffect *pEffect = this->realtimeEffects[mapping.effectIndex];
|
||||
float currentValue = pEffect->GetControlValue(mapping.controlIndex);
|
||||
currentValue = currentValue == 0 ? 1 : 0;
|
||||
if (currentValue != range)
|
||||
{
|
||||
pEffect->SetControl(mapping.controlIndex, range);
|
||||
pfnCallback(callbackHandle, mapping.instanceId, mapping.pPortInfo->index(), range);
|
||||
}
|
||||
|
||||
} else {
|
||||
// any control value toggles.
|
||||
triggered = true;
|
||||
mapping.lastValue = range;
|
||||
IEffect *pEffect = this->realtimeEffects[mapping.effectIndex];
|
||||
float currentValue = pEffect->GetControlValue(mapping.controlIndex);
|
||||
currentValue = currentValue == 0 ? 1: 0;
|
||||
pEffect->SetControl(mapping.controlIndex, currentValue);
|
||||
pfnCallback(callbackHandle, mapping.instanceId, mapping.pPortInfo->index(), currentValue);
|
||||
}
|
||||
mapping.lastValue = range;
|
||||
break;
|
||||
}
|
||||
case MappingType::Momentary:
|
||||
case MidiControlType::Select:
|
||||
case MidiControlType::Dial:
|
||||
{
|
||||
IEffect *pEffect = this->realtimeEffects[mapping.effectIndex];
|
||||
float value = mapping.pPortInfo->rangeToValue(range);
|
||||
if (pEffect->GetControlValue(mapping.controlIndex) != value)
|
||||
range = mapping.midiBinding.adjustRange(range);
|
||||
float currentValue = mapping.pPortInfo->rangeToValue(range);
|
||||
if (pEffect->GetControlValue(mapping.controlIndex) != currentValue)
|
||||
{
|
||||
this->SetControlValue(mapping.effectIndex, mapping.controlIndex, value);
|
||||
pfnCallback(callbackHandle, mapping.instanceId, mapping.pPortInfo->index(), value);
|
||||
this->SetControlValue(mapping.effectIndex, mapping.controlIndex,currentValue);
|
||||
pfnCallback(callbackHandle, mapping.instanceId, mapping.pPortInfo->index(), currentValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MidiControlType::None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,12 +72,13 @@ namespace pipedal
|
||||
|
||||
RealtimeRingBufferWriter *ringBufferWriter;
|
||||
|
||||
enum class MappingType
|
||||
enum class MidiControlType
|
||||
{
|
||||
Linear,
|
||||
Circular,
|
||||
Momentary,
|
||||
Latched,
|
||||
None,
|
||||
Select,
|
||||
Dial,
|
||||
Toggle,
|
||||
Trigger
|
||||
};
|
||||
class MidiMapping
|
||||
{
|
||||
@@ -89,8 +90,9 @@ namespace pipedal
|
||||
int controlIndex = -1;
|
||||
int key; // key to the note or control. internal use only.
|
||||
bool hasLastValue = false;
|
||||
float lastValue = -1;
|
||||
MappingType mappingType;
|
||||
bool lastValueIncreasing = false;
|
||||
float lastValue = 0;
|
||||
MidiControlType mappingType;
|
||||
MidiBinding midiBinding;
|
||||
};
|
||||
|
||||
|
||||
+21
-4
@@ -57,10 +57,20 @@ class MapFeature;
|
||||
const int LINEAR_CONTROL_TYPE = 0;
|
||||
const int CIRCULAR_CONTROL_TYPE = 1;
|
||||
|
||||
const int LATCH_CONTROL_TYPE = 0;
|
||||
const int MOMENTARY_CONTROL_TYPE = 1;
|
||||
|
||||
|
||||
enum class SwitchControlTypeT {
|
||||
TRIGGER_ON_RISING_EDGE = 0,
|
||||
TRIGGER_ON_ANY = 2,
|
||||
TOGGLE_ON_RISING_EDGE = 0,
|
||||
TOGGLE_ON_VALUE = 1,
|
||||
TOGGLE_ON_ANY = 2,
|
||||
|
||||
LATCH_CONTROL_TYPE = 0,
|
||||
MOMENTARY_CONTROL_TYPE = 1,
|
||||
|
||||
};
|
||||
|
||||
|
||||
class MidiBinding {
|
||||
public:
|
||||
@@ -74,7 +84,7 @@ private:
|
||||
float maxValue_ = 1;
|
||||
float rotaryScale_ = 1;
|
||||
int linearControlType_ = LINEAR_CONTROL_TYPE;
|
||||
int switchControlType_ = LATCH_CONTROL_TYPE;
|
||||
int switchControlType_ = (int)SwitchControlTypeT::LATCH_CONTROL_TYPE;
|
||||
public:
|
||||
static MidiBinding SystemBinding(const std::string&symbol)
|
||||
{
|
||||
@@ -105,8 +115,15 @@ public:
|
||||
GETTER_SETTER(maxValue);
|
||||
GETTER_SETTER(rotaryScale);
|
||||
GETTER_SETTER(linearControlType);
|
||||
GETTER_SETTER(switchControlType);
|
||||
|
||||
SwitchControlTypeT switchControlType() const { return (SwitchControlTypeT)switchControlType_; }
|
||||
void switchControlType(SwitchControlTypeT value) { switchControlType_ = (int)value; }
|
||||
|
||||
|
||||
float adjustRange(float range)
|
||||
{
|
||||
return maxValue_*range+minValue_*(1.0f-range);
|
||||
}
|
||||
DECLARE_JSON_MAP(MidiBinding);
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user