diff --git a/Makefile b/Makefile
index 63a0b6f..a1dd49f 100644
--- a/Makefile
+++ b/Makefile
@@ -47,12 +47,15 @@ SOURCES += src/HC-2/cc_map_widget.cpp
SOURCES += src/HC-3/HC-3.cpp
SOURCES += src/HC-3/HC-3-ui.cpp
-SOURCES += src/HC-4/HC-4.cpp
-SOURCES += src/HC-4/HC-4-ui.cpp
+#SOURCES += src/HC-4/HC-4.cpp
+#SOURCES += src/HC-4/HC-4-ui.cpp
SOURCES += src/Pedals/Pedals.cpp
SOURCES += src/Pedals/Pedals-ui.cpp
+SOURCES += src/Round/Round.cpp
+SOURCES += src/Round/Round-ui.cpp
+
DISTRIBUTABLES += res
# DISTRIBUTABLES += presets
# DISTRIBUTABLES += selections
diff --git a/plugin.json b/plugin.json
index b1d982e..8a8c1bd 100644
--- a/plugin.json
+++ b/plugin.json
@@ -32,10 +32,10 @@
"tags": [ "Expander" ]
},
{
- "slug": "pachde-hc-4",
- "name": "HC-4",
- "description": "Next HC One module",
- "tags": [ "Expander" ]
+ "slug": "pachde-hc-round",
+ "name": "Round",
+ "description": "Rounding (HC-1 companion)",
+ "tags": [ "Controller", "MIDI", "Expander" ]
},
{
"slug": "pachde-hc-pedal-1",
diff --git a/res/Pedal1.svg b/res/Pedal1.svg
index 5aeb9a5..b888627 100644
--- a/res/Pedal1.svg
+++ b/res/Pedal1.svg
@@ -1,9 +1,11 @@
-
\ No newline at end of file
diff --git a/res/Pedal2.svg b/res/Pedal2.svg
index e72a46a..f7d4391 100644
--- a/res/Pedal2.svg
+++ b/res/Pedal2.svg
@@ -2,25 +2,15 @@
\ No newline at end of file
+
diff --git a/res/Round.svg b/res/Round.svg
new file mode 100644
index 0000000..7a5d16b
--- /dev/null
+++ b/res/Round.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/src/HC-1/HC-1-draw.cpp b/src/HC-1/HC-1-draw.cpp
index 217ba2f..2d95ae6 100644
--- a/src/HC-1/HC-1-draw.cpp
+++ b/src/HC-1/HC-1-draw.cpp
@@ -230,7 +230,7 @@ void Hc1ModuleWidget::drawPedalAssignment(
void Hc1ModuleWidget::drawPedals(NVGcontext* vg, std::shared_ptr font, bool stockPedals)
{
- SetTextStyle(vg, font, RampGray(G_85), 10.f);
+ SetTextStyle(vg, font, GetStockColor(StockColor::Gold), 10.f);
if (stockPedals) {
drawPedalAssignment(vg, PRESET_RIGHT + 1.f, PRESET_BOTTOM - 19.f, '1', 64, 0);
drawPedalAssignment(vg, PRESET_RIGHT + 1.f, PRESET_BOTTOM - 4.5f, '2', 66, 0);
diff --git a/src/HC-1/HC-1-ui.cpp b/src/HC-1/HC-1-ui.cpp
index e868b08..dad41ee 100644
--- a/src/HC-1/HC-1-ui.cpp
+++ b/src/HC-1/HC-1-ui.cpp
@@ -97,7 +97,7 @@ void Hc1ModuleWidget::createPresetPrevNext()
});
}
addChild(w);
- addChild(createStaticTextLabel(Vec(Vec(RIGHT_COLUMN_BUTTONS - 7.f, y + 5.f)), 25.f, "-", TextAlignment::Center, 9.f, false));
+ addChild(createStaticTextLabel(Vec(Vec(RIGHT_COLUMN_BUTTONS - 7.f, y + 5.f)), 25.f, "-", TextAlignment::Center, 10.f, true));
w = createWidgetCentered(Vec(RIGHT_COLUMN_BUTTONS + 7.f, y));
w->describe("Next preset\n Shift+Click by 10\n Ctrl+Click for device order");
@@ -111,10 +111,10 @@ void Hc1ModuleWidget::createPresetPrevNext()
});
}
addChild(w);
- addChild(createStaticTextLabel(Vec(Vec(RIGHT_COLUMN_BUTTONS + 7.f, y + 5.f)), 25.f, "+", TextAlignment::Center, 9.f, false));
+ addChild(createStaticTextLabel(Vec(Vec(RIGHT_COLUMN_BUTTONS + 7.f, y + 5.f)), 25.f, "+", TextAlignment::Center, 10.f, true));
y += 12.f;
- addChild(createStaticTextLabel(Vec(Vec(RIGHT_COLUMN_BUTTONS, y)), 25.f, "Preset", TextAlignment::Center, 9.f, false));
+ addChild(createStaticTextLabel(Vec(Vec(RIGHT_COLUMN_BUTTONS, y)), 25.f, "Preset", TextAlignment::Center, 10.f, true));
}
void Hc1ModuleWidget::createPresetPaging()
diff --git a/src/HC-2/HC-2-layout.hpp b/src/HC-2/HC-2-layout.hpp
index 25c8aef..dfa8d61 100644
--- a/src/HC-2/HC-2-layout.hpp
+++ b/src/HC-2/HC-2-layout.hpp
@@ -10,26 +10,18 @@ constexpr const float KNOB_SPREAD = 54.25f;
constexpr const float KNOB_COL1 = 35.f;
constexpr const float KNOB_ROW = 44.f;
-constexpr const float ROUND_BOX_TOP = 35.f;
-constexpr const float ROUND_BOX_LEFT = 7.5f;
-constexpr const float ROUND_BOX_WIDTH = 105.f;
-constexpr const float ROUND_BOX_HALF = 110.f * .5f;
constexpr const float REL_OFFSET = 20.f;
constexpr const float REL_VOFFSET = 10.f;
constexpr const float CV_COLUMN_OFFSET = 24.f;
constexpr const float CV_ROW_OFFSET = 6.f;
constexpr const float STATIC_LABEL_OFFSET = 29.5f;
-constexpr const float ROUND_KNOB_ROW = 34.f;
-constexpr const float ROUND_COL1 = ROUND_BOX_HALF - KNOB_RADIUS - 3.f * PAD;
-constexpr const float ROUND_COL2 = ROUND_BOX_HALF + KNOB_RADIUS + 2.f * PAD;
-constexpr const float ROUND_COL3 = ROUND_BOX_WIDTH - KNOB_RADIUS + PAD;
-constexpr const float COMP_BOX_LEFT = ROUND_BOX_LEFT + ROUND_BOX_WIDTH + 7.5;
-constexpr const float COMP_BOX_TOP = ROUND_BOX_TOP;
+constexpr const float COMP_BOX_LEFT = 7.5;
+constexpr const float COMP_BOX_TOP = 35.f;
constexpr const float COMP_BOX_WIDTH = KNOB_SPREAD * 4.f;
-constexpr const float TEQ_BOX_LEFT = ROUND_BOX_LEFT;
-constexpr const float TEQ_BOX_TOP = ROUND_BOX_TOP + KNOB_BOX_HEIGHT + 7.5f;
+constexpr const float TEQ_BOX_LEFT = 7.5f;
+constexpr const float TEQ_BOX_TOP = COMP_BOX_TOP + KNOB_BOX_HEIGHT + 7.5f;
constexpr const float TEQ_BOX_WIDTH = KNOB_SPREAD * 3.f;
}
\ No newline at end of file
diff --git a/src/HC-2/HC-2-ui.cpp b/src/HC-2/HC-2-ui.cpp
index eb28036..db10b5d 100644
--- a/src/HC-2/HC-2-ui.cpp
+++ b/src/HC-2/HC-2-ui.cpp
@@ -9,7 +9,6 @@
#include "../widgets/port.hpp"
#include "../widgets/small_push.hpp"
#include "../widgets/switch_4.hpp"
-#include "tuning_ui.hpp"
namespace pachde {
@@ -28,55 +27,6 @@ inline uint8_t GetSmallParamValue(rack::app::ModuleWidget* w, int id, uint8_t de
return U8(pq->getValue());
}
-void Hc2ModuleWidget::createRoundingUI(float x, float y)
-{
- // Rounding cluster
- addChild(createHeaderWidget(x, y, ROUND_BOX_WIDTH, KNOB_BOX_HEIGHT));
- addChild(createStaticTextLabel(Vec(x + MORE_PAD, y + PAD), 40.f, "Rounding", TextAlignment::Left));
-
- addParam(createParamCentered(
- Vec(x + ROUND_COL2, y + PAD + PAD + HALF_KNOB),
- module, Hc2P::P_ROUND_KIND));
-
- addChild(createModKnob(
- Vec( x + ROUND_COL1, y + ROUND_KNOB_ROW),
- module, Hc2P::P_ROUND_RATE, Hc2I::IN_ROUND_RATE, Hc2P::P_ROUND_RATE_REL));
- addParam(createLightParamCentered>>(
- Vec( x + ROUND_COL1 - REL_OFFSET, y + ROUND_KNOB_ROW - REL_VOFFSET),
- module, Hc2P::P_ROUND_RATE_REL, Hc2L::L_ROUND_RATE_REL));
- addChild(createInputCentered(
- Vec( x + ROUND_COL1 - CV_COLUMN_OFFSET, y + ROUND_KNOB_ROW + HALF_KNOB),
- module, Hc2I::IN_ROUND_RATE));
-
- auto p = createParamCentered(Vec( x + ROUND_COL2, y + ROUND_KNOB_ROW), module, Hc2P::P_ROUND_TUNING);
- p->setImage();
- addChild(p);
-
- addParam(createLightParamCentered>>(
- Vec( x + ROUND_COL3, y + ROUND_KNOB_ROW - REL_VOFFSET),
- module, Hc2P::P_ROUND_INITIAL, Hc2L::L_ROUND_INITIAL));
- addChild(createInputCentered(
- Vec( x + ROUND_COL3, y + ROUND_KNOB_ROW + HALF_KNOB),
- module, Hc2I::IN_ROUND_INITIAL));
-
- rounding_summary = createLazyDynamicTextLabel(
- Vec(x + ROUND_BOX_HALF, y + KNOB_BOX_HEIGHT - 11.f),
- Vec(100.f, 12.f),
- [=]() {
- bool initial = GetSmallParamValue(this, Hc2P::P_ROUND_INITIAL);
- auto rk = describeRoundKindShort(static_cast(GetSmallParamValue(this, Hc2P::P_ROUND_KIND)));
- auto rr = GetSmallParamValue(this,Hc2P::P_ROUND_RATE);
- PackedTuning tuning = static_cast(GetSmallParamValue(this, Hc2P::P_ROUND_TUNING));
- auto ts = describeTuning(unpackTuning(tuning));
- return format_string("%s %s %d %s",
- rk.c_str(), (initial ? "I" : "\u2022"), rr, ts.c_str());
- },
- 9.f, false, TextAlignment::Center,
- GetStockColor(StockColor::Gold), true)
- ;
- addChild(rounding_summary);
-}
-
void Hc2ModuleWidget::createCompressorUI(float x, float y)
{
addChild(createHeaderWidget(x, y, COMP_BOX_WIDTH, KNOB_BOX_HEIGHT));
@@ -158,7 +108,6 @@ Hc2ModuleWidget::Hc2ModuleWidget(Hc2Module * module)
setPanel(createPanel(asset::plugin(pluginInstance, "res/HC-2.svg")));
addChild(partner_picker = createPartnerPicker(7.f, 14.f, 180.f, module ? &module->partner_binding : nullptr));
- createRoundingUI(ROUND_BOX_LEFT, ROUND_BOX_TOP);
createCompressorUI(COMP_BOX_LEFT, COMP_BOX_TOP);
createTiltEqUI(TEQ_BOX_LEFT, TEQ_BOX_TOP);
@@ -167,16 +116,6 @@ Hc2ModuleWidget::Hc2ModuleWidget(Hc2Module * module)
addChild(createCCMap(x, box.size.y - 24.f, true, CCMapChannel::Sixteen, this));
}
-void Hc2ModuleWidget::onPresetChanged(const PresetChangedEvent& e)
-{
- rounding_summary->modified();
-}
-
-void Hc2ModuleWidget::onRoundingChanged(const RoundingChangedEvent& e)
-{
- rounding_summary->modified();
-}
-
void Hc2ModuleWidget::onDeviceChanged(const DeviceChangedEvent& e)
{
partner_picker->onDeviceChanged(e);
diff --git a/src/HC-2/HC-2.cpp b/src/HC-2/HC-2.cpp
index 8a107d6..df7081d 100644
--- a/src/HC-2/HC-2.cpp
+++ b/src/HC-2/HC-2.cpp
@@ -6,7 +6,6 @@
#include "../widgets/cc_param.hpp"
#include "../widgets/components.hpp"
#include "../widgets/pedal_param.hpp"
-#include "tuning_ui.hpp"
namespace pachde {
@@ -16,21 +15,6 @@ Hc2Module::Hc2Module()
config(Params::NUM_PARAMS, Inputs::NUM_INPUTS, Outputs::NUM_OUTPUTS, Lights::NUM_LIGHTS);
- configInput(Inputs::IN_ROUND_RATE, "Round rate");
-
- auto p = configCCParam(EMCC_RoundRate, false, this, Params::P_ROUND_RATE, Inputs::IN_ROUND_RATE, Params::P_ROUND_RATE_REL, Lights::L_ROUND_RATE_REL, 0.f, 127.f, 0.f, "Round rate");
- p->snapEnabled = true;
- configSwitch(P_ROUND_RATE_REL, 0.f, 1.f, 0.f, "Round rate CV-relative", offon);
- configSwitch(P_ROUND_INITIAL, 0.f, 1.f, 0.f, "Round initial", offon);
- configInput(Inputs::IN_ROUND_INITIAL, "Round initial trigger");
- configSwitch(P_ROUND_KIND, 0.f, 3.f, 0.f, "Round type", {
- "Normal",
- "Release",
- "Y (Full to none)",
- "Inverse Y (None to full)"
- });
- configTuningParam(this, P_ROUND_TUNING);
-
configCCParam(EMCC_CompressorThreshold, false, this, P_COMP_THRESHOLD, IN_COMP_THRESHOLD, P_COMP_THRESHOLD_REL, L_COMP_THRESHOLD_REL, 0.f, 127.f, 127.f, "Threshold", "%", 0.f, 100.f/127.f)->snapEnabled = true;
configCCParam(EMCC_CompressorThreshold, false, this, P_COMP_ATTACK, IN_COMP_ATTACK, P_COMP_ATTACK_REL, L_COMP_ATTACK_REL, 0.f, 127.f, 64.f, "Attack", "%", 0.f, 100.f/127.f)->snapEnabled = true;
configCCParam(EMCC_CompressorThreshold, false, this, P_COMP_RATIO, IN_COMP_RATIO, P_COMP_RATIO_REL, L_COMP_RATIO_REL, 0.f, 127.f, 64.f, "Ratio", "%", 0.f, 100.f/127.f)->snapEnabled = true;
@@ -93,51 +77,6 @@ Hc1Module* Hc2Module::getPartner()
return getPartnerImpl(this);
}
-void Hc2Module::onPresetChanged(const PresetChangedEvent& e)
-{
- pullRounding();
- if (ui_event_sink) {
- ui_event_sink->onPresetChanged(e);
- }
-}
-
-void Hc2Module::onRoundingChanged(const RoundingChangedEvent& e)
-{
- bool changed = false;
- auto old = rounding;
- rounding = e.rounding;
-
- if (old.rate != rounding.rate) {
- changed = true;
- auto pq = dynamic_cast(getParamQuantity(Params::P_ROUND_RATE));
- pq->setValueSilent(rounding.rate);
- }
-
- if (old.initial != rounding.initial) {
- changed = true;
- getParamQuantity(Params::P_ROUND_INITIAL)->setValue(1.f * rounding.initial);
- getLight(Lights::L_ROUND_INITIAL).setBrightness(1.0f * rounding.initial);
- }
-
- if (old.kind != rounding.kind) {
- changed = true;
- getParamQuantity(Params::P_ROUND_KIND)->setValue(static_cast(rounding.kind));
- }
- if (old.tuning != rounding.tuning) {
- changed = true;
- getParamQuantity(Params::P_ROUND_TUNING)->setValue(packTuning(rounding.tuning));
- }
- if (old.equal != rounding.equal) {
- changed = true;
- // $BUGBUG: why is this commented out?
- //getParamQuantity(Params::P_ROUND_EQUAL)->setValue(rounding.equal);
- }
-
- if (changed && ui_event_sink) {
- ui_event_sink->onRoundingChanged(e);
- }
-}
-
void Hc2Module::onCompressorChanged(const CompressorChangedEvent &e)
{
bool changed = false;
@@ -215,31 +154,6 @@ void Hc2Module::onDisconnect(const DisconnectEvent& e)
}
}
-void Hc2Module::pullRounding(Hc1Module * partner)
-{
- if (!partner) partner = getPartner();
- if (!partner) return;
- rounding = partner->em.rounding;
- getParamQuantity(Params::P_ROUND_KIND)->setValue(static_cast(rounding.kind));
- getParamQuantity(Params::P_ROUND_INITIAL)->setValue(1.f * rounding.initial);
- getLight(Lights::L_ROUND_INITIAL).setBrightness(1.0f * rounding.initial);
- dynamic_cast(getParamQuantity(Params::P_ROUND_RATE))->setValueSilent(rounding.rate);
- getParamQuantity(Params::P_ROUND_TUNING)->setValue(packTuning(rounding.tuning));
- if (ui_event_sink) {
- ui_event_sink->onRoundingChanged(RoundingChangedEvent{rounding});
- }
-}
-
-void Hc2Module::pushRounding(Hc1Module * partner)
-{
- if (!partner) partner = getPartner();
- if (!partner) return;
- partner->em.rounding = rounding;
- if (ui_event_sink) {
- ui_event_sink->onRoundingChanged(RoundingChangedEvent{rounding});
- }
-}
-
void Hc2Module::pullCompressor(Hc1Module *partner)
{
if (!partner) partner = getPartner();
@@ -313,50 +227,6 @@ void Hc2Module::processCV(int paramId)
}
}
-void Hc2Module::processRoundingControls()
-{
- {
- auto pq = dynamic_cast(getParamQuantity(Params::P_ROUND_RATE));
- assert(pq);
- auto rr = pq->valueToSend();
- if (pq->last_value != rr) {
- rounding.rate = rr;
- pushRounding();
- pq->syncValue();
- }
- }
- {
- bool ri = getParamQuantity(Params::P_ROUND_INITIAL)->getValue() >= .5f;
- getLight(Lights::L_ROUND_INITIAL).setBrightness(1.0f * rounding.initial);
- if (rounding.initial != ri) {
- rounding.initial = ri;
- pushRounding();
- sendControlChange(EM_MasterChannel, EMCC_RoundInitial, ri * 127);
- }
- }
-
- {
- RoundKind kind = static_cast(static_cast(getParamQuantity(P_ROUND_KIND)->getValue()));
- if (kind != rounding.kind) {
- rounding.kind = kind;
- pushRounding();
- auto partner = getPartner();
- uint8_t rev = partner ? (partner->em.reverse_surface ? 1 : 0) : 0;
- sendControlChange(EM_SettingsChannel, EMCC_Reverse_Rounding, (static_cast(kind) << 1) | rev);
- }
- }
-
- {
- auto tq = dynamic_cast(getParamQuantity(P_ROUND_TUNING));
- Tuning tuning = tq->getTuning();
- if (tuning != rounding.tuning) {
- rounding.tuning = tuning;
- pushRounding();
- sendControlChange(EM_SettingsChannel, EMCC_TuningGrid, tuning);
- }
- }
-}
-
void Hc2Module::processCompressorControls()
{
bool changed = false;
@@ -426,7 +296,6 @@ void Hc2Module::processTiltEqControls()
void Hc2Module::processControls()
{
if (!control_rate.process()) { return; }
- processRoundingControls();
processCompressorControls();
processTiltEqControls();
}
@@ -435,7 +304,6 @@ void Hc2Module::process(const ProcessArgs& args)
{
if (++check_cv > CV_INTERVAL) {
check_cv = 0;
- processCV(Params::P_ROUND_RATE);
processCV(Params::P_COMP_THRESHOLD);
processCV(Params::P_COMP_ATTACK);
processCV(Params::P_COMP_RATIO);
@@ -445,15 +313,6 @@ void Hc2Module::process(const ProcessArgs& args)
processCV(Params::P_TEQ_MIX);
}
- if (getInput(Inputs::IN_ROUND_INITIAL).isConnected()) {
- auto v = getInput(Inputs::IN_ROUND_INITIAL).getVoltage();
- if (round_initial_trigger.process(v, 0.1f, 5.f)) {
- round_initial_trigger.reset();
- auto pq = getParamQuantity(Params::P_ROUND_INITIAL);
- bool ri = !(pq->getValue() >= .5f); // toggle
- pq->setValue(1.0f * ri);
- }
- }
processControls();
getLight(Lights::L_COMPRESSOR).setBrightness(static_cast(compressor.mix)/127.f);
getLight(Lights::L_TEQ).setBrightness(static_cast(tilt_eq.mix)/127.f);
diff --git a/src/HC-2/HC-2.hpp b/src/HC-2/HC-2.hpp
index 6ae2a6b..a0a5fc5 100644
--- a/src/HC-2/HC-2.hpp
+++ b/src/HC-2/HC-2.hpp
@@ -27,15 +27,6 @@ struct Hc2Module : Module, ISendMidi, IHandleHcEvents
{
enum Params
{
- P_ROUND_RATE, // 0..127 cc25
- P_ROUND_INITIAL, // 0..1 cc 28
- P_ROUND_KIND, // 0..3 ch16 cc61, but includes reverse surface bit
- P_ROUND_TUNING, // 0..69
- P_ROUND_RATE_REL,
-
- P_PEDAL1,
- P_PEDAL2,
-
P_COMP_THRESHOLD,
P_COMP_ATTACK,
P_COMP_RATIO,
@@ -56,9 +47,6 @@ struct Hc2Module : Module, ISendMidi, IHandleHcEvents
};
enum Inputs
{
- IN_ROUND_RATE,
- IN_ROUND_INITIAL,
-
IN_COMP_THRESHOLD,
IN_COMP_ATTACK,
IN_COMP_RATIO,
@@ -76,9 +64,6 @@ struct Hc2Module : Module, ISendMidi, IHandleHcEvents
};
enum Lights
{
- L_ROUND_RATE_REL,
- L_ROUND_INITIAL,
-
L_COMP_THRESHOLD_REL,
L_COMP_ATTACK_REL,
L_COMP_RATIO_REL,
@@ -95,7 +80,6 @@ struct Hc2Module : Module, ISendMidi, IHandleHcEvents
NUM_LIGHTS
};
- Rounding rounding;
Compressor compressor;
TiltEq tilt_eq;
@@ -113,8 +97,6 @@ struct Hc2Module : Module, ISendMidi, IHandleHcEvents
explicit Hc2Module();
virtual ~Hc2Module();
- void pullRounding(Hc1Module * partner = nullptr);
- void pushRounding(Hc1Module * partner = nullptr);
void pullCompressor(Hc1Module * partner = nullptr);
void pushCompressor(Hc1Module * partner = nullptr);
void pullTiltEq(Hc1Module * partner = nullptr);
@@ -145,9 +127,9 @@ struct Hc2Module : Module, ISendMidi, IHandleHcEvents
bool readyToSend() override;
// IHandleHcEvents
- void onPresetChanged(const PresetChangedEvent& e) override;
+ //void onPresetChanged(const PresetChangedEvent& e) override;
//void onPedalChanged(const PedalChangedEvent& e) override;
- void onRoundingChanged(const RoundingChangedEvent& e) override;
+ //void onRoundingChanged(const RoundingChangedEvent& e) override;
void onCompressorChanged(const CompressorChangedEvent& e) override;
void onTiltEqChanged(const TiltEqChangedEvent& e) override;
void onDeviceChanged(const DeviceChangedEvent& e) override;
@@ -158,7 +140,6 @@ struct Hc2ModuleWidget : ModuleWidget, IHandleHcEvents
{
Hc2Module* my_module = nullptr;
PartnerPicker* partner_picker = nullptr;
- DynamicTextLabel* rounding_summary = nullptr;
explicit Hc2ModuleWidget(Hc2Module * module);
virtual ~Hc2ModuleWidget() {
@@ -167,14 +148,13 @@ struct Hc2ModuleWidget : ModuleWidget, IHandleHcEvents
// }
}
Hc1Module* getPartner();
- void createRoundingUI(float x, float y);
void createCompressorUI(float x, float y);
void createTiltEqUI(float x, float y);
// IHandleHcEvents
- void onPresetChanged(const PresetChangedEvent& e) override;
+ //void onPresetChanged(const PresetChangedEvent& e) override;
//void onPedalChanged(const PedalChangedEvent& e) override;
- void onRoundingChanged(const RoundingChangedEvent& e) override;
+ //void onRoundingChanged(const RoundingChangedEvent& e) override;
void onDeviceChanged(const DeviceChangedEvent& e) override;
void onDisconnect(const DisconnectEvent& e) override;
diff --git a/src/Pedals/Pedals-ui.cpp b/src/Pedals/Pedals-ui.cpp
index 87498a6..719310b 100644
--- a/src/Pedals/Pedals-ui.cpp
+++ b/src/Pedals/Pedals-ui.cpp
@@ -60,7 +60,7 @@ void PedalUICore::createUI()
/// pedal function knob
float x_center = box.size.x * .5f;
- addChild(pedal_assign = createStaticTextLabel(Vec(x_center, 37.f), 60.f, "Sustain", TextAlignment::Center, 10.f, true));
+ addChild(pedal_assign = createStaticTextLabel(Vec(x_center, 37.f), 60.f, "Sustain", TextAlignment::Center, 9.f, false, GetStockColor(StockColor::Gold)));
addChild(createParamCentered(Vec(x_center, 64.f), module, PedalCore::P_PEDAL_ASSIGN));
// value slider
diff --git a/src/Round/Round-ui.cpp b/src/Round/Round-ui.cpp
new file mode 100644
index 0000000..f3c1a81
--- /dev/null
+++ b/src/Round/Round-ui.cpp
@@ -0,0 +1,127 @@
+#include "Round.hpp"
+#include "../widgets/port.hpp"
+#include "../widgets/cc_param.hpp"
+#include "../widgets/switch_4.hpp"
+#include "../colors.hpp"
+#include "../misc.hpp"
+#include "../text.hpp"
+#include "tuning_ui.hpp"
+
+namespace pachde {
+
+using RP = RoundModule::Params;
+using RI = RoundModule::Inputs;
+using RL = RoundModule::Lights;
+
+constexpr const float REL_OFFSET = 20.f;
+constexpr const float REL_VOFFSET = 10.f;
+constexpr const float CV_COLUMN_OFFSET = 24.f;
+constexpr const float CV_ROW_OFFSET = 6.f;
+constexpr const float STATIC_LABEL_OFFSET = 29.5f;
+constexpr const float KNOB_RADIUS = 12.f;
+constexpr const float HALF_KNOB = KNOB_RADIUS *.5f;
+
+inline uint8_t GetSmallParamValue(rack::app::ModuleWidget* w, int id, uint8_t default_value = 0) {
+ auto p = w->getParam(id);
+ if (!p) return default_value;
+ auto pq = p->getParamQuantity();
+ if (!pq) return default_value;
+ return U8(pq->getValue());
+}
+
+RoundModuleWidget::RoundModuleWidget(RoundModule * module)
+: my_module(module)
+{
+ setModule(module);
+ if (module) {
+ my_module->ui_event_sink = this;
+ }
+ setPanel(createPanel(asset::plugin(pluginInstance, "res/Round.svg")));
+ addChild(partner_picker = createPartnerPicker(7.f, 14.f, 180.f, module ? &module->partner_binding : nullptr));
+
+ float center = box.size.x * .5f;
+
+ // Type
+ float y = 60.f;
+ addParam(createParamCentered(
+ Vec(center, y),
+ module, RP::P_ROUND_KIND));
+ y += 10.f;
+ addChild(type_text = createLazyDynamicTextLabel(
+ Vec(center, y),
+ Vec(100.f, 12.f),
+ [=]() { return describeRoundKind(static_cast(GetSmallParamValue(this, RP::P_ROUND_KIND))); },
+ 9.f, false, TextAlignment::Center,GetStockColor(StockColor::Gold), false));
+
+ // Tuning
+ y = 130.f;
+ auto p = createParamCentered(Vec(center, y), module, RP::P_ROUND_TUNING);
+ p->setImage();
+ addChild(p);
+ y += KNOB_RADIUS + 4.f;
+ addChild(tuning_text = createLazyDynamicTextLabel(
+ Vec(center, y),
+ Vec(100.f, 12.f),
+ [=]() {
+ PackedTuning tuning = static_cast(GetSmallParamValue(this, RP::P_ROUND_TUNING));
+ return describeTuning(unpackTuning(tuning));
+ },
+ 9.f, false, TextAlignment::Center,GetStockColor(StockColor::Gold), false));
+
+ // Initial
+ y = 190.f;
+ addParam(createLightParamCentered>>(
+ Vec(center, y),
+ module, RP::P_ROUND_INITIAL, RL::L_ROUND_INITIAL));
+ y += 16.f;
+ addChild(createInputCentered(
+ Vec(center, y),
+ module, RI::IN_ROUND_INITIAL));
+
+ // Rate
+ y = 265.f;
+ addChild(createModKnob(
+ Vec( center, y),
+ module, RP::P_ROUND_RATE, RI::IN_ROUND_RATE, RP::P_ROUND_RATE_REL));
+ y += 18.f;
+ addParam(createLightParamCentered>>(
+ Vec(center - 14.f, y),
+ module, RP::P_ROUND_RATE_REL, RL::L_ROUND_RATE_REL));
+ y += KNOB_RADIUS;
+ addChild(createInputCentered(
+ Vec( center, y),
+ module, RI::IN_ROUND_RATE));
+
+}
+
+Hc1Module* RoundModuleWidget::getPartner()
+{
+ if (!module) return nullptr;
+ return my_module->getPartner();
+}
+
+
+void RoundModuleWidget::onPresetChanged(const PresetChangedEvent& e)
+{
+ tuning_text->modified();
+ type_text->modified();
+}
+
+void RoundModuleWidget::onRoundingChanged(const RoundingChangedEvent &e)
+{
+ tuning_text->modified();
+ type_text->modified();
+}
+
+void RoundModuleWidget::onDeviceChanged(const DeviceChangedEvent &e)
+{
+ partner_picker->onDeviceChanged(e);
+}
+
+void RoundModuleWidget::onDisconnect(const DisconnectEvent& e)
+{
+ partner_picker->onDisconnect(e);
+}
+
+
+}
\ No newline at end of file
diff --git a/src/Round/Round.cpp b/src/Round/Round.cpp
new file mode 100644
index 0000000..29e7cef
--- /dev/null
+++ b/src/Round/Round.cpp
@@ -0,0 +1,260 @@
+#include "Round.hpp"
+#include "../widgets/cc_param.hpp"
+#include "tuning_ui.hpp"
+
+namespace pachde {
+
+RoundModule::RoundModule()
+{
+ std::vector offon = {"off", "on"};
+ config(Params::NUM_PARAMS, Inputs::NUM_INPUTS, Outputs::NUM_OUTPUTS, Lights::NUM_LIGHTS);
+
+ configInput(Inputs::IN_ROUND_RATE, "Round rate");
+
+ auto p = configCCParam(EMCC_RoundRate, false, this, Params::P_ROUND_RATE, Inputs::IN_ROUND_RATE, Params::P_ROUND_RATE_REL, Lights::L_ROUND_RATE_REL, 0.f, 127.f, 0.f, "Round rate");
+ p->snapEnabled = true;
+ configSwitch(P_ROUND_RATE_REL, 0.f, 1.f, 0.f, "Round rate CV-relative", offon);
+ configSwitch(P_ROUND_INITIAL, 0.f, 1.f, 0.f, "Round initial", offon);
+ configInput(Inputs::IN_ROUND_INITIAL, "Round initial trigger");
+ configSwitch(P_ROUND_KIND, 0.f, 3.f, 0.f, "Round type", {
+ "Normal",
+ "Release",
+ "Y (Full to none)",
+ "Inverse Y (None to full)"
+ });
+ configTuningParam(this, P_ROUND_TUNING);
+}
+
+RoundModule::~RoundModule()
+{
+ if (!partner_subscribed) return;
+ auto partner = partner_binding.getPartner();
+ if (partner){
+ partner->unsubscribeHcEvents(this);
+ partner_subscribed = false;
+ }
+}
+
+json_t * RoundModule::dataToJson()
+{
+ auto root = json_object();
+ json_object_set_new(root, "device", json_string(partner_binding.claim.c_str()));
+ return root;
+}
+
+void RoundModule::dataFromJson(json_t *root)
+{
+ auto j = json_object_get(root, "device");
+ if (j) {
+ partner_binding.setClaim(json_string_value(j));
+ }
+}
+
+Hc1Module* RoundModule::getPartner()
+{
+ return getPartnerImpl(this);
+}
+
+// ISendMidi
+void RoundModule::sendControlChange(uint8_t channel, uint8_t cc, uint8_t value)
+{
+ auto partner = getPartner();
+ if (partner) {
+ partner->sendControlChange(channel, cc, value);
+ }
+}
+//void sendProgramChange(uint8_t channel, uint8_t program) {}
+//void sendKeyPressure(uint8_t channel, uint8_t note, uint8_t pressure) {}
+//void sendChannelPressure(uint8_t channel, uint8_t pressure) {}
+//void sendPitchBend(uint8_t channel, uint8_t bend_lo, uint8_t bend_hi) {}
+bool RoundModule::readyToSend()
+{
+ auto partner = getPartner();
+ return partner && partner->ready();
+}
+
+void RoundModule::onPresetChanged(const PresetChangedEvent &e)
+{
+ pullRounding();
+ if (ui_event_sink) {
+ ui_event_sink->onPresetChanged(e);
+ }
+}
+
+void RoundModule::onRoundingChanged(const RoundingChangedEvent& e)
+{
+ bool changed = false;
+ auto old = rounding;
+ rounding = e.rounding;
+
+ if (old.rate != rounding.rate) {
+ changed = true;
+ auto pq = dynamic_cast(getParamQuantity(Params::P_ROUND_RATE));
+ pq->setValueSilent(rounding.rate);
+ }
+
+ if (old.initial != rounding.initial) {
+ changed = true;
+ getParamQuantity(Params::P_ROUND_INITIAL)->setValue(1.f * rounding.initial);
+ getLight(Lights::L_ROUND_INITIAL).setBrightness(1.0f * rounding.initial);
+ }
+
+ if (old.kind != rounding.kind) {
+ changed = true;
+ getParamQuantity(Params::P_ROUND_KIND)->setValue(static_cast(rounding.kind));
+ }
+ if (old.tuning != rounding.tuning) {
+ changed = true;
+ getParamQuantity(Params::P_ROUND_TUNING)->setValue(packTuning(rounding.tuning));
+ }
+ if (old.equal != rounding.equal) {
+ changed = true;
+ // $BUGBUG: why is this commented out?
+ //getParamQuantity(Params::P_ROUND_EQUAL)->setValue(rounding.equal);
+ }
+
+ if (changed && ui_event_sink) {
+ ui_event_sink->onRoundingChanged(e);
+ }
+}
+
+void RoundModule::onDeviceChanged(const DeviceChangedEvent& e)
+{
+ partner_binding.setClaim(e.device ? e.device->info.spec() : 0);
+ if (ui_event_sink) {
+ ui_event_sink->onDeviceChanged(e);
+ }
+}
+
+void RoundModule::onDisconnect(const DisconnectEvent& e)
+{
+ partner_subscribed = false;
+ partner_binding.forgetModule();
+ if (ui_event_sink) {
+ ui_event_sink->onDisconnect(e);
+ }
+}
+void RoundModule::pullRounding(Hc1Module * partner)
+{
+ if (!partner) partner = getPartner();
+ if (!partner) return;
+ rounding = partner->em.rounding;
+ getParamQuantity(Params::P_ROUND_KIND)->setValue(static_cast(rounding.kind));
+ getParamQuantity(Params::P_ROUND_INITIAL)->setValue(1.f * rounding.initial);
+ getLight(Lights::L_ROUND_INITIAL).setBrightness(1.0f * rounding.initial);
+ dynamic_cast(getParamQuantity(Params::P_ROUND_RATE))->setValueSilent(rounding.rate);
+ getParamQuantity(Params::P_ROUND_TUNING)->setValue(packTuning(rounding.tuning));
+ if (ui_event_sink) {
+ ui_event_sink->onRoundingChanged(RoundingChangedEvent{rounding});
+ }
+}
+
+void RoundModule::processCV(int paramId)
+{
+ auto pq = dynamic_cast(getParamQuantity(paramId));
+ if (!pq) return;
+ if (pq->inputId < 0) return;
+
+ auto in = getInput(pq->inputId);
+
+ bool relative = pq->relativeId >= 0 ? getParam(pq->relativeId).getValue() > .5f : false;
+ if (pq->lightId >= 0) {
+ getLight(pq->lightId).setBrightness((relative *.20f) + ((in.isConnected() && relative) *.80f));
+ }
+
+ if (in.isConnected()) {
+ auto v = in.getVoltage();
+ if (relative) {
+ pq->setRelativeVoltage(v);
+ } else {
+ pq->offset = 0.f;
+ pq->setKnobVoltage(v);
+ }
+ } else {
+ pq->offset = 0.f;
+ }
+}
+
+void RoundModule::pushRounding(Hc1Module * partner)
+{
+ if (!partner) partner = getPartner();
+ if (!partner) return;
+ partner->em.rounding = rounding;
+ if (ui_event_sink) {
+ ui_event_sink->onRoundingChanged(RoundingChangedEvent{rounding});
+ }
+}
+
+void RoundModule::processRoundingControls()
+{
+ {
+ auto pq = dynamic_cast(getParamQuantity(Params::P_ROUND_RATE));
+ assert(pq);
+ auto rr = pq->valueToSend();
+ if (pq->last_value != rr) {
+ rounding.rate = rr;
+ pushRounding();
+ pq->syncValue();
+ }
+ }
+ {
+ bool ri = getParamQuantity(Params::P_ROUND_INITIAL)->getValue() >= .5f;
+ getLight(Lights::L_ROUND_INITIAL).setBrightness(1.0f * rounding.initial);
+ if (rounding.initial != ri) {
+ rounding.initial = ri;
+ pushRounding();
+ sendControlChange(EM_MasterChannel, EMCC_RoundInitial, ri * 127);
+ }
+ }
+
+ {
+ RoundKind kind = static_cast(static_cast(getParamQuantity(P_ROUND_KIND)->getValue()));
+ if (kind != rounding.kind) {
+ rounding.kind = kind;
+ pushRounding();
+ auto partner = getPartner();
+ uint8_t rev = partner ? (partner->em.reverse_surface ? 1 : 0) : 0;
+ sendControlChange(EM_SettingsChannel, EMCC_Reverse_Rounding, (static_cast(kind) << 1) | rev);
+ }
+ }
+
+ {
+ auto tq = dynamic_cast(getParamQuantity(P_ROUND_TUNING));
+ Tuning tuning = tq->getTuning();
+ if (tuning != rounding.tuning) {
+ rounding.tuning = tuning;
+ pushRounding();
+ sendControlChange(EM_SettingsChannel, EMCC_TuningGrid, tuning);
+ }
+ }
+}
+
+void RoundModule::processControls()
+{
+ if (!control_rate.process()) { return; }
+ processRoundingControls();
+}
+
+void RoundModule::process(const ProcessArgs& args)
+{
+ if (++check_cv > CV_INTERVAL) {
+ check_cv = 0;
+ processCV(Params::P_ROUND_RATE);
+ }
+
+ if (getInput(Inputs::IN_ROUND_INITIAL).isConnected()) {
+ auto v = getInput(Inputs::IN_ROUND_INITIAL).getVoltage();
+ if (round_initial_trigger.process(v, 0.1f, 5.f)) {
+ round_initial_trigger.reset();
+ auto pq = getParamQuantity(Params::P_ROUND_INITIAL);
+ bool ri = !(pq->getValue() >= .5f); // toggle
+ pq->setValue(1.0f * ri);
+ }
+ }
+
+ processControls();
+}
+
+}
+
+Model *modelRound = createModel("pachde-hc-round");
\ No newline at end of file
diff --git a/src/Round/Round.hpp b/src/Round/Round.hpp
new file mode 100644
index 0000000..d8a2e3f
--- /dev/null
+++ b/src/Round/Round.hpp
@@ -0,0 +1,121 @@
+#pragma once
+#ifndef ROUND_HPP_INCLUDED
+#define ROUND_HPP_INCLUDED
+#include
+#include "../hc_events.hpp"
+#include "../module_broker.hpp"
+#include "../plugin.hpp"
+#include "../widgets/label_widget.hpp"
+#include "../widgets/partner_picker.hpp"
+#include "../widgets/symbol_widget.hpp"
+
+namespace pachde {
+
+using Symbol = SymbolWidget::Symbol;
+
+
+struct RoundModule : Module, ISendMidi, IHandleHcEvents
+{
+ enum Params
+ {
+ P_ROUND_RATE, // 0..127 cc25
+ P_ROUND_INITIAL, // 0..1 cc 28
+ P_ROUND_KIND, // 0..3 ch16 cc61, but includes reverse surface bit
+ P_ROUND_TUNING, // 0..69
+ P_ROUND_RATE_REL,
+ NUM_PARAMS,
+ };
+ enum Inputs
+ {
+ IN_ROUND_RATE,
+ IN_ROUND_INITIAL,
+ NUM_INPUTS
+ };
+ enum Outputs
+ {
+ NUM_OUTPUTS
+ };
+ enum Lights
+ {
+ L_ROUND_RATE_REL,
+ L_ROUND_INITIAL,
+ NUM_LIGHTS
+ };
+
+ Rounding rounding;
+
+ PartnerBinding partner_binding;
+ bool partner_subscribed = false;
+
+ IHandleHcEvents * ui_event_sink = nullptr;
+ const int CV_INTERVAL = 128;
+ int check_cv = 0;
+ RateTrigger control_rate;
+ rack::dsp::SchmittTrigger round_initial_trigger;
+
+ void pullRounding(Hc1Module * partner = nullptr);
+ void pushRounding(Hc1Module * partner = nullptr);
+ void processCV(int paramId);
+ void processRoundingControls();
+ void processControls();
+
+ RoundModule();
+ virtual ~RoundModule();
+ Hc1Module * getPartner();
+
+ // ISendMidi
+ //virtual void sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) {}
+ //virtual void sendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity) {}
+ void sendControlChange(uint8_t channel, uint8_t cc, uint8_t value) override;
+ //void sendProgramChange(uint8_t channel, uint8_t program) {}
+ //void sendKeyPressure(uint8_t channel, uint8_t note, uint8_t pressure) {}
+ //void sendChannelPressure(uint8_t channel, uint8_t pressure) {}
+ //void sendPitchBend(uint8_t channel, uint8_t bend_lo, uint8_t bend_hi) {}
+ bool readyToSend() override;
+
+ // IHandleHcEvents
+ void onPresetChanged(const PresetChangedEvent& e) override;
+ void onRoundingChanged(const RoundingChangedEvent& e) override;
+ // void onPedalChanged(const PedalChangedEvent& e) override;
+ void onDeviceChanged(const DeviceChangedEvent& e) override;
+ void onDisconnect(const DisconnectEvent& e) override;
+ // void onFavoritesFileChanged(const FavoritesFileChangedEvent& e) override;
+
+ // Module
+ void onSampleRateChange(const SampleRateChangeEvent& e) override {
+ control_rate.onSampleRateChanged(e);
+ }
+ json_t *dataToJson() override;
+ void dataFromJson(json_t *root) override;
+ void process(const ProcessArgs& args) override;
+};
+
+
+struct RoundModuleWidget : ModuleWidget, IHandleHcEvents
+{
+ RoundModule * my_module;
+ PartnerPicker* partner_picker = nullptr;
+
+ DynamicTextLabel* tuning_text = nullptr;
+ DynamicTextLabel* type_text = nullptr;
+
+ explicit RoundModuleWidget(RoundModule * module);
+ virtual ~RoundModuleWidget() {
+ if (my_module) {
+ my_module->ui_event_sink = nullptr;
+ }
+ }
+
+ Hc1Module * getPartner();
+
+ // IHandleHcEvents
+ void onPresetChanged(const PresetChangedEvent& e) override;
+ void onRoundingChanged(const RoundingChangedEvent& e) override;
+ void onDeviceChanged(const DeviceChangedEvent& e) override;
+ void onDisconnect(const DisconnectEvent& e) override;
+ // void onFavoritesFileChanged(const FavoritesFileChangedEvent& e) override;
+
+};
+
+}
+#endif
\ No newline at end of file
diff --git a/src/HC-2/tuning_ui.hpp b/src/Round/tuning_ui.hpp
similarity index 99%
rename from src/HC-2/tuning_ui.hpp
rename to src/Round/tuning_ui.hpp
index 33feb80..54470cd 100644
--- a/src/HC-2/tuning_ui.hpp
+++ b/src/Round/tuning_ui.hpp
@@ -2,7 +2,6 @@
#ifndef TUNING_UI_HPP_INCLUDED
#define TUNING_UI_HPP_INCLUDED
#include
-#include "HC-2.hpp"
#include "../em.hpp"
using namespace ::rack;
namespace pachde {
diff --git a/src/em_types/em_rounding.cpp b/src/em_types/em_rounding.cpp
index 37ea810..eb5a11b 100644
--- a/src/em_types/em_rounding.cpp
+++ b/src/em_types/em_rounding.cpp
@@ -8,8 +8,8 @@ std::string describeRoundKind(RoundKind kind)
switch (kind) {
case RoundKind::Normal: return "Normal";
case RoundKind::Release: return "Release";
- case RoundKind::Y: return "Y (Full to none)";
- case RoundKind::InverseY: return "Inverse Y (None to full)";
+ case RoundKind::Y: return "Y";
+ case RoundKind::InverseY: return "Inverse Y";
}
return "?";
}
diff --git a/src/plugin.cpp b/src/plugin.cpp
index 779a57e..8cd5f9e 100644
--- a/src/plugin.cpp
+++ b/src/plugin.cpp
@@ -8,9 +8,10 @@ void init(Plugin *p)
p->addModel(modelHc1);
p->addModel(modelHc2);
p->addModel(modelHc3);
- p->addModel(modelHc4);
+ //p->addModel(modelHc4);
p->addModel(modelPedal1);
p->addModel(modelPedal2);
+ p->addModel(modelRound);
// Any other plugin initialization may go here.
// As an alternative, consider lazy-loading assets and lookup tables when your module is created to reduce startup times of Rack.
diff --git a/src/plugin.hpp b/src/plugin.hpp
index cd31d25..1f4ed5f 100644
--- a/src/plugin.hpp
+++ b/src/plugin.hpp
@@ -6,7 +6,8 @@ extern Plugin* pluginInstance;
extern Model* modelHc1;
extern Model* modelHc2;
extern Model* modelHc3;
-extern Model* modelHc4;
+//extern Model* modelHc4;
extern Model* modelPedal1;
extern Model* modelPedal2;
+extern Model* modelRound;