commit b6e8be4b86475050344a62ffbf1be8254a0fbcb4
parent 7b9781d54d2dbfa191ac4a226fb65794ffd0b170
Author: Matt Demanett <matt@demanett.net>
Date: Wed, 25 Mar 2020 22:27:00 -0400
Base classes and test modules for expanders.
Diffstat:
9 files changed, 425 insertions(+), 3 deletions(-)
diff --git a/res-src/TestExpanderBase-src.svg b/res-src/TestExpanderBase-src.svg
@@ -0,0 +1,77 @@
+<svg
+ version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="45"
+ height="380"
+ viewBox="0 0 45 380"
+>
+ <style>
+ text {
+ fill: #333;
+ font-family: 'Roboto', sans-serif;
+ font-weight: bold;
+ }
+ text.title {
+ font-family: 'Comfortaa', sans-serif;
+ font-weight: normal;
+ }
+ text.brand {
+ font-family: 'Audiowide', sans-serif;
+ font-weight: bold;
+ }
+ </style>
+
+ <defs>
+ <symbol id="input" viewBox="0 0 24px 24px">
+ <g transform="translate(12 12)">
+ <circle cx="0" cy="0" r="5" stroke-width="1" stroke="#0f0" fill="#0f0" />
+ <circle cx="0" cy="0" r="10.5" stroke-width="3" stroke="#0f0" fill="none" />
+ </g>
+ </symbol>
+
+ <symbol id="output" viewBox="0 0 24px 24px">
+ <g transform="translate(12 12)">
+ <circle cx="0" cy="0" r="5" stroke-width="1" stroke="#f00" fill="#f00" />
+ <circle cx="0" cy="0" r="10.5" stroke-width="3" stroke="#f00" fill="none" />
+ </g>
+ </symbol>
+
+ <symbol id="light-small" viewBox="0 0 6.4px 6.4px">
+ <rect width="6.4" height="6.4" fill="#0f0" />
+ </symbol>
+ </defs>
+
+ <rect width="100%" height="100%" fill="#ddd" />
+ <polyline points="1,1 44,1 44,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" />
+ <polyline points="0.5,0.5 44.5,0.5 44.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" />
+ <polyline points="0,0 45,0 45,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" />
+
+ <g transform="rotate(-90) translate(-376 13)">
+ <text class="title" font-size="7pt" letter-spacing="2.5px">TEB</text>
+ <g transform="translate(0 12)">
+ <text class="brand" font-size="7pt" letter-spacing="2px">BGA</text>
+ <rect width="3.0" height="3" fill="#ddd" transform="translate(11.5 -5)" />
+ </g>
+ </g>
+
+ <g transform="translate(0 245)">
+ <use id="COM_LIGHT" xlink:href="#light-small" transform="translate(10 0.5)" />
+ <text font-size="5pt" letter-spacing="1px" transform="translate(19 6)">COM</text>
+ </g>
+
+ <g transform="translate(0 260)">
+ <g transform="translate(5.5 0)">
+ <rect width="34" height="10" fill="#fafafa" transform="translate(0 28)" />
+ <rect width="34" height="35" rx="5" fill="#fafafa" />
+ <use id="IN_INPUT" xlink:href="#input" transform="translate(5 3)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(12.5 35)">IN</text>
+ </g>
+ <g transform="translate(5.5 41)">
+ <rect width="34" height="10" fill="#bbb" transform="translate(0 -3)" />
+ <rect width="34" height="35" rx="5" fill="#bbb" />
+ <use id="OUT_OUTPUT" xlink:href="#output" transform="translate(5 0)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(8.3 32)">OUT</text>
+ </g>
+ </g>
+</svg>
diff --git a/res-src/TestExpanderExtension-src.svg b/res-src/TestExpanderExtension-src.svg
@@ -0,0 +1,63 @@
+<svg
+ version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="45"
+ height="380"
+ viewBox="0 0 45 380"
+>
+ <style>
+ text {
+ fill: #333;
+ font-family: 'Roboto', sans-serif;
+ font-weight: bold;
+ }
+ text.title {
+ font-family: 'Comfortaa', sans-serif;
+ font-weight: normal;
+ }
+ text.brand {
+ font-family: 'Audiowide', sans-serif;
+ font-weight: bold;
+ }
+ </style>
+
+ <defs>
+ <symbol id="output" viewBox="0 0 24px 24px">
+ <g transform="translate(12 12)">
+ <circle cx="0" cy="0" r="5" stroke-width="1" stroke="#f00" fill="#f00" />
+ <circle cx="0" cy="0" r="10.5" stroke-width="3" stroke="#f00" fill="none" />
+ </g>
+ </symbol>
+
+ <symbol id="light-small" viewBox="0 0 6.4px 6.4px">
+ <rect width="6.4" height="6.4" fill="#0f0" />
+ </symbol>
+ </defs>
+
+ <rect width="100%" height="100%" fill="#ddd" />
+ <polyline points="1,1 44,1 44,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" />
+ <polyline points="0.5,0.5 44.5,0.5 44.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" />
+ <polyline points="0,0 45,0 45,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" />
+
+ <g transform="rotate(-90) translate(-376 13)">
+ <text class="title" font-size="7pt" letter-spacing="2.5px">TEE</text>
+ <g transform="translate(0 12)">
+ <text class="brand" font-size="7pt" letter-spacing="2px">BGA</text>
+ <rect width="3.0" height="3" fill="#ddd" transform="translate(11.5 -5)" />
+ </g>
+ </g>
+
+ <g transform="translate(0 280)">
+ <use id="COM_LIGHT" xlink:href="#light-small" transform="translate(10 0.5)" />
+ <text font-size="5pt" letter-spacing="1px" transform="translate(19 6)">COM</text>
+ </g>
+
+ <g transform="translate(0 260)">
+ <g transform="translate(5.5 41)">
+ <rect width="34" height="38" rx="5" fill="#bbb" transform="translate(0 -3)"/>
+ <use id="OUT_OUTPUT" xlink:href="#output" transform="translate(5 0)" />
+ <text font-size="5pt" letter-spacing="2px" transform="translate(8.3 32)">OUT</text>
+ </g>
+ </g>
+</svg>
diff --git a/res/TestExpanderBase.svg b/res/TestExpanderBase.svg
Binary files differ.
diff --git a/res/TestExpanderExtension.svg b/res/TestExpanderExtension.svg
Binary files differ.
diff --git a/src/TestExpander.cpp b/src/TestExpander.cpp
@@ -0,0 +1,104 @@
+
+#include "TestExpander.hpp"
+
+int TestExpanderBase::channels() {
+ return inputs[IN_INPUT].getChannels();
+}
+
+void TestExpanderBase::processAll(const ProcessArgs& args) {
+ outputs[OUT_OUTPUT].setChannels(_channels);
+ lights[COM_LIGHT].value = connected();
+}
+
+void TestExpanderBase::processChannel(const ProcessArgs& args, int c) {
+ if (connected()) {
+ toExpander()->sample[c] = inputs[IN_INPUT].getPolyVoltage(c);
+ outputs[OUT_OUTPUT].setVoltage(fromExpander()->sample[c], c);
+ }
+ else {
+ outputs[OUT_OUTPUT].setVoltage(inputs[IN_INPUT].getPolyVoltage(c), c);
+ }
+}
+
+struct TestExpanderBaseWidget : ModuleWidget {
+ static constexpr int hp = 3;
+
+ TestExpanderBaseWidget(TestExpanderBase* module) {
+ setModule(module);
+ box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
+
+ {
+ SvgPanel *panel = new SvgPanel();
+ panel->box.size = box.size;
+ panel->setBackground(APP->window->loadSvg(asset::plugin(pluginInstance, "res/TestExpanderBase.svg")));
+ addChild(panel);
+ }
+
+ addChild(createWidget<ScrewSilver>(Vec(0, 0)));
+ addChild(createWidget<ScrewSilver>(Vec(box.size.x - 15, 365)));
+
+ // generated by svg_widgets.rb
+ auto inInputPosition = Vec(10.5, 263.0);
+
+ auto outOutputPosition = Vec(10.5, 301.0);
+
+ auto comLightPosition = Vec(10.0, 245.5);
+ // end generated by svg_widgets.rb
+
+ addInput(createInput<Port24>(inInputPosition, module, TestExpanderBase::IN_INPUT));
+
+ addOutput(createOutput<Port24>(outOutputPosition, module, TestExpanderBase::OUT_OUTPUT));
+
+ addChild(createLight<SmallLight<GreenLight>>(comLightPosition, module, TestExpanderBase::COM_LIGHT));
+ }
+};
+
+Model* modelTestExpanderBase = createModel<TestExpanderBase, TestExpanderBaseWidget>("Bogaudio-TestExpanderBase", "TEB", "expanders test base module");
+
+
+void TestExpanderExtension::processAll(const ProcessArgs& args) {
+ outputs[OUT_OUTPUT].setChannels(_channels);
+ lights[COM_LIGHT].value = connected();
+}
+
+void TestExpanderExtension::processChannel(const ProcessArgs& args, int c) {
+ if (connected()) {
+ float sample = fromBase()->sample[c];
+ toBase()->sample[c] = -sample;
+ outputs[OUT_OUTPUT].setVoltage(sample, c);
+ }
+ else {
+ outputs[OUT_OUTPUT].setVoltage(0.0f, c);
+ }
+}
+
+struct TestExpanderExtensionWidget : ModuleWidget {
+ static constexpr int hp = 3;
+
+ TestExpanderExtensionWidget(TestExpanderExtension* module) {
+ setModule(module);
+ box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
+
+ {
+ SvgPanel *panel = new SvgPanel();
+ panel->box.size = box.size;
+ panel->setBackground(APP->window->loadSvg(asset::plugin(pluginInstance, "res/TestExpanderExtension.svg")));
+ addChild(panel);
+ }
+
+ addChild(createWidget<ScrewSilver>(Vec(0, 0)));
+ addChild(createWidget<ScrewSilver>(Vec(box.size.x - 15, 365)));
+
+ // generated by svg_widgets.rb
+ auto outOutputPosition = Vec(10.5, 301.0);
+
+ auto comLightPosition = Vec(10.0, 280.5);
+ // end generated by svg_widgets.rb
+
+ addOutput(createOutput<Port24>(outOutputPosition, module, TestExpanderExtension::OUT_OUTPUT));
+
+ addChild(createLight<SmallLight<GreenLight>>(comLightPosition, module, TestExpanderExtension::COM_LIGHT));
+ }
+};
+
+Model* modelTestExpanderExtension = createModel<TestExpanderExtension, TestExpanderExtensionWidget>("Bogaudio-TestExpanderExtension", "TEE", "expanders test expander module");
diff --git a/src/TestExpander.hpp b/src/TestExpander.hpp
@@ -0,0 +1,74 @@
+#pragma once
+
+#include "bogaudio.hpp"
+#include "expanders.hpp"
+
+extern Model* modelTestExpanderBase;
+extern Model* modelTestExpanderExtension;
+
+namespace bogaudio {
+
+struct TestExpanderMessage : MessageBase {
+ int channels = 0;
+ float sample[BGModule::maxChannels] {};
+};
+
+struct TestExpanderExtension;
+
+struct TestExpanderBase : ExpandableModule<TestExpanderMessage, TestExpanderExtension> {
+ enum ParamsIds {
+ NUM_PARAMS
+ };
+
+ enum InputsIds {
+ IN_INPUT,
+ NUM_INPUTS
+ };
+
+ enum OutputsIds {
+ OUT_OUTPUT,
+ NUM_OUTPUTS
+ };
+
+ enum LightsIds {
+ COM_LIGHT,
+ NUM_LIGHTS
+ };
+
+ TestExpanderBase() {
+ config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
+ }
+
+ int channels() override;
+ void processAll(const ProcessArgs& args) override;
+ void processChannel(const ProcessArgs& args, int c) override;
+};
+
+struct TestExpanderExtension : ExpanderModule<TestExpanderMessage, TestExpanderBase> {
+ enum ParamsIds {
+ NUM_PARAMS
+ };
+
+ enum InputsIds {
+ NUM_INPUTS
+ };
+
+ enum OutputsIds {
+ OUT_OUTPUT,
+ NUM_OUTPUTS
+ };
+
+ enum LightsIds {
+ COM_LIGHT,
+ NUM_LIGHTS
+ };
+
+ TestExpanderExtension() {
+ config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
+ }
+
+ void processAll(const ProcessArgs& args) override;
+ void processChannel(const ProcessArgs& args, int c) override;
+};
+
+} // namespace bogaudio
diff --git a/src/bogaudio.cpp b/src/bogaudio.cpp
@@ -81,6 +81,7 @@
#include "Test.hpp"
#include "Test2.hpp"
+#include "TestExpander.hpp"
#include "TestVCF.hpp"
#include "template_panels.hpp"
@@ -188,6 +189,8 @@ void init(rack::Plugin *p) {
#ifdef TEST
p->addModel(modelTest);
p->addModel(modelTest2);
+ p->addModel(modelTestExpanderBase);
+ p->addModel(modelTestExpanderExtension);
p->addModel(modelTestVCF);
p->addModel(modelThreeHP);
diff --git a/src/expanders.hpp b/src/expanders.hpp
@@ -0,0 +1,101 @@
+#pragma once
+
+#include <type_traits>
+
+#include "rack.hpp"
+#include "module.hpp"
+
+using namespace rack;
+
+namespace bogaudio {
+
+struct MessageBase {
+ int channels = 0;
+
+ virtual ~MessageBase() {}
+};
+
+template<class MSG, class EM>
+struct ExpandableModule : BGModule {
+ MSG _messages[2] {};
+
+ ExpandableModule() {
+ static_assert(std::is_base_of<MessageBase, MSG>::value, "type parameter MSG must derive from MessageBase");
+
+ rightExpander.producerMessage = &_messages[0];
+ rightExpander.consumerMessage = &_messages[1];
+ }
+
+ inline bool connected() {
+ return rightExpander.module && dynamic_cast<EM*>(rightExpander.module);
+ }
+
+ inline MSG* toExpander() {
+ assert(connected());
+ MSG* m = (MSG*)rightExpander.module->leftExpander.producerMessage;
+ assert(m);
+ m->channels = _channels;
+ return m;
+ }
+
+ inline MSG* fromExpander() {
+ assert(connected());
+ MSG* m = (MSG*)rightExpander.consumerMessage;
+ assert(m);
+ return m;
+ }
+
+ void process(const ProcessArgs& args) override {
+ BGModule::process(args);
+ if (rightExpander.module) {
+ rightExpander.module->leftExpander.messageFlipRequested = true;
+ }
+ }
+};
+
+// An expander must be to the right of the expanded module to work.
+template<class MSG, class BM>
+struct ExpanderModule : BGModule {
+ MSG _messages[2] {};
+
+ ExpanderModule() {
+ static_assert(std::is_base_of<MessageBase, MSG>::value, "type parameter MSG must derive from MessageBase");
+
+ leftExpander.producerMessage = &_messages[0];
+ leftExpander.consumerMessage = &_messages[1];
+ }
+
+ inline bool connected() {
+ return leftExpander.module && dynamic_cast<BM*>(leftExpander.module);
+ }
+
+ inline MSG* fromBase() {
+ assert(connected());
+ MSG* m = (MSG*)leftExpander.consumerMessage;
+ assert(m);
+ return m;
+ }
+
+ inline MSG* toBase() {
+ assert(connected());
+ MSG* m = (MSG*)leftExpander.module->rightExpander.producerMessage;
+ assert(m);
+ return m;
+ }
+
+ int channels() override final {
+ if (connected()) {
+ return fromBase()->channels;
+ }
+ return 1;
+ }
+
+ void process(const ProcessArgs& args) override {
+ BGModule::process(args);
+ if (leftExpander.module) {
+ leftExpander.module->rightExpander.messageFlipRequested = true;
+ }
+ }
+};
+
+} // namespace bogaudio
diff --git a/src/module.hpp b/src/module.hpp
@@ -22,9 +22,9 @@ struct BGModule : Module {
}
}
- void onReset() override final;
- void onSampleRateChange() override final;
- void process(const ProcessArgs& args) override final;
+ void onReset() override;
+ void onSampleRateChange() override;
+ void process(const ProcessArgs& args) override;
virtual void reset() {}
virtual void sampleRateChange() {}