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 @@
+
+
+
+
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));