From 24ad763bc8b5ba106f85015071b132cd01269555 Mon Sep 17 00:00:00 2001 From: falkTX Date: Fri, 29 Oct 2021 02:40:57 +0100 Subject: [PATCH] Initial implementation for host tempo module: play, bar and beat --- plugins/Cardinal/res/HostTime.svg | 237 ++++++++++++++++++++++++ plugins/Cardinal/src/HostParameters.cpp | 23 +-- plugins/Cardinal/src/HostTime.cpp | 88 ++++++++- plugins/Cardinal/src/plugincontext.hpp | 46 +++++ src/CardinalPlugin.cpp | 15 ++ src/PluginContext.hpp | 10 + 6 files changed, 388 insertions(+), 31 deletions(-) create mode 100644 plugins/Cardinal/res/HostTime.svg create mode 100644 plugins/Cardinal/src/plugincontext.hpp diff --git a/plugins/Cardinal/res/HostTime.svg b/plugins/Cardinal/res/HostTime.svg new file mode 100644 index 0000000..6d5ce0c --- /dev/null +++ b/plugins/Cardinal/res/HostTime.svg @@ -0,0 +1,237 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/Cardinal/src/HostParameters.cpp b/plugins/Cardinal/src/HostParameters.cpp index a017b5a..6138fd5 100644 --- a/plugins/Cardinal/src/HostParameters.cpp +++ b/plugins/Cardinal/src/HostParameters.cpp @@ -15,28 +15,7 @@ * For a full copy of the GNU General Public License see the LICENSE file. */ -#include "plugin.hpp" -#include "../dpf/distrho/extra/Mutex.hpp" - -// ----------------------------------------------------------------------------------------------------------- -// from PluginContext.hpp - -START_NAMESPACE_DISTRHO - -static constexpr const uint32_t kModuleParameters = 24; - -class Plugin; - -struct CardinalPluginContext : rack::Context { - uint32_t bufferSize; - double sampleRate; - float parameters[kModuleParameters]; - Mutex mutex; - Plugin* const plugin; - CardinalPluginContext(Plugin* const p); -}; - -END_NAMESPACE_DISTRHO +#include "plugincontext.hpp" // ----------------------------------------------------------------------------------------------------------- diff --git a/plugins/Cardinal/src/HostTime.cpp b/plugins/Cardinal/src/HostTime.cpp index 19575d5..7d62d6d 100644 --- a/plugins/Cardinal/src/HostTime.cpp +++ b/plugins/Cardinal/src/HostTime.cpp @@ -15,7 +15,7 @@ * For a full copy of the GNU General Public License see the LICENSE file. */ -#include "plugin.hpp" +#include "plugincontext.hpp" struct HostTime : Module { enum ParamIds { @@ -24,19 +24,72 @@ struct HostTime : Module { enum InputIds { NUM_INPUTS }; - enum OutputIds { - NUM_OUTPUTS - }; - enum LightIds { - NUM_LIGHTS + enum HostTimeIds { + kHostTimeRolling, + kHostTimeBeat, + kHostTimeBar, + kHostTimeCount }; + rack::dsp::PulseGenerator pulseBeat, pulseBar; + float sampleTime = 0.0f; + HostTime() { - config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + config(NUM_PARAMS, NUM_INPUTS, kHostTimeCount, kHostTimeCount); + + CardinalPluginContext* const pcontext = reinterpret_cast(APP); + + if (pcontext == nullptr) + throw rack::Exception("Plugin context is null."); + + sampleTime = 1.0f / static_cast(pcontext->sampleRate); } - void process(const ProcessArgs&) override { - // TODO + void process(const ProcessArgs&) override + { + if (CardinalPluginContext* const pcontext = reinterpret_cast(APP)) + { + const bool playing = pcontext->playing; + + if (playing) + { + if (pcontext->tick == 0.0) + { + pulseBeat.trigger(); + if (pcontext->beat == 1) + pulseBar.trigger(); + } + + if ((pcontext->tick += pcontext->ticksPerFrame) >= pcontext->ticksPerBeat) + { + pcontext->tick -= pcontext->ticksPerBeat; + pulseBeat.trigger(); + + if (++pcontext->beat > pcontext->beatsPerBar) + { + pcontext->beat = 1; + ++pcontext->bar; + pulseBar.trigger(); + } + } + } + + const bool hasBeat = pulseBeat.process(sampleTime); + const bool hasBar = pulseBar.process(sampleTime); + + lights[kHostTimeRolling].setBrightness(playing ? 1.0 : 0.0f); + lights[kHostTimeBeat].setBrightness(hasBeat ? 1.0 : 0.0f); + lights[kHostTimeBar].setBrightness(hasBar ? 1.0 : 0.0f); + + outputs[kHostTimeRolling].setVoltage(playing ? 10.0f : 0.0f); + outputs[kHostTimeBeat].setVoltage(hasBeat ? 10.0f : 0.0f); + outputs[kHostTimeBar].setVoltage(hasBar ? 10.0f : 0.0f); + } + } + + void onSampleRateChange(const SampleRateChangeEvent& e) override + { + sampleTime = e.sampleTime; } }; @@ -44,6 +97,23 @@ struct HostTimeWidget : ModuleWidget { HostTimeWidget(HostTime* const module) { setModule(module); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostTime.svg"))); + + addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + + const float startX = 10.0f; + const float startY = 170.0f; + const float padding = 30.0f; + + addOutput(createOutput(Vec(startX, startY + 0 * padding), module, HostTime::kHostTimeRolling)); + addOutput(createOutput(Vec(startX, startY + 1 * padding), module, HostTime::kHostTimeBeat)); + addOutput(createOutput(Vec(startX, startY + 2 * padding), module, HostTime::kHostTimeBar)); + + addChild(createLightCentered>(Vec(startX + padding, startY + 0 * padding), module, HostTime::kHostTimeRolling)); + addChild(createLightCentered>(Vec(startX + padding, startY + 1 * padding), module, HostTime::kHostTimeBeat)); + addChild(createLightCentered>(Vec(startX + padding, startY + 2 * padding), module, HostTime::kHostTimeBar)); } }; diff --git a/plugins/Cardinal/src/plugincontext.hpp b/plugins/Cardinal/src/plugincontext.hpp new file mode 100644 index 0000000..e6eab19 --- /dev/null +++ b/plugins/Cardinal/src/plugincontext.hpp @@ -0,0 +1,46 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021 Filipe Coelho + * + * 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. + */ + +#pragma once + +#include "plugin.hpp" +#include "../dpf/distrho/extra/Mutex.hpp" + +// ----------------------------------------------------------------------------------------------------------- +// from PluginContext.hpp + +START_NAMESPACE_DISTRHO + +static constexpr const uint32_t kModuleParameters = 24; + +class Plugin; + +struct CardinalPluginContext : rack::Context { + uint32_t bufferSize; + double sampleRate; + float parameters[kModuleParameters]; + bool playing, frameZero; + int32_t bar, beat, beatsPerBar; + double tick, ticksPerBeat, ticksPerFrame; + Mutex mutex; + Plugin* const plugin; + CardinalPluginContext(Plugin* const p); +}; + +END_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------------------------------------------- diff --git a/src/CardinalPlugin.cpp b/src/CardinalPlugin.cpp index d92b7b5..ebb88a3 100644 --- a/src/CardinalPlugin.cpp +++ b/src/CardinalPlugin.cpp @@ -815,6 +815,21 @@ protected: std::memset(outputs[1], 0, sizeof(float)*frames); } + { + const TimePosition& timePos(getTimePosition()); + context->playing = timePos.playing; + context->frameZero = timePos.frame == 0; + if (timePos.bbt.valid) + { + context->bar = timePos.bbt.bar; + context->beat = timePos.bbt.beat; + context->beatsPerBar = timePos.bbt.beatsPerBar; + context->tick = timePos.bbt.tick; + context->ticksPerBeat = timePos.bbt.ticksPerBeat; + context->ticksPerFrame = 1.0 / (60.0 * getSampleRate() / timePos.bbt.beatsPerMinute / timePos.bbt.ticksPerBeat); + } + } + std::memset(fAudioBufferOut, 0, sizeof(float)*frames*DISTRHO_PLUGIN_NUM_OUTPUTS); for (CardinalMidiInputDevice* dev : fMidiInputs) diff --git a/src/PluginContext.hpp b/src/PluginContext.hpp index 6ac3bf4..778954d 100644 --- a/src/PluginContext.hpp +++ b/src/PluginContext.hpp @@ -40,6 +40,9 @@ struct CardinalPluginContext : rack::Context { uint32_t bufferSize; double sampleRate; float parameters[kModuleParameters]; + bool playing, frameZero; + int32_t bar, beat, beatsPerBar; + double tick, ticksPerBeat, ticksPerFrame; Mutex mutex; Plugin* const plugin; @@ -47,6 +50,13 @@ struct CardinalPluginContext : rack::Context { CardinalPluginContext(Plugin* const p) : bufferSize(p->getBufferSize()), sampleRate(p->getSampleRate()), + playing(false), + frameZero(false), + bar(0), + beat(0), + beatsPerBar(0), + tick(0.0), + ticksPerBeat(0.0), plugin(p) { std::memset(parameters, 0, sizeof(parameters));