Cardinal/plugins/Cardinal/src/HostTime.cpp
falkTX 3898ea976e
Work a bit on params/time GUI; Implement Time clock signal
Signed-off-by: falkTX <falktx@falktx.com>
2021-10-29 23:16:01 +01:00

162 lines
6.4 KiB
C++

/*
* DISTRHO Cardinal Plugin
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
*
* 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.
*/
#include "plugincontext.hpp"
struct HostTime : Module {
enum ParamIds {
NUM_PARAMS
};
enum InputIds {
NUM_INPUTS
};
enum HostTimeIds {
kHostTimeRolling,
kHostTimeBar,
kHostTimeBeat,
kHostTimeClock,
kHostTimeCount
};
rack::dsp::PulseGenerator pulseBar, pulseBeat, pulseClock;
float sampleTime = 0.0f;
HostTime()
{
config(NUM_PARAMS, NUM_INPUTS, kHostTimeCount, kHostTimeCount);
CardinalPluginContext* const pcontext = reinterpret_cast<CardinalPluginContext*>(APP);
if (pcontext == nullptr)
throw rack::Exception("Plugin context is null.");
}
void process(const ProcessArgs& args) override
{
if (CardinalPluginContext* const pcontext = reinterpret_cast<CardinalPluginContext*>(APP))
{
const bool playing = pcontext->playing;
if (playing)
{
if (pcontext->tick == 0.0)
{
pulseClock.trigger();
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();
}
}
if ((pcontext->tickClock += pcontext->ticksPerFrame) >= pcontext->ticksPerClock)
{
pcontext->tickClock -= pcontext->ticksPerClock;
pulseClock.trigger();
}
}
const bool hasBar = pulseBar.process(args.sampleTime);
const bool hasBeat = pulseBeat.process(args.sampleTime);
const bool hasClock = pulseClock.process(args.sampleTime);
lights[kHostTimeRolling].setBrightness(playing ? 1.0f : 0.0f);
lights[kHostTimeBar].setBrightnessSmooth(hasBar ? 1.0f : 0.0f, args.sampleTime * 0.5f);
lights[kHostTimeBeat].setBrightnessSmooth(hasBeat ? 1.0f : 0.0f, args.sampleTime);
lights[kHostTimeClock].setBrightnessSmooth(hasClock ? 1.0f : 0.0f, args.sampleTime * 2.0f);
outputs[kHostTimeRolling].setVoltage(playing ? 10.0f : 0.0f);
outputs[kHostTimeBar].setVoltage(hasBar ? 10.0f : 0.0f);
outputs[kHostTimeBeat].setVoltage(hasBeat ? 10.0f : 0.0f);
outputs[kHostTimeClock].setVoltage(hasClock ? 10.0f : 0.0f);
}
}
};
struct HostTimeWidget : ModuleWidget {
static constexpr const float startX = 10.0f;
static constexpr const float startY = 73.0f;
static constexpr const float padding = 32.0f;
HostTimeWidget(HostTime* const module)
{
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostTime.svg")));
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addOutput(createOutput<PJ301MPort>(Vec(startX, startY + 0 * padding), module, HostTime::kHostTimeRolling));
addOutput(createOutput<PJ301MPort>(Vec(startX, startY + 1 * padding), module, HostTime::kHostTimeBar));
addOutput(createOutput<PJ301MPort>(Vec(startX, startY + 2 * padding), module, HostTime::kHostTimeBeat));
addOutput(createOutput<PJ301MPort>(Vec(startX, startY + 3 * padding), module, HostTime::kHostTimeClock));
const float x = startX + 28;
addChild(createLightCentered<SmallLight<GreenLight>> (Vec(x, startY + 0 * padding + 12), module, HostTime::kHostTimeRolling));
addChild(createLightCentered<SmallLight<RedLight>> (Vec(x, startY + 1 * padding + 12), module, HostTime::kHostTimeBar));
addChild(createLightCentered<SmallLight<YellowLight>>(Vec(x, startY + 2 * padding + 12), module, HostTime::kHostTimeBeat));
addChild(createLightCentered<SmallLight<YellowLight>>(Vec(x, startY + 3 * padding + 12), module, HostTime::kHostTimeClock));
}
void drawOutputLine(NVGcontext* const vg, const uint offset, const char* const text)
{
const float y = startY + offset * padding;
nvgBeginPath(vg);
nvgRoundedRect(vg, startX - 1.0f, y - 2.0f, box.size.x - (startX + 1) * 2, 28.0f, 4);
nvgFillColor(vg, nvgRGBA(0xda, 0xda, 0xda, 0xf0));
nvgFill(vg);
nvgStrokeColor(vg, nvgRGBA(0x4a, 0x4a, 0x4a, 0xc0));
nvgStroke(vg);
nvgBeginPath(vg);
nvgFillColor(vg, color::BLACK);
nvgText(vg, startX + 36, y + 16, text, nullptr);
}
void draw(const DrawArgs& args) override
{
nvgBeginPath(args.vg);
nvgRect(args.vg, 0, 0, box.size.x, box.size.y);
nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, 0, 0, box.size.y,
nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22)));
nvgFill(args.vg);
nvgFontFaceId(args.vg, 0);
nvgFontSize(args.vg, 14);
drawOutputLine(args.vg, 0, "Playing");
drawOutputLine(args.vg, 1, "Bar");
drawOutputLine(args.vg, 2, "Beat");
drawOutputLine(args.vg, 3, "Clock");
ModuleWidget::draw(args);
}
};
Model* modelHostTime = createModel<HostTime, HostTimeWidget>("HostTime");