Browse Source

Redesign module CPU meter based on Pyer design.

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
e249f82564
3 changed files with 56 additions and 72 deletions
  1. +12
    -11
      include/engine/Module.hpp
  2. +26
    -45
      src/app/ModuleWidget.cpp
  3. +18
    -16
      src/engine/Module.cpp

+ 12
- 11
include/engine/Module.hpp View File

@@ -231,17 +231,6 @@ struct Module {
std::string createPatchStorageDirectory();
std::string getPatchStorageDirectory();

struct ProcessArgs {
/** The current sample rate in Hz. */
float sampleRate;
/** The timestep of process() in seconds.
Defined by `1 / sampleRate`.
*/
float sampleTime;
/** Number of audio samples since the Engine's first sample. */
int64_t frame;
};

/** Getters for members */
plugin::Model* getModel() {
return model;
@@ -285,14 +274,26 @@ struct Module {

// Virtual methods

struct ProcessArgs {
/** The current sample rate in Hz. */
float sampleRate;
/** The timestep of process() in seconds.
Defined by `1 / sampleRate`.
*/
float sampleTime;
/** Number of audio samples since the Engine's first sample. */
int64_t frame;
};
/** Advances the module by one audio sample.
Override this method to read Inputs and Params and to write Outputs and Lights.
*/
virtual void process(const ProcessArgs& args) {
step();
}

/** DEPRECATED. Override `process(const ProcessArgs& args)` instead. */
virtual void step() {}

/** Called instead of process() when Module is bypassed.
Typically you do not need to override this. Use configBypass() instead.
If you do override it, avoid reading param values, since the state of the module should have no effect on routing.


+ 26
- 45
src/app/ModuleWidget.cpp View File

@@ -221,17 +221,6 @@ void ModuleWidget::draw(const DrawArgs& args) {
int meterLength = module->meterLength();
int meterIndex = module->meterIndex();

float meterMax = 0.f;
float meterAvg = 0.f;
for (int i = 0; i < meterLength; i++) {
float m = meterBuffer[i];
meterAvg += m;
meterMax = std::max(meterMax, m);
}
meterAvg /= meterLength;
float percentMax = meterMax * sampleRate;
float mult = (percentMax <= 0.1f) ? 10.f : 1.f;

// // Text background
// nvgBeginPath(args.vg);
// nvgRect(args.vg, 0.0, box.size.y - infoHeight, box.size.x, infoHeight);
@@ -240,48 +229,40 @@ void ModuleWidget::draw(const DrawArgs& args) {

// Draw time plot
nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x, box.size.y);
nvgMoveTo(args.vg, 0.0, box.size.y);
math::Vec p1;
for (int i = 0; i < meterLength; i++) {
int index = (meterIndex - i + meterLength) % meterLength;
float percent = math::clamp(meterBuffer[index] * mult * sampleRate, 0.f, 1.f);
int index = math::eucMod(meterIndex + i + 1, meterLength);
float meter = math::clamp(meterBuffer[index] * sampleRate, 0.f, 1.f);
math::Vec p;
p.x = (1.f - (float) i / (meterLength - 1)) * box.size.x;
p.y = (1.f - percent) * (box.size.y);
nvgLineTo(args.vg, p.x, p.y);
p.x = (float) i / (meterLength - 1) * box.size.x;
p.y = (1.f - meter) * box.size.y;
if (i == 0) {
nvgLineTo(args.vg, VEC_ARGS(p));
}
else {
math::Vec p2 = p;
p2.x -= 0.5f / (meterLength - 1) * box.size.x;
nvgBezierTo(args.vg, VEC_ARGS(p1), VEC_ARGS(p2), VEC_ARGS(p));
}
p1 = p;
p1.x += 0.5f / (meterLength - 1) * box.size.x;
}
NVGcolor color;
if (mult == 1.f)
color = nvgRGBAf(0.5, 0, 0, 0.85);
else if (mult == 10.f)
color = nvgRGBAf(0.85, 0, 0, 0.85);
nvgLineTo(args.vg, 0.0, box.size.y);
nvgLineTo(args.vg, box.size.x, box.size.y);
nvgClosePath(args.vg);
nvgFillColor(args.vg, color);
NVGcolor color = nvgRGBAf(0.5, 0.5, 0.5, 1.0);
nvgFillColor(args.vg, color::alpha(color, 0.5));
nvgFill(args.vg);

// Text
float percent = meterAvg * sampleRate * 100.f;
float microseconds = meterAvg * 1e6f;
std::string meterText = string::f("%.0fx\n%.2f μs\n%.1f%%", mult, microseconds, percent);
bndLabel(args.vg, 0.0, box.size.y - 60, INFINITY, INFINITY, -1, meterText.c_str());

// Draw border
nvgStrokeColor(args.vg, color);
nvgBeginPath(args.vg);
nvgRect(args.vg, 0, 0, box.size.x, box.size.y);
nvgStrokeWidth(args.vg, 2.0);
nvgStrokeColor(args.vg, color);
nvgStroke(args.vg);
}

// if (module) {
// nvgBeginPath(args.vg);
// nvgRect(args.vg, 0, 0, 20, 20);
// nvgFillColor(args.vg, nvgRGBAf(0, 0, 0, 0.75));
// nvgFill(args.vg);

// std::string debugText = string::f("%d", module->id);
// bndLabel(args.vg, 0, 0, INFINITY, INFINITY, -1, debugText.c_str());
// }
// Text
float percent = meterBuffer[meterIndex] * sampleRate * 100.f;
float microseconds = meterBuffer[meterIndex] * 1e6f;
std::string meterText = string::f("%.2f μs/sample %.1f%%", microseconds, percent);
bndLabel(args.vg, box.size.x - 130.0, 0.0, INFINITY, INFINITY, -1, meterText.c_str());
}

// Selection
if (APP->scene->rack->isSelected(this)) {


+ 18
- 16
src/engine/Module.cpp View File

@@ -14,18 +14,18 @@ namespace engine {


// Arbitrary prime number so it doesn't over- or under-estimate time of buffered processors.
static const int meterDivider = 1;
static const int meterBufferLength = 128;
static const int METER_DIVIDER = 37;
static const int METER_BUFFER_LEN = 32;
static const float METER_TIME = 1.0f;


struct Module::Internal {
bool bypassed = false;

int64_t meterLastBlock = 0;
int meterSamples = 0;
float meterTimeTotal = 0.f;
float meterDurationTotal = 0.f;

float meterBuffer[meterBufferLength] = {};
float meterBuffer[METER_BUFFER_LEN] = {};
int meterIndex = 0;
};

@@ -299,7 +299,7 @@ const float* Module::meterBuffer() {


int Module::meterLength() {
return meterBufferLength;
return METER_BUFFER_LEN;
}


@@ -332,7 +332,7 @@ static void Port_step(Port* that, float deltaTime) {

void Module::doProcess(const ProcessArgs& args) {
// This global setting can change while the function is running, so use a local variable.
bool meterEnabled = settings::cpuMeter && (args.frame % meterDivider == 0);
bool meterEnabled = settings::cpuMeter && (args.frame % METER_DIVIDER == 0);

// Start CPU timer
double startTime;
@@ -351,21 +351,23 @@ void Module::doProcess(const ProcessArgs& args) {
double endTime = system::getTime();
float duration = endTime - startTime;

int64_t block = APP->engine->getBlock();
if (block > internal->meterLastBlock) {
internal->meterSamples++;
internal->meterDurationTotal += duration;

// Seconds we've been measuring
float meterTime = internal->meterSamples * METER_DIVIDER * args.sampleTime;

if (meterTime >= METER_TIME) {
// Push time to buffer
if (internal->meterSamples > 0) {
internal->meterBuffer[internal->meterIndex++] = internal->meterTimeTotal / internal->meterSamples;
internal->meterIndex %= meterBufferLength;
internal->meterIndex++;
internal->meterIndex %= METER_BUFFER_LEN;
internal->meterBuffer[internal->meterIndex] = internal->meterDurationTotal / internal->meterSamples;
}
// Reset total
internal->meterSamples = 0;
internal->meterTimeTotal = 0.f;
internal->meterDurationTotal = 0.f;
}

internal->meterLastBlock = block;
internal->meterSamples++;
internal->meterTimeTotal += duration;
}

// Iterate ports to step plug lights


Loading…
Cancel
Save