HostTime: Rename Clock to Step, add full time and BBT display

Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
falkTX 2022-02-01 20:53:11 +00:00
parent 1311b6a127
commit c7006e3726
No known key found for this signature in database
GPG key ID: CDBAA37ABC74FBA0
3 changed files with 154 additions and 107 deletions

View file

@ -35,6 +35,8 @@ struct HostTime : Module {
kHostTimeCount kHostTimeCount
}; };
const CardinalPluginContext* const pcontext;
rack::dsp::PulseGenerator pulseReset, pulseBar, pulseBeat, pulseClock; rack::dsp::PulseGenerator pulseReset, pulseBar, pulseBeat, pulseClock;
float sampleTime = 0.0f; float sampleTime = 0.0f;
int64_t lastBlockFrame = -1; int64_t lastBlockFrame = -1;
@ -45,141 +47,145 @@ struct HostTime : Module {
int32_t beat = 0; int32_t beat = 0;
double tick = 0.0; double tick = 0.0;
double tickClock = 0.0; double tickClock = 0.0;
uint32_t seconds = 0;
} timeInfo; } timeInfo;
HostTime() HostTime()
: pcontext(static_cast<CardinalPluginContext*>(APP))
{ {
config(NUM_PARAMS, NUM_INPUTS, kHostTimeCount, kHostTimeCount);
const CardinalPluginContext* const pcontext = static_cast<CardinalPluginContext*>(APP);
if (pcontext == nullptr) if (pcontext == nullptr)
throw rack::Exception("Plugin context is null."); throw rack::Exception("Plugin context is null.");
config(NUM_PARAMS, NUM_INPUTS, kHostTimeCount, kHostTimeCount);
} }
void process(const ProcessArgs& args) override void process(const ProcessArgs& args) override
{ {
if (const CardinalPluginContext* const pcontext = static_cast<CardinalPluginContext*>(APP)) const int64_t blockFrame = pcontext->engine->getBlockFrame();
// Update time position if running a new audio block
if (lastBlockFrame != blockFrame)
{ {
const int64_t blockFrame = pcontext->engine->getBlockFrame(); lastBlockFrame = blockFrame;
timeInfo.reset = pcontext->reset;
// Update time position if running a new audio block timeInfo.bar = pcontext->bar;
if (lastBlockFrame != blockFrame) timeInfo.beat = pcontext->beat;
{ timeInfo.tick = pcontext->tick;
lastBlockFrame = blockFrame; timeInfo.tickClock = pcontext->tickClock;
timeInfo.reset = pcontext->reset; timeInfo.seconds = pcontext->frame / pcontext->sampleRate;
timeInfo.bar = pcontext->bar;
timeInfo.beat = pcontext->beat;
timeInfo.tick = pcontext->tick;
timeInfo.tickClock = pcontext->tickClock;
}
const bool playing = pcontext->playing;
const bool playingWithBBT = playing && pcontext->bbtValid;
if (playingWithBBT)
{
if (timeInfo.tick == 0.0)
{
pulseReset.trigger();
pulseClock.trigger();
pulseBeat.trigger();
if (timeInfo.beat == 1)
pulseBar.trigger();
}
if (timeInfo.reset)
{
timeInfo.reset = false;
pulseReset.trigger();
}
if ((timeInfo.tick += pcontext->ticksPerFrame) >= pcontext->ticksPerBeat)
{
timeInfo.tick -= pcontext->ticksPerBeat;
pulseBeat.trigger();
if (++timeInfo.beat > pcontext->beatsPerBar)
{
timeInfo.beat = 1;
++timeInfo.bar;
pulseBar.trigger();
}
}
if ((timeInfo.tickClock += pcontext->ticksPerFrame) >= pcontext->ticksPerClock)
{
timeInfo.tickClock -= pcontext->ticksPerClock;
pulseClock.trigger();
}
}
const bool hasReset = pulseReset.process(args.sampleTime);
const bool hasBar = pulseBar.process(args.sampleTime);
const bool hasBeat = pulseBeat.process(args.sampleTime);
const bool hasClock = pulseClock.process(args.sampleTime);
const float beatPhase = playingWithBBT && pcontext->ticksPerBeat > 0.0
? timeInfo.tick / pcontext->ticksPerBeat
: 0.0f;
const float barPhase = playingWithBBT && pcontext->beatsPerBar > 0
? ((float) (timeInfo.beat - 1) + beatPhase) / pcontext->beatsPerBar
: 0.0f;
lights[kHostTimeRolling].setBrightness(playing ? 1.0f : 0.0f);
lights[kHostTimeReset].setBrightnessSmooth(hasReset ? 1.0f : 0.0f, args.sampleTime * 0.5f);
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);
lights[kHostTimeBarPhase].setBrightness(barPhase);
lights[kHostTimeBeatPhase].setBrightness(beatPhase);
outputs[kHostTimeRolling].setVoltage(playing ? 10.0f : 0.0f);
outputs[kHostTimeReset].setVoltage(hasReset ? 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);
outputs[kHostTimeBarPhase].setVoltage(barPhase * 10.0f);
outputs[kHostTimeBeatPhase].setVoltage(beatPhase * 10.0f);
} }
const bool playing = pcontext->playing;
const bool playingWithBBT = playing && pcontext->bbtValid;
if (playingWithBBT)
{
if (timeInfo.tick == 0.0)
{
pulseReset.trigger();
pulseClock.trigger();
pulseBeat.trigger();
if (timeInfo.beat == 1)
pulseBar.trigger();
}
if (timeInfo.reset)
{
timeInfo.reset = false;
pulseReset.trigger();
}
if ((timeInfo.tick += pcontext->ticksPerFrame) >= pcontext->ticksPerBeat)
{
timeInfo.tick -= pcontext->ticksPerBeat;
pulseBeat.trigger();
if (++timeInfo.beat > pcontext->beatsPerBar)
{
timeInfo.beat = 1;
++timeInfo.bar;
pulseBar.trigger();
}
}
if ((timeInfo.tickClock += pcontext->ticksPerFrame) >= pcontext->ticksPerClock)
{
timeInfo.tickClock -= pcontext->ticksPerClock;
pulseClock.trigger();
}
}
const bool hasReset = pulseReset.process(args.sampleTime);
const bool hasBar = pulseBar.process(args.sampleTime);
const bool hasBeat = pulseBeat.process(args.sampleTime);
const bool hasClock = pulseClock.process(args.sampleTime);
const float beatPhase = playingWithBBT && pcontext->ticksPerBeat > 0.0
? timeInfo.tick / pcontext->ticksPerBeat
: 0.0f;
const float barPhase = playingWithBBT && pcontext->beatsPerBar > 0
? ((float) (timeInfo.beat - 1) + beatPhase) / pcontext->beatsPerBar
: 0.0f;
lights[kHostTimeRolling].setBrightness(playing ? 1.0f : 0.0f);
lights[kHostTimeReset].setBrightnessSmooth(hasReset ? 1.0f : 0.0f, args.sampleTime * 0.5f);
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);
lights[kHostTimeBarPhase].setBrightness(barPhase);
lights[kHostTimeBeatPhase].setBrightness(beatPhase);
outputs[kHostTimeRolling].setVoltage(playing ? 10.0f : 0.0f);
outputs[kHostTimeReset].setVoltage(hasReset ? 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);
outputs[kHostTimeBarPhase].setVoltage(barPhase * 10.0f);
outputs[kHostTimeBeatPhase].setVoltage(beatPhase * 10.0f);
} }
}; };
struct HostTimeWidget : ModuleWidget { struct HostTimeWidget : ModuleWidget {
static constexpr const float startX = 10.0f; static constexpr const float startX = 10.0f;
static constexpr const float startY = 73.0f; static constexpr const float startY_top = 71.0f;
static constexpr const float startY_cv = 115.0f;
static constexpr const float padding = 32.0f; static constexpr const float padding = 32.0f;
HostTimeWidget(HostTime* const module) HostTime* const module;
std::shared_ptr<Font> monoFont;
HostTimeWidget(HostTime* const m)
: module(m)
{ {
setModule(module); setModule(m);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostTime.svg"))); setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostTime.svg")));
monoFont = APP->window->loadFont(asset::system("res/fonts/ShareTechMono-Regular.ttf"));
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0))); addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * 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(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))); 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_cv + 0 * padding), m, HostTime::kHostTimeRolling));
addOutput(createOutput<PJ301MPort>(Vec(startX, startY + 1 * padding), module, HostTime::kHostTimeReset)); addOutput(createOutput<PJ301MPort>(Vec(startX, startY_cv + 1 * padding), m, HostTime::kHostTimeReset));
addOutput(createOutput<PJ301MPort>(Vec(startX, startY + 2 * padding), module, HostTime::kHostTimeBar)); addOutput(createOutput<PJ301MPort>(Vec(startX, startY_cv + 2 * padding), m, HostTime::kHostTimeBar));
addOutput(createOutput<PJ301MPort>(Vec(startX, startY + 3 * padding), module, HostTime::kHostTimeBeat)); addOutput(createOutput<PJ301MPort>(Vec(startX, startY_cv + 3 * padding), m, HostTime::kHostTimeBeat));
addOutput(createOutput<PJ301MPort>(Vec(startX, startY + 4 * padding), module, HostTime::kHostTimeClock)); addOutput(createOutput<PJ301MPort>(Vec(startX, startY_cv + 4 * padding), m, HostTime::kHostTimeClock));
addOutput(createOutput<PJ301MPort>(Vec(startX, startY + 5 * padding), module, HostTime::kHostTimeBarPhase)); addOutput(createOutput<PJ301MPort>(Vec(startX, startY_cv + 5 * padding), m, HostTime::kHostTimeBarPhase));
addOutput(createOutput<PJ301MPort>(Vec(startX, startY + 6 * padding), module, HostTime::kHostTimeBeatPhase)); addOutput(createOutput<PJ301MPort>(Vec(startX, startY_cv + 6 * padding), m, HostTime::kHostTimeBeatPhase));
const float x = startX + 28; const float x = startX + 28;
addChild(createLightCentered<SmallLight<GreenLight>> (Vec(x, startY + 0 * padding + 12), module, HostTime::kHostTimeRolling)); addChild(createLightCentered<SmallLight<GreenLight>> (Vec(x, startY_cv + 0 * padding + 12), m, HostTime::kHostTimeRolling));
addChild(createLightCentered<SmallLight<WhiteLight>> (Vec(x, startY + 1 * padding + 12), module, HostTime::kHostTimeReset)); addChild(createLightCentered<SmallLight<WhiteLight>> (Vec(x, startY_cv + 1 * padding + 12), m, HostTime::kHostTimeReset));
addChild(createLightCentered<SmallLight<RedLight>> (Vec(x, startY + 2 * padding + 12), module, HostTime::kHostTimeBar)); addChild(createLightCentered<SmallLight<RedLight>> (Vec(x, startY_cv + 2 * padding + 12), m, HostTime::kHostTimeBar));
addChild(createLightCentered<SmallLight<YellowLight>>(Vec(x, startY + 3 * padding + 12), module, HostTime::kHostTimeBeat)); addChild(createLightCentered<SmallLight<YellowLight>>(Vec(x, startY_cv + 3 * padding + 12), m, HostTime::kHostTimeBeat));
addChild(createLightCentered<SmallLight<YellowLight>>(Vec(x, startY + 4 * padding + 12), module, HostTime::kHostTimeClock)); addChild(createLightCentered<SmallLight<YellowLight>>(Vec(x, startY_cv + 4 * padding + 12), m, HostTime::kHostTimeClock));
addChild(createLightCentered<SmallLight<YellowLight>>(Vec(x, startY + 5 * padding + 12), module, HostTime::kHostTimeBarPhase)); addChild(createLightCentered<SmallLight<YellowLight>>(Vec(x, startY_cv + 5 * padding + 12), m, HostTime::kHostTimeBarPhase));
addChild(createLightCentered<SmallLight<YellowLight>>(Vec(x, startY + 6 * padding + 12), module, HostTime::kHostTimeBeatPhase)); addChild(createLightCentered<SmallLight<YellowLight>>(Vec(x, startY_cv + 6 * padding + 12), m, HostTime::kHostTimeBeatPhase));
} }
void drawOutputLine(NVGcontext* const vg, const uint offset, const char* const text) void drawOutputLine(NVGcontext* const vg, const uint offset, const char* const text)
{ {
const float y = startY + offset * padding; const float y = startY_cv + offset * padding;
nvgBeginPath(vg); nvgBeginPath(vg);
nvgRoundedRect(vg, startX - 1.0f, y - 2.0f, box.size.x - (startX + 1) * 2, 28.0f, 4); nvgRoundedRect(vg, startX - 1.0f, y - 2.0f, box.size.x - (startX + 1) * 2, 28.0f, 4);
nvgFillColor(vg, nvgRGB(0xd0, 0xd0, 0xd0)); nvgFillColor(vg, nvgRGB(0xd0, 0xd0, 0xd0));
@ -204,14 +210,55 @@ struct HostTimeWidget : ModuleWidget {
drawOutputLine(args.vg, 1, "Reset"); drawOutputLine(args.vg, 1, "Reset");
drawOutputLine(args.vg, 2, "Bar"); drawOutputLine(args.vg, 2, "Bar");
drawOutputLine(args.vg, 3, "Beat"); drawOutputLine(args.vg, 3, "Beat");
drawOutputLine(args.vg, 4, "Clock"); drawOutputLine(args.vg, 4, "Step");
nvgFontSize(args.vg, 11); nvgFontSize(args.vg, 11);
drawOutputLine(args.vg, 5, "Bar Phase"); drawOutputLine(args.vg, 5, "Bar Phase");
drawOutputLine(args.vg, 6, "Beat Phase"); drawOutputLine(args.vg, 6, "Beat Phase");
nvgBeginPath(args.vg);
nvgRoundedRect(args.vg, startX - 1.0f, startY_top, 98.0f, 38.0f, 4); // 98
nvgFillColor(args.vg, color::BLACK);
nvgFill(args.vg);
ModuleWidget::draw(args); ModuleWidget::draw(args);
} }
void drawLayer(const DrawArgs& args, int layer) override
{
if (layer == 1)
{
nvgFontFaceId(args.vg, monoFont->handle);
nvgFontSize(args.vg, 17);
nvgFillColor(args.vg, nvgRGBf(0.76f, 0.11f, 0.22f));
char timeString1[24];
char timeString2[24];
if (module != nullptr && monoFont != nullptr)
{
const uint32_t seconds = module->timeInfo.seconds;
std::snprintf(timeString1, sizeof(timeString1), " %02d:%02d:%02d",
(seconds / 3600) % 100,
(seconds / 60) % 60,
seconds % 60);
std::snprintf(timeString2, sizeof(timeString2), "%03d:%02d:%04d",
module->timeInfo.bar % 1000,
module->timeInfo.beat % 100,
static_cast<int>(module->timeInfo.tick + 0.5));
}
else
{
std::strcpy(timeString1, " 00:00:00");
std::strcpy(timeString2, "001:01:0000");
}
nvgText(args.vg, startX + 3.5f, startY_top + 15.0f, timeString1, nullptr);
nvgText(args.vg, startX + 3.5f, startY_top + 33.0f, timeString2, nullptr);
}
ModuleWidget::drawLayer(args, layer);
}
}; };
Model* modelHostTime = createModel<HostTime, HostTimeWidget>("HostTime"); Model* modelHostTime = createModel<HostTime, HostTimeWidget>("HostTime");

View file

@ -91,7 +91,7 @@ struct ImGuiWidget::PrivateData {
if (useMonospacedFont) if (useMonospacedFont)
{ {
const std::string fontPath = asset::system("fonts/ShareTechMono-Regular.ttf"); const std::string fontPath = asset::system("res/fonts/ShareTechMono-Regular.ttf");
ImFontConfig fc; ImFontConfig fc;
fc.OversampleH = 1; fc.OversampleH = 1;
fc.OversampleV = 1; fc.OversampleV = 1;

View file

@ -38,7 +38,7 @@
{ {
"id": 3, "id": 3,
"plugin": "Cardinal", "plugin": "Cardinal",
"model": "HostParameters", "model": "HostTime",
"version": "2.0", "version": "2.0",
"params": [], "params": [],
"leftModuleId": 2, "leftModuleId": 2,
@ -51,12 +51,12 @@
{ {
"id": 4, "id": 4,
"plugin": "Cardinal", "plugin": "Cardinal",
"model": "HostTime", "model": "HostParameters",
"version": "2.0", "version": "2.0",
"params": [], "params": [],
"leftModuleId": 3, "leftModuleId": 3,
"pos": [ "pos": [
27, 26,
0 0
] ]
} }