Add Host Parameters Map module, functional but still WIP
Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
parent
952304999d
commit
e861389537
7 changed files with 639 additions and 39 deletions
|
@ -90,6 +90,15 @@
|
|||
"External"
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "HostParametersMap",
|
||||
"name": "Host Parameters Map",
|
||||
"description": "Allows host-controlled plugin parameters to control other module parameters",
|
||||
"manualUrl": "https://github.com/DISTRHO/Cardinal/blob/main/docs/CARDINAL-MODULES.md#host-parameters-map",
|
||||
"tags": [
|
||||
"External"
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "HostTime",
|
||||
"name": "Host Time",
|
||||
|
|
|
@ -59,6 +59,7 @@ struct HostMIDIMap : TerminalModule {
|
|||
uint32_t lastProcessCounter;
|
||||
int nextLearningId;
|
||||
uint8_t channel;
|
||||
bool bypassed = false;
|
||||
|
||||
// from Rack
|
||||
bool smooth;
|
||||
|
@ -95,12 +96,10 @@ struct HostMIDIMap : TerminalModule {
|
|||
{
|
||||
paramHandles[id].color = nvgRGBf(0.76f, 0.11f, 0.22f);
|
||||
paramHandles[id].text.reserve(25);
|
||||
valueFilters[id].setTau(1 / 30.f);
|
||||
pcontext->engine->addParamHandle(¶mHandles[id]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_MIDI_CONTROL; i++)
|
||||
valueFilters[i].setTau(1 / 30.f);
|
||||
|
||||
divider.setDivision(32);
|
||||
onReset();
|
||||
}
|
||||
|
@ -141,13 +140,14 @@ struct HostMIDIMap : TerminalModule {
|
|||
|
||||
if (processCounterChanged)
|
||||
{
|
||||
bypassed = isBypassed();
|
||||
lastProcessCounter = processCounter;
|
||||
midiEvents = pcontext->midiEvents;
|
||||
midiEventsLeft = pcontext->midiEventCount;
|
||||
midiEventFrame = 0;
|
||||
}
|
||||
|
||||
if (isBypassed() || !divider.process())
|
||||
if (bypassed || !divider.process())
|
||||
{
|
||||
++midiEventFrame;
|
||||
return;
|
||||
|
@ -262,21 +262,6 @@ struct HostMIDIMap : TerminalModule {
|
|||
void processTerminalOutput(const ProcessArgs&) override
|
||||
{}
|
||||
|
||||
void clearMap(int id)
|
||||
{
|
||||
nextLearningId = -1;
|
||||
learningId = -1;
|
||||
learnedCc = false;
|
||||
learnedParam = false;
|
||||
|
||||
ccs[id] = -1;
|
||||
values[id] = -1;
|
||||
pcontext->engine->updateParamHandle(¶mHandles[id], -1, 0, true);
|
||||
valueFilters[id].reset();
|
||||
refreshParamHandleText(id);
|
||||
updateMapLen();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------
|
||||
// stuff for resetting state
|
||||
|
||||
|
@ -308,7 +293,21 @@ struct HostMIDIMap : TerminalModule {
|
|||
// ----------------------------------------------------------------------------------------------------------------
|
||||
// stuff called from panel side, must lock engine
|
||||
|
||||
// called from onSelect
|
||||
void clearMap(int id)
|
||||
{
|
||||
nextLearningId = -1;
|
||||
learningId = -1;
|
||||
learnedCc = false;
|
||||
learnedParam = false;
|
||||
|
||||
ccs[id] = -1;
|
||||
values[id] = -1;
|
||||
pcontext->engine->updateParamHandle(¶mHandles[id], -1, 0, true);
|
||||
valueFilters[id].reset();
|
||||
refreshParamHandleText(id);
|
||||
updateMapLen();
|
||||
}
|
||||
|
||||
void enableLearn(const int id)
|
||||
{
|
||||
if (learningId == id)
|
||||
|
@ -321,16 +320,6 @@ struct HostMIDIMap : TerminalModule {
|
|||
learnedParam = false;
|
||||
}
|
||||
|
||||
// called from onDeselect
|
||||
void disableLearn(const int id)
|
||||
{
|
||||
nextLearningId = -1;
|
||||
|
||||
if (learningId == id)
|
||||
learningId = -1;
|
||||
}
|
||||
|
||||
// called from onDeselect
|
||||
void learnParam(const int id, const int64_t moduleId, const int paramId)
|
||||
{
|
||||
pcontext->engine->updateParamHandle(¶mHandles[id], moduleId, paramId, true);
|
||||
|
@ -339,6 +328,16 @@ struct HostMIDIMap : TerminalModule {
|
|||
updateMapLen();
|
||||
}
|
||||
|
||||
/*
|
||||
void disableLearn(const int id)
|
||||
{
|
||||
nextLearningId = -1;
|
||||
|
||||
if (learningId == id)
|
||||
learningId = -1;
|
||||
}
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------
|
||||
// common utils
|
||||
|
||||
|
@ -371,14 +370,16 @@ struct HostMIDIMap : TerminalModule {
|
|||
// this is called during RT!!
|
||||
void refreshParamHandleText(const int id)
|
||||
{
|
||||
char textBuf[25];
|
||||
|
||||
if (ccs[id] >= 0)
|
||||
{
|
||||
char textBuf[25];
|
||||
std::sprintf(textBuf, "CC%02d", ccs[id]);
|
||||
paramHandles[id].text.assign(textBuf);
|
||||
}
|
||||
else
|
||||
std::strcpy(textBuf, "MIDI-Map");
|
||||
|
||||
paramHandles[id].text.assign(textBuf);
|
||||
{
|
||||
paramHandles[id].text.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void updateMapLen()
|
||||
|
@ -471,7 +472,6 @@ struct HostMIDIMap : TerminalModule {
|
|||
struct CardinalMIDIMapChoice : CardinalLedDisplayChoice {
|
||||
HostMIDIMap* const module;
|
||||
const int id;
|
||||
int disableLearnFrames = -1;
|
||||
ParamWidget* lastTouchedParam = nullptr;
|
||||
|
||||
CardinalMIDIMapChoice(HostMIDIMap* const m, const int i)
|
||||
|
@ -576,10 +576,10 @@ struct CardinalMIDIMapChoice : CardinalLedDisplayChoice {
|
|||
switch (e.button)
|
||||
{
|
||||
case GLFW_MOUSE_BUTTON_RIGHT:
|
||||
APP->scene->rack->touchedParam = lastTouchedParam = nullptr;
|
||||
module->clearMap(id);
|
||||
e.consume(this);
|
||||
break;
|
||||
// fall-through
|
||||
case GLFW_MOUSE_BUTTON_LEFT:
|
||||
APP->scene->rack->touchedParam = lastTouchedParam = nullptr;
|
||||
module->enableLearn(id);
|
||||
|
|
589
plugins/Cardinal/src/HostParameters-Map.cpp
Normal file
589
plugins/Cardinal/src/HostParameters-Map.cpp
Normal file
|
@ -0,0 +1,589 @@
|
|||
/*
|
||||
* DISTRHO Cardinal Plugin
|
||||
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of
|
||||
* the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* For a full copy of the GNU General Public License see the LICENSE file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file contains portions from VCVRack's core/MIDIMap.cpp
|
||||
* Copyright (C) 2016-2021 VCV.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "plugincontext.hpp"
|
||||
#include "ModuleWidgets.hpp"
|
||||
#include "Widgets.hpp"
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
static constexpr const uint8_t MAX_MAPPED_PARAMS = 64;
|
||||
|
||||
struct HostParametersMap : TerminalModule {
|
||||
enum ParamIds {
|
||||
NUM_PARAMS
|
||||
};
|
||||
enum InputIds {
|
||||
NUM_INPUTS
|
||||
};
|
||||
enum OutputIds {
|
||||
NUM_OUTPUTS
|
||||
};
|
||||
enum LightIds {
|
||||
NUM_LIGHTS
|
||||
};
|
||||
|
||||
struct Mapping {
|
||||
uint8_t hostParamId = UINT8_MAX;
|
||||
bool inverted = false;
|
||||
bool smooth = false;
|
||||
ParamHandle paramHandle;
|
||||
};
|
||||
|
||||
Mapping mappings[MAX_MAPPED_PARAMS];
|
||||
dsp::ExponentialFilter valueFilters[MAX_MAPPED_PARAMS];
|
||||
bool filterInitialized[MAX_MAPPED_PARAMS] = {};
|
||||
bool valueReached[MAX_MAPPED_PARAMS] = {};
|
||||
|
||||
uint8_t numMappedParmeters = 1;
|
||||
uint8_t learningId = UINT8_MAX;
|
||||
|
||||
CardinalPluginContext* const pcontext;
|
||||
bool parametersChanged[kModuleParameters] = {};
|
||||
float parameterValues[kModuleParameters];
|
||||
bool bypassed = false;
|
||||
bool firstRun = true;
|
||||
uint32_t lastProcessCounter = 0;
|
||||
|
||||
HostParametersMap()
|
||||
: pcontext(static_cast<CardinalPluginContext*>(APP))
|
||||
{
|
||||
if (pcontext == nullptr)
|
||||
throw rack::Exception("Plugin context is null.");
|
||||
|
||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
|
||||
|
||||
for (uint8_t id = 0; id < MAX_MAPPED_PARAMS; ++id)
|
||||
{
|
||||
mappings[id].paramHandle.color = nvgRGBf(0.76f, 0.11f, 0.22f);
|
||||
valueFilters[id].setTau(1 / 30.f);
|
||||
pcontext->engine->addParamHandle(&mappings[id].paramHandle);
|
||||
}
|
||||
|
||||
std::memcpy(parameterValues, pcontext->parameters, sizeof(parameterValues));
|
||||
}
|
||||
|
||||
~HostParametersMap()
|
||||
{
|
||||
if (pcontext == nullptr)
|
||||
return;
|
||||
|
||||
for (uint8_t id = 0; id < MAX_MAPPED_PARAMS; ++id)
|
||||
pcontext->engine->removeParamHandle(&mappings[id].paramHandle);
|
||||
}
|
||||
|
||||
void onReset() override
|
||||
{
|
||||
lastProcessCounter = 0;
|
||||
|
||||
// Use NoLock because we're already in an Engine write-lock if Engine::resetModule().
|
||||
// We also might be in the MIDIMap() constructor, which could cause problems, but when constructing, all ParamHandles will point to no Modules anyway.
|
||||
clearMaps_NoLock();
|
||||
numMappedParmeters = 1;
|
||||
}
|
||||
|
||||
void clearMaps_NoLock()
|
||||
{
|
||||
learningId = UINT8_MAX;
|
||||
|
||||
for (uint8_t id = 0; id < MAX_MAPPED_PARAMS; ++id)
|
||||
{
|
||||
pcontext->engine->updateParamHandle_NoLock(&mappings[id].paramHandle, -1, 0, true);
|
||||
valueReached[id] = false;
|
||||
valueFilters[id].reset();
|
||||
mappings[id].hostParamId = UINT8_MAX;
|
||||
}
|
||||
|
||||
firstRun = true;
|
||||
std::memcpy(parameterValues, pcontext->parameters, sizeof(parameterValues));
|
||||
std::memset(parametersChanged, 0, sizeof(parametersChanged));
|
||||
}
|
||||
|
||||
void processTerminalInput(const ProcessArgs& args) override
|
||||
{
|
||||
const uint32_t processCounter = pcontext->processCounter;
|
||||
|
||||
if (lastProcessCounter == processCounter)
|
||||
return;
|
||||
|
||||
lastProcessCounter = processCounter;
|
||||
|
||||
if (isBypassed())
|
||||
return;
|
||||
|
||||
for (uint32_t i = 0; i < kModuleParameters; ++i)
|
||||
{
|
||||
if (d_isEqual(pcontext->parameters[i], parameterValues[i]))
|
||||
continue;
|
||||
|
||||
parameterValues[i] = pcontext->parameters[i];
|
||||
parametersChanged[i] = true;
|
||||
}
|
||||
|
||||
for (uint id = 0; id < numMappedParmeters; ++id)
|
||||
{
|
||||
ParamHandle& paramHandle(mappings[id].paramHandle);
|
||||
|
||||
if (paramHandle.module == nullptr)
|
||||
continue;
|
||||
|
||||
// Get ParamQuantity from ParamHandle
|
||||
const int paramId = paramHandle.paramId;
|
||||
ParamQuantity* const paramQuantity = paramHandle.module->paramQuantities[paramId];
|
||||
if (!paramQuantity)
|
||||
continue;
|
||||
if (!paramQuantity->isBounded())
|
||||
continue;
|
||||
|
||||
// Validate hostParamId
|
||||
const uint8_t hostParamId = mappings[id].hostParamId;
|
||||
if (hostParamId >= kModuleParameters)
|
||||
continue;
|
||||
|
||||
// Set filter from param value if filter is uninitialized
|
||||
if (!filterInitialized[id])
|
||||
{
|
||||
valueFilters[id].out = paramQuantity->getScaledValue();
|
||||
filterInitialized[id] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if parameter was changed by the host
|
||||
if (parametersChanged[hostParamId] && !firstRun)
|
||||
valueReached[id] = false;
|
||||
else if (valueReached[id])
|
||||
continue;
|
||||
|
||||
// Apply value, smooth as needed.
|
||||
const float value = 0.1f * (mappings[id].inverted ? 10.f - parameterValues[hostParamId]
|
||||
: parameterValues[hostParamId]);
|
||||
|
||||
if (mappings[id].smooth && std::fabs(valueFilters[id].out - value) < 1.f)
|
||||
{
|
||||
// Smooth value with filter
|
||||
if (d_isEqual(valueFilters[id].process(args.sampleTime * pcontext->bufferSize, value), value))
|
||||
{
|
||||
valueReached[id] = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Jump value
|
||||
if (d_isEqual(valueFilters[id].out, value))
|
||||
{
|
||||
valueReached[id] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
valueFilters[id].out = value;
|
||||
}
|
||||
|
||||
paramQuantity->setScaledValue(valueFilters[id].out);
|
||||
}
|
||||
|
||||
firstRun = false;
|
||||
std::memset(parametersChanged, 0, sizeof(parametersChanged));
|
||||
}
|
||||
|
||||
void processTerminalOutput(const ProcessArgs&) override
|
||||
{}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------
|
||||
// save and load json stuff
|
||||
|
||||
json_t* dataToJson() override
|
||||
{
|
||||
json_t* const rootJ = json_object();
|
||||
DISTRHO_SAFE_ASSERT_RETURN(rootJ != nullptr, nullptr);
|
||||
|
||||
if (json_t* const mapsJ = json_array())
|
||||
{
|
||||
for (uint id = 0; id < numMappedParmeters; ++id)
|
||||
{
|
||||
json_t* const mapJ = json_object();
|
||||
DISTRHO_SAFE_ASSERT_CONTINUE(mapJ != nullptr);
|
||||
json_object_set_new(mapJ, "hostParamId", json_integer(mappings[id].hostParamId));
|
||||
json_object_set_new(mapJ, "inverted", json_boolean(mappings[id].inverted));
|
||||
json_object_set_new(mapJ, "smooth", json_boolean(mappings[id].smooth));
|
||||
json_object_set_new(mapJ, "moduleId", json_integer(mappings[id].paramHandle.moduleId));
|
||||
json_object_set_new(mapJ, "paramId", json_integer(mappings[id].paramHandle.paramId));
|
||||
json_array_append_new(mapsJ, mapJ);
|
||||
}
|
||||
json_object_set_new(rootJ, "maps", mapsJ);
|
||||
}
|
||||
|
||||
return rootJ;
|
||||
}
|
||||
|
||||
void dataFromJson(json_t* const rootJ) override
|
||||
{
|
||||
// Use NoLock because we're already in an Engine write-lock.
|
||||
clearMaps_NoLock();
|
||||
|
||||
if (json_t* const mapsJ = json_object_get(rootJ, "maps"))
|
||||
{
|
||||
json_t* mapJ;
|
||||
size_t id;
|
||||
json_array_foreach(mapsJ, id, mapJ)
|
||||
{
|
||||
if (id >= MAX_MAPPED_PARAMS)
|
||||
break;
|
||||
json_t* const hostParamIdJ = json_object_get(mapJ, "hostParamId");
|
||||
json_t* const invertedJ = json_object_get(mapJ, "inverted");
|
||||
json_t* const smoothJ = json_object_get(mapJ, "smooth");
|
||||
json_t* const moduleIdJ = json_object_get(mapJ, "moduleId");
|
||||
json_t* const paramIdJ = json_object_get(mapJ, "paramId");
|
||||
if (hostParamIdJ == nullptr)
|
||||
continue;
|
||||
if (invertedJ == nullptr)
|
||||
continue;
|
||||
if (smoothJ == nullptr)
|
||||
continue;
|
||||
if (moduleIdJ == nullptr)
|
||||
continue;
|
||||
if (paramIdJ == nullptr)
|
||||
continue;
|
||||
|
||||
filterInitialized[id] = false;
|
||||
valueReached[id] = true;
|
||||
valueFilters[id].reset();
|
||||
mappings[id].hostParamId = json_integer_value(hostParamIdJ);
|
||||
mappings[id].inverted = json_boolean_value(invertedJ);
|
||||
mappings[id].smooth = json_boolean_value(smoothJ);
|
||||
pcontext->engine->updateParamHandle_NoLock(&mappings[id].paramHandle,
|
||||
json_integer_value(moduleIdJ),
|
||||
json_integer_value(paramIdJ),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
updateMapLen();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------
|
||||
// stuff called from panel side
|
||||
|
||||
void clearMap(const uint8_t id)
|
||||
{
|
||||
learningId = UINT8_MAX;
|
||||
|
||||
mappings[id].hostParamId = UINT8_MAX;
|
||||
pcontext->engine->updateParamHandle(&mappings[id].paramHandle, -1, 0, true);
|
||||
updateMapLen();
|
||||
}
|
||||
|
||||
void learnParam(const uint8_t hostParamId, const bool inverted, const bool smooth,
|
||||
const int64_t moduleId, const int paramId)
|
||||
{
|
||||
const uint8_t id = learningId;
|
||||
learningId = UINT8_MAX;
|
||||
DISTRHO_SAFE_ASSERT_RETURN(id < MAX_MAPPED_PARAMS,);
|
||||
|
||||
filterInitialized[id] = false;
|
||||
valueFilters[id].reset();
|
||||
valueReached[id] = true;
|
||||
mappings[id].inverted = inverted;
|
||||
mappings[id].smooth = smooth;
|
||||
mappings[id].hostParamId = hostParamId;
|
||||
|
||||
if (mappings[id].paramHandle.moduleId != moduleId || mappings[id].paramHandle.paramId != paramId)
|
||||
pcontext->engine->updateParamHandle(&mappings[id].paramHandle, moduleId, paramId, true);
|
||||
|
||||
updateMapLen();
|
||||
}
|
||||
|
||||
void updateMapLen()
|
||||
{
|
||||
// Find last nonempty map
|
||||
int16_t id;
|
||||
for (id = MAX_MAPPED_PARAMS; --id >= 0;)
|
||||
{
|
||||
if (mappings[id].paramHandle.moduleId >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
numMappedParmeters = static_cast<uint8_t>(id + 1);
|
||||
|
||||
// Add an empty "Mapping..." slot
|
||||
if (numMappedParmeters < MAX_MAPPED_PARAMS)
|
||||
++numMappedParmeters;
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#ifndef HEADLESS
|
||||
struct HostParametersMapChoice : CardinalLedDisplayChoice {
|
||||
HostParametersMap* const module;
|
||||
const uint8_t id;
|
||||
uint8_t hostParamId = UINT8_MAX;
|
||||
bool inverted = false;
|
||||
bool smooth = true;
|
||||
|
||||
HostParametersMapChoice(HostParametersMap* const m, const uint8_t i)
|
||||
: CardinalLedDisplayChoice(),
|
||||
module(m),
|
||||
id(i)
|
||||
{
|
||||
alignTextCenter = false;
|
||||
|
||||
// Module browser setup
|
||||
if (m == nullptr)
|
||||
{
|
||||
bgColor = nvgRGB(0, 0, 0);
|
||||
color.a = 0.75f;
|
||||
text = "Click here to map";
|
||||
}
|
||||
}
|
||||
|
||||
void draw(const DrawArgs& args) override
|
||||
{
|
||||
if (bgColor.a > 0.0f)
|
||||
{
|
||||
nvgBeginPath(args.vg);
|
||||
nvgRoundedRect(args.vg, 0, 0, box.size.x, box.size.y, 4);
|
||||
nvgFillColor(args.vg, bgColor);
|
||||
nvgFill(args.vg);
|
||||
}
|
||||
|
||||
Widget::draw(args);
|
||||
}
|
||||
|
||||
void step() override
|
||||
{
|
||||
if (module == nullptr)
|
||||
return;
|
||||
|
||||
// Set bgColor and selected state
|
||||
if (module->learningId == id)
|
||||
{
|
||||
bgColor = color;
|
||||
bgColor.a = 0.125f;
|
||||
|
||||
if (ParamWidget* const touchedParam = APP->scene->rack->touchedParam)
|
||||
{
|
||||
APP->scene->rack->touchedParam = nullptr;
|
||||
DISTRHO_SAFE_ASSERT_RETURN(hostParamId < kModuleParameters,);
|
||||
|
||||
const int64_t moduleId = touchedParam->module->id;
|
||||
const int paramId = touchedParam->paramId;
|
||||
module->learnParam(hostParamId, inverted, smooth, moduleId, paramId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bgColor = nvgRGB(0, 0, 0);
|
||||
}
|
||||
|
||||
// Set text
|
||||
text.clear();
|
||||
|
||||
// mapped
|
||||
if (module->mappings[id].hostParamId < kModuleParameters)
|
||||
text += string::f("P%02d: ", module->mappings[id].hostParamId + 1);
|
||||
if (module->mappings[id].paramHandle.moduleId >= 0)
|
||||
text += getParamName();
|
||||
|
||||
// Set text color
|
||||
if (text.empty() && module->learningId != id)
|
||||
color.a = 0.75f;
|
||||
else
|
||||
color.a = 1.0f;
|
||||
|
||||
// unmapped
|
||||
if (text.empty())
|
||||
{
|
||||
if (module->learningId == id)
|
||||
text = "Mapping...";
|
||||
else
|
||||
text = module->numMappedParmeters == 1 ? "Click here to map" : "Unmapped";
|
||||
}
|
||||
}
|
||||
|
||||
void onButton(const ButtonEvent& e) override
|
||||
{
|
||||
DISTRHO_SAFE_ASSERT_RETURN(module != nullptr,);
|
||||
|
||||
e.stopPropagating();
|
||||
|
||||
if (e.action != GLFW_PRESS)
|
||||
return;
|
||||
|
||||
switch (e.button)
|
||||
{
|
||||
case GLFW_MOUSE_BUTTON_RIGHT:
|
||||
APP->scene->rack->touchedParam = nullptr;
|
||||
module->clearMap(id);
|
||||
e.consume(this);
|
||||
break;
|
||||
case GLFW_MOUSE_BUTTON_LEFT:
|
||||
APP->scene->rack->touchedParam = nullptr;
|
||||
e.consume(this);
|
||||
// reset before dialog
|
||||
module->learningId = hostParamId = UINT8_MAX;
|
||||
inverted = smooth = false;
|
||||
HostParametersMapChoice* const self = this;
|
||||
// open dialog
|
||||
async_dialog_text_input("Plugin-exposed parameter index to map to", "1", [self](char* newText){
|
||||
if (self == nullptr || newText == nullptr)
|
||||
return;
|
||||
// FIXME use a proper dialog
|
||||
const int hostParamIdTry = std::atoi(newText);
|
||||
if (hostParamIdTry > 0 && hostParamIdTry < (int)kModuleParameters)
|
||||
{
|
||||
self->module->learningId = self->id;
|
||||
self->hostParamId = static_cast<uint8_t>(hostParamIdTry - 1);
|
||||
self->inverted = false;
|
||||
self->smooth = false;
|
||||
}
|
||||
std::free(newText);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getParamName() const
|
||||
{
|
||||
DISTRHO_SAFE_ASSERT_RETURN(module != nullptr, "error");
|
||||
DISTRHO_SAFE_ASSERT_RETURN(id < module->numMappedParmeters, "error");
|
||||
|
||||
ParamHandle paramHandle(module->mappings[id].paramHandle);
|
||||
|
||||
Module* const paramModule = paramHandle.module;
|
||||
DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("paramModule is null", paramModule != nullptr, "error");
|
||||
|
||||
const int paramId = paramHandle.paramId;
|
||||
DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("paramId is out of bounds", paramId < (int) paramModule->params.size(), "error");
|
||||
|
||||
ParamQuantity* const paramQuantity = paramModule->paramQuantities[paramId];
|
||||
std::string s = paramQuantity->name;
|
||||
if (s.empty())
|
||||
s = "Unnamed";
|
||||
s += " (";
|
||||
s += paramModule->model->name;
|
||||
s += ")";
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
struct HostParametersMapDisplay : Widget {
|
||||
HostParametersMap* module;
|
||||
ScrollWidget* scroll;
|
||||
HostParametersMapChoice* choices[MAX_MAPPED_PARAMS];
|
||||
LedDisplaySeparator* separators[MAX_MAPPED_PARAMS];
|
||||
|
||||
void drawLayer(const DrawArgs& args, int layer) override
|
||||
{
|
||||
nvgScissor(args.vg, RECT_ARGS(args.clipBox));
|
||||
Widget::drawLayer(args, layer);
|
||||
nvgResetScissor(args.vg);
|
||||
}
|
||||
|
||||
void setModule(HostParametersMap* const module)
|
||||
{
|
||||
this->module = module;
|
||||
|
||||
scroll = new ScrollWidget;
|
||||
scroll->box.size = box.size;
|
||||
addChild(scroll);
|
||||
|
||||
float posY = 0.0f;
|
||||
for (uint8_t id = 0; id < MAX_MAPPED_PARAMS; ++id)
|
||||
{
|
||||
if (id != 0)
|
||||
{
|
||||
LedDisplaySeparator* separator = createWidget<LedDisplaySeparator>(Vec(0.0f, posY));
|
||||
separator->box.size = Vec(box.size.x, 1.0f);
|
||||
separator->visible = false;
|
||||
scroll->container->addChild(separator);
|
||||
separators[id] = separator;
|
||||
}
|
||||
|
||||
HostParametersMapChoice* const choice = new HostParametersMapChoice(module, id);
|
||||
choice->box.pos = Vec(0.0f, posY);
|
||||
choice->box.size = Vec(box.size.x, 20.0f);
|
||||
choice->visible = id == 0;
|
||||
scroll->container->addChild(choice);
|
||||
choices[id] = choice;
|
||||
|
||||
posY += choice->box.size.y;
|
||||
}
|
||||
}
|
||||
|
||||
void step() override
|
||||
{
|
||||
if (module != nullptr)
|
||||
{
|
||||
const uint8_t numMappedParmeters = module->numMappedParmeters;
|
||||
|
||||
for (uint8_t id = 1; id < MAX_MAPPED_PARAMS; ++id)
|
||||
{
|
||||
separators[id]->visible = (id < numMappedParmeters);
|
||||
choices[id]->visible = (id < numMappedParmeters);
|
||||
}
|
||||
}
|
||||
|
||||
Widget::step();
|
||||
}
|
||||
};
|
||||
|
||||
struct HostParametersMapWidget : ModuleWidgetWith11HP {
|
||||
HostParametersMap* const module;
|
||||
|
||||
HostParametersMapWidget(HostParametersMap* const m)
|
||||
: module(m)
|
||||
{
|
||||
setModule(module);
|
||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostParamsMap.svg")));
|
||||
createAndAddScrews();
|
||||
|
||||
HostParametersMapDisplay* const display = createWidget<HostParametersMapDisplay>(Vec(1.0f, 71.0f));
|
||||
display->box.size = Vec(box.size.x - 2.0f, box.size.y - 89.0f);
|
||||
display->setModule(m);
|
||||
addChild(display);
|
||||
}
|
||||
|
||||
void draw(const DrawArgs& args) override
|
||||
{
|
||||
drawBackground(args.vg);
|
||||
ModuleWidgetWith11HP::draw(args);
|
||||
}
|
||||
};
|
||||
#else
|
||||
struct HostParametersMapWidget : ModuleWidget {
|
||||
HostParametersMapWidget(HostParametersMap* const module) {
|
||||
setModule(module);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Model* modelHostParametersMap = createModel<HostParametersMap, HostParametersMapWidget>("HostParametersMap");
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
|
@ -53,7 +53,6 @@ struct HostParameters : TerminalModule {
|
|||
{
|
||||
const uint32_t processCounter = pcontext->processCounter;
|
||||
|
||||
// only checked on input
|
||||
if (lastProcessCounter != processCounter)
|
||||
{
|
||||
bypassed = isBypassed();
|
||||
|
|
|
@ -43,6 +43,7 @@ extern Model* modelHostMIDICC;
|
|||
extern Model* modelHostMIDIGate;
|
||||
extern Model* modelHostMIDIMap;
|
||||
extern Model* modelHostParameters;
|
||||
extern Model* modelHostParametersMap;
|
||||
extern Model* modelHostTime;
|
||||
extern Model* modelIldaeil;
|
||||
extern Model* modelMPV;
|
||||
|
|
|
@ -200,6 +200,7 @@ PLUGIN_FILES += Cardinal/src/HostMIDI-CC.cpp
|
|||
PLUGIN_FILES += Cardinal/src/HostMIDI-Gate.cpp
|
||||
PLUGIN_FILES += Cardinal/src/HostMIDI-Map.cpp
|
||||
PLUGIN_FILES += Cardinal/src/HostParameters.cpp
|
||||
PLUGIN_FILES += Cardinal/src/HostParameters-Map.cpp
|
||||
PLUGIN_FILES += Cardinal/src/HostTime.cpp
|
||||
PLUGIN_FILES += Cardinal/src/TextEditor.cpp
|
||||
|
||||
|
@ -219,7 +220,6 @@ ifneq ($(HEADLESS),true)
|
|||
PLUGIN_FILES += Cardinal/src/ImGuiWidget.cpp
|
||||
PLUGIN_FILES += Cardinal/src/ImGuiTextEditor.cpp
|
||||
PLUGIN_FILES += Cardinal/src/SassyScope.cpp
|
||||
# PLUGIN_FILES += Cardinal/src/sassy/sassy_scope.cpp
|
||||
PLUGIN_FILES += $(wildcard Cardinal/src/DearImGui/*.cpp)
|
||||
PLUGIN_FILES += $(wildcard Cardinal/src/DearImGuiColorTextEditor/*.cpp)
|
||||
endif
|
||||
|
|
|
@ -895,6 +895,7 @@ static void initStatic__Cardinal()
|
|||
p->addModel(modelHostMIDIGate);
|
||||
p->addModel(modelHostMIDIMap);
|
||||
p->addModel(modelHostParameters);
|
||||
p->addModel(modelHostParametersMap);
|
||||
p->addModel(modelHostTime);
|
||||
p->addModel(modelTextEditor);
|
||||
#ifndef STATIC_BUILD
|
||||
|
@ -931,6 +932,7 @@ static void initStatic__Cardinal()
|
|||
modelHostMIDIGate,
|
||||
modelHostMIDIMap,
|
||||
modelHostParameters,
|
||||
modelHostParametersMap,
|
||||
modelHostTime,
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue