BogaudioModules

BogaudioModules for VCV Rack
Log | Files | Refs | README | LICENSE

commit fe0d05f7dd38737381b45cd42519b6af21e54840
parent 0b877235a79c4b0eeaf249cceffbfa118cee7a62
Author: Matt Demanett <matt@demanett.net>
Date:   Sat, 11 Apr 2020 02:13:27 -0400

PGMR: performance improvements; better performance for expandable/expander modules generally. #107

Diffstat:
Msrc/Mix4.hpp | 8++++++--
Msrc/Mix8.hpp | 8++++++--
Msrc/Pgmr.cpp | 8++++----
Msrc/Pgmr.hpp | 13++++++++++---
Msrc/TestExpander.hpp | 6++++--
Msrc/expanders.hpp | 52+++++++++++++++++++++++++++-------------------------
Msrc/utils.hpp | 15+++++++++++++++
7 files changed, 72 insertions(+), 38 deletions(-)

diff --git a/src/Mix4.hpp b/src/Mix4.hpp @@ -15,7 +15,7 @@ struct Mix4x; typedef MixerExpanderMessage<4> Mix4ExpanderMessage; -struct Mix4 : ExpandableModule<Mix4ExpanderMessage, Mix4x, BGModule> { +struct Mix4 : ExpandableModule<Mix4ExpanderMessage, BGModule> { enum ParamsIds { LEVEL1_PARAM, PAN1_PARAM, @@ -90,8 +90,10 @@ struct Mix4 : ExpandableModule<Mix4ExpanderMessage, Mix4x, BGModule> { _channels[1] = new MixerChannel(params[LEVEL2_PARAM], params[MUTE2_PARAM], inputs[CV2_INPUT]); _channels[2] = new MixerChannel(params[LEVEL3_PARAM], params[MUTE3_PARAM], inputs[CV3_INPUT]); _channels[3] = new MixerChannel(params[LEVEL4_PARAM], params[MUTE4_PARAM], inputs[CV4_INPUT]); + sampleRateChange(); _rms.setSensitivity(0.05f); + setExpanderModel(modelMix4x); } virtual ~Mix4() { for (int i = 0; i < 4; ++i) { @@ -105,7 +107,7 @@ struct Mix4 : ExpandableModule<Mix4ExpanderMessage, Mix4x, BGModule> { void processAll(const ProcessArgs& args) override; }; -struct Mix4x : ExpanderModule<Mix4ExpanderMessage, Mix4, BGModule> { +struct Mix4x : ExpanderModule<Mix4ExpanderMessage, BGModule> { enum ParamsIds { LOW1_PARAM, MID1_PARAM, @@ -205,6 +207,8 @@ struct Mix4x : ExpanderModule<Mix4ExpanderMessage, Mix4, BGModule> { _channels[1] = new MixerExpanderChannel(params[LOW2_PARAM], params[MID2_PARAM], params[HIGH2_PARAM], params[A2_PARAM], params[B2_PARAM], params[PRE_A2_PARAM], params[PRE_B2_PARAM], inputs[A2_INPUT], inputs[B2_INPUT]); _channels[2] = new MixerExpanderChannel(params[LOW3_PARAM], params[MID3_PARAM], params[HIGH3_PARAM], params[A3_PARAM], params[B3_PARAM], params[PRE_A3_PARAM], params[PRE_B3_PARAM], inputs[A3_INPUT], inputs[B3_INPUT]); _channels[3] = new MixerExpanderChannel(params[LOW4_PARAM], params[MID4_PARAM], params[HIGH4_PARAM], params[A4_PARAM], params[B4_PARAM], params[PRE_A4_PARAM], params[PRE_B4_PARAM], inputs[A4_INPUT], inputs[B4_INPUT]); + + setBaseModel(modelMix4); } virtual ~Mix4x() { for (int i = 0; i < 4; ++i) { diff --git a/src/Mix8.hpp b/src/Mix8.hpp @@ -15,7 +15,7 @@ struct Mix8x; typedef MixerExpanderMessage<8> Mix8ExpanderMessage; -struct Mix8 : ExpandableModule<Mix8ExpanderMessage, Mix8x, BGModule> { +struct Mix8 : ExpandableModule<Mix8ExpanderMessage, BGModule> { enum ParamsIds { LEVEL1_PARAM, MUTE1_PARAM, @@ -130,8 +130,10 @@ struct Mix8 : ExpandableModule<Mix8ExpanderMessage, Mix8x, BGModule> { _channels[5] = new MixerChannel(params[LEVEL6_PARAM], params[MUTE6_PARAM], inputs[CV6_INPUT]); _channels[6] = new MixerChannel(params[LEVEL7_PARAM], params[MUTE7_PARAM], inputs[CV7_INPUT]); _channels[7] = new MixerChannel(params[LEVEL8_PARAM], params[MUTE8_PARAM], inputs[CV8_INPUT]); + sampleRateChange(); _rms.setSensitivity(0.05f); + setExpanderModel(modelMix8x); } virtual ~Mix8() { for (int i = 0; i < 8; ++i) { @@ -145,7 +147,7 @@ struct Mix8 : ExpandableModule<Mix8ExpanderMessage, Mix8x, BGModule> { void processAll(const ProcessArgs& args) override; }; -struct Mix8x : ExpanderModule<Mix8ExpanderMessage, Mix8, BGModule> { +struct Mix8x : ExpanderModule<Mix8ExpanderMessage, BGModule> { enum ParamsIds { LOW1_PARAM, MID1_PARAM, @@ -313,6 +315,8 @@ struct Mix8x : ExpanderModule<Mix8ExpanderMessage, Mix8, BGModule> { _channels[5] = new MixerExpanderChannel(params[LOW6_PARAM], params[MID6_PARAM], params[HIGH6_PARAM], params[A6_PARAM], params[B6_PARAM], params[PRE_A6_PARAM], params[PRE_B6_PARAM], inputs[A6_INPUT], inputs[B6_INPUT]); _channels[6] = new MixerExpanderChannel(params[LOW7_PARAM], params[MID7_PARAM], params[HIGH7_PARAM], params[A7_PARAM], params[B7_PARAM], params[PRE_A7_PARAM], params[PRE_B7_PARAM], inputs[A7_INPUT], inputs[B7_INPUT]); _channels[7] = new MixerExpanderChannel(params[LOW8_PARAM], params[MID8_PARAM], params[HIGH8_PARAM], params[A8_PARAM], params[B8_PARAM], params[PRE_A8_PARAM], params[PRE_B8_PARAM], inputs[A8_INPUT], inputs[B8_INPUT]); + + setBaseModel(modelMix8); } virtual ~Mix8x() { for (int i = 0; i < 8; ++i) { diff --git a/src/Pgmr.cpp b/src/Pgmr.cpp @@ -80,7 +80,7 @@ PgmrRegistry& PgmrRegistry::registry() { void Pgmr::reset() { - std::lock_guard<std::mutex> lock(_stepsLock); + std::lock_guard<SpinLock> lock(_stepsLock); for (int c = 0; c < maxChannels; ++c) { _lastSteps[c] = -1; @@ -124,7 +124,7 @@ void Pgmr::processAlways(const ProcessArgs& args) { } void Pgmr::processChannel(const ProcessArgs& args, int c) { - std::lock_guard<std::mutex> lock(_stepsLock); + std::lock_guard<SpinLock> lock(_stepsLock); int steps = _steps.size(); if (c == 0) { for (int i = 0, n = _steps.size(); i < n; ++i) { @@ -200,7 +200,7 @@ void Pgmr::processChannel(const ProcessArgs& args, int c) { } void Pgmr::setSteps(std::vector<PgmrStep*>& steps) { - std::lock_guard<std::mutex> lock(_stepsLock); + std::lock_guard<SpinLock> lock(_stepsLock); _steps = steps; } @@ -342,7 +342,7 @@ struct PgmrWidget : AddressableSequenceBaseModuleWidget { mi->addItem(RangeOptionMenuItem(m, "+/-1V", 0.0f, 1.0f)); OptionsMenuItem::addToMenu(mi, menu); - OptionsMenuItem* so = new OptionsMenuItem("Step-selected output"); + OptionsMenuItem* so = new OptionsMenuItem("Output on selected step"); so->addItem(OptionMenuItem("Gate", [m]() { return !m->_selectTriggers; }, [m]() { m->_selectTriggers = false; })); so->addItem(OptionMenuItem("Trigger", [m]() { return m->_selectTriggers; }, [m]() { m->_selectTriggers = true; })); OptionsMenuItem::addToMenu(so, menu); diff --git a/src/Pgmr.hpp b/src/Pgmr.hpp @@ -94,7 +94,7 @@ public: static PgmrRegistry& registry(); }; -struct Pgmr : ExpandableModule<PgmrExpanderMessage, PgmrX, OutputRangeAddressableSequenceModule>, PgmrBase { +struct Pgmr : ExpandableModule<PgmrExpanderMessage, OutputRangeAddressableSequenceModule>, PgmrBase { enum ParamsIds { DIRECTION_PARAM, SELECT_ON_CLOCK_PARAM, @@ -154,7 +154,7 @@ struct Pgmr : ExpandableModule<PgmrExpanderMessage, PgmrX, OutputRangeAddressabl float _sampleTime = 0.001f; bool _selectTriggers = false; - std::mutex _stepsLock; + SpinLock _stepsLock; std::vector<PgmrStep*> _steps; int _lastSteps[maxChannels] {}; rack::dsp::PulseGenerator _allPulseGens[maxChannels]; @@ -190,6 +190,8 @@ struct Pgmr : ExpandableModule<PgmrExpanderMessage, PgmrX, OutputRangeAddressabl _localSteps[1] = new PgmrStep(params[CVA2_PARAM], params[CVB2_PARAM], params[CVC2_PARAM], params[CVD2_PARAM], lights[SELECT2_LIGHT], params[SELECT2_PARAM], inputs[SELECT2_INPUT], outputs[SELECT2_OUTPUT]); _localSteps[2] = new PgmrStep(params[CVA3_PARAM], params[CVB3_PARAM], params[CVC3_PARAM], params[CVD3_PARAM], lights[SELECT3_LIGHT], params[SELECT3_PARAM], inputs[SELECT3_INPUT], outputs[SELECT3_OUTPUT]); _localSteps[3] = new PgmrStep(params[CVA4_PARAM], params[CVB4_PARAM], params[CVC4_PARAM], params[CVD4_PARAM], lights[SELECT4_LIGHT], params[SELECT4_PARAM], inputs[SELECT4_INPUT], outputs[SELECT4_OUTPUT]); + + setExpanderModel(modelPgmrX); _id = PgmrRegistry::registry().registerBase(*this); } virtual ~Pgmr() { @@ -206,7 +208,7 @@ struct Pgmr : ExpandableModule<PgmrExpanderMessage, PgmrX, OutputRangeAddressabl void setSteps(std::vector<PgmrStep*>& steps); }; -struct PgmrX : ExpanderModule<PgmrExpanderMessage, PgmrBase, ExpandableModule<PgmrExpanderMessage, PgmrX, BGModule>>, PgmrBase { +struct PgmrX : ExpanderModule<PgmrExpanderMessage, ExpandableModule<PgmrExpanderMessage, BGModule>>, PgmrBase { enum ParamsIds { CVA1_PARAM, CVB1_PARAM, @@ -288,10 +290,15 @@ struct PgmrX : ExpanderModule<PgmrExpanderMessage, PgmrBase, ExpandableModule<Pg configParam<OutputParamQuantity>(CVC4_PARAM, -1.0f, 1.0f, 0.0f, "Step 4C", " V"); configParam<OutputParamQuantity>(CVD4_PARAM, -1.0f, 1.0f, 0.0f, "Step 4D", " V"); configParam<OutputParamQuantity>(SELECT4_PARAM, 0.0f, 1.0f, 0.0f, "Select 4"); + _localSteps[0] = new PgmrStep(params[CVA1_PARAM], params[CVB1_PARAM], params[CVC1_PARAM], params[CVD1_PARAM], lights[SELECT1_LIGHT], params[SELECT1_PARAM], inputs[SELECT1_INPUT], outputs[SELECT1_OUTPUT]); _localSteps[1] = new PgmrStep(params[CVA2_PARAM], params[CVB2_PARAM], params[CVC2_PARAM], params[CVD2_PARAM], lights[SELECT2_LIGHT], params[SELECT2_PARAM], inputs[SELECT2_INPUT], outputs[SELECT2_OUTPUT]); _localSteps[2] = new PgmrStep(params[CVA3_PARAM], params[CVB3_PARAM], params[CVC3_PARAM], params[CVD3_PARAM], lights[SELECT3_LIGHT], params[SELECT3_PARAM], inputs[SELECT3_INPUT], outputs[SELECT3_OUTPUT]); _localSteps[3] = new PgmrStep(params[CVA4_PARAM], params[CVB4_PARAM], params[CVC4_PARAM], params[CVD4_PARAM], lights[SELECT4_LIGHT], params[SELECT4_PARAM], inputs[SELECT4_INPUT], outputs[SELECT4_OUTPUT]); + + setBaseModel(modelPgmr); + setChainableModel(modelPgmrX); + setExpanderModel(modelPgmrX); } virtual ~PgmrX() { PgmrRegistry::registry().deregisterExpander(_baseID, _position); diff --git a/src/TestExpander.hpp b/src/TestExpander.hpp @@ -14,7 +14,7 @@ struct TestExpanderMessage : ExpanderMessage { struct TestExpanderExtension; -struct TestExpanderBase : ExpandableModule<TestExpanderMessage, TestExpanderExtension, BGModule> { +struct TestExpanderBase : ExpandableModule<TestExpanderMessage, BGModule> { enum ParamsIds { NUM_PARAMS }; @@ -36,6 +36,7 @@ struct TestExpanderBase : ExpandableModule<TestExpanderMessage, TestExpanderExte TestExpanderBase() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + setExpanderModel(modelTestExpanderExtension); } int channels() override; @@ -43,7 +44,7 @@ struct TestExpanderBase : ExpandableModule<TestExpanderMessage, TestExpanderExte void processChannel(const ProcessArgs& args, int c) override; }; -struct TestExpanderExtension : ExpanderModule<TestExpanderMessage, TestExpanderBase, BGModule> { +struct TestExpanderExtension : ExpanderModule<TestExpanderMessage, BGModule> { enum ParamsIds { NUM_PARAMS }; @@ -64,6 +65,7 @@ struct TestExpanderExtension : ExpanderModule<TestExpanderMessage, TestExpanderB TestExpanderExtension() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + setBaseModel(modelTestExpanderBase); } void processAll(const ProcessArgs& args) override; diff --git a/src/expanders.hpp b/src/expanders.hpp @@ -15,8 +15,9 @@ struct ExpanderMessage { virtual ~ExpanderMessage() {} }; -template<class MSG, class EM, class BASE> +template<class MSG, class BASE> struct ExpandableModule : BASE { + Model* _expanderModel = NULL; MSG _messages[2] {}; bool _wasConnected = false; @@ -28,27 +29,24 @@ struct ExpandableModule : BASE { BGModule::rightExpander.consumerMessage = &_messages[1]; } + void setExpanderModel(Model* m) { + _expanderModel = m; + } + bool expanderConnected() { - bool connected = BGModule::rightExpander.module && dynamic_cast<EM*>(BGModule::rightExpander.module); + bool connected = BGModule::rightExpander.module && _expanderModel && BGModule::rightExpander.module->model == _expanderModel; if (!connected && _wasConnected) { _messages[1] = _messages[0] = MSG(); } return _wasConnected = connected; } - MSG* toExpander() { - assert(expanderConnected()); - MSG* m = (MSG*)BGModule::rightExpander.module->leftExpander.producerMessage; - assert(m); - m->channels = BGModule::_channels; - return m; + inline MSG* toExpander() { + return (MSG*)BGModule::rightExpander.module->leftExpander.producerMessage; } - MSG* fromExpander() { - assert(expanderConnected()); - MSG* m = (MSG*)BGModule::rightExpander.consumerMessage; - assert(m); - return m; + inline MSG* fromExpander() { + return (MSG*)BGModule::rightExpander.consumerMessage; } void process(const BGModule::ProcessArgs& args) override { @@ -60,8 +58,10 @@ struct ExpandableModule : BASE { }; // An expander must be to the right of the expanded module to work. -template<class MSG, class BM, class BASE> +template<class MSG, class BASE> struct ExpanderModule : BASE { + Model* _baseModel = NULL; + Model* _chainableModel = NULL; MSG _messages[2] {}; bool _wasConnected = false; @@ -73,26 +73,28 @@ struct ExpanderModule : BASE { BGModule::leftExpander.consumerMessage = &_messages[1]; } + void setBaseModel(Model* m) { + _baseModel = m; + } + + void setChainableModel(Model* m) { + _chainableModel = m; + } + bool baseConnected() { - bool connected = BGModule::leftExpander.module && dynamic_cast<BM*>(BGModule::leftExpander.module); + bool connected = BGModule::leftExpander.module && ((_baseModel && BGModule::leftExpander.module->model == _baseModel) || (_chainableModel && BGModule::leftExpander.module->model == _chainableModel)); if (!connected && _wasConnected) { _messages[1] = _messages[0] = MSG(); } return _wasConnected = connected; } - MSG* fromBase() { - assert(baseConnected()); - MSG* m = (MSG*)BGModule::leftExpander.consumerMessage; - assert(m); - return m; + inline MSG* fromBase() { + return (MSG*)BGModule::leftExpander.consumerMessage; } - MSG* toBase() { - assert(baseConnected()); - MSG* m = (MSG*)BGModule::leftExpander.module->rightExpander.producerMessage; - assert(m); - return m; + inline MSG* toBase() { + return (MSG*)BGModule::leftExpander.module->rightExpander.producerMessage; } int channels() override final { diff --git a/src/utils.hpp b/src/utils.hpp @@ -1,5 +1,7 @@ #pragma once +#include <atomic> + #include "rack.hpp" using namespace rack; @@ -17,4 +19,17 @@ Model* createModel( return rack::createModel<TModule, TModuleWidget>(slug); } +// https://stackoverflow.com/questions/26583433/c11-implementation-of-spinlock-using-atomic +struct SpinLock { + std::atomic_flag locked = ATOMIC_FLAG_INIT ; + + void lock() { + while (locked.test_and_set(std::memory_order_acquire)) {} + } + + void unlock() { + locked.clear(std::memory_order_release); + } +}; + } // namespace bogaudio