|
|
@@ -217,8 +217,11 @@ struct ScopeDisplay : LedDisplay { |
|
|
|
} |
|
|
|
|
|
|
|
void calculateStats(Stats& stats, int wave, int channels) { |
|
|
|
if (!module) |
|
|
|
if (!module) { |
|
|
|
stats.min = -5.f; |
|
|
|
stats.max = 5.f; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
stats = Stats(); |
|
|
|
for (int i = 0; i < BUFFER_SIZE; i++) { |
|
|
@@ -234,13 +237,21 @@ struct ScopeDisplay : LedDisplay { |
|
|
|
} |
|
|
|
|
|
|
|
void drawWave(const DrawArgs& args, int wave, int channel, float offset, float gain) { |
|
|
|
if (!module) |
|
|
|
return; |
|
|
|
|
|
|
|
// Copy point buffer to stack to prevent min/max values being different phase. |
|
|
|
// This is currently only 256*4*16*4 = 64 kiB. |
|
|
|
Scope::Point pointBuffer[BUFFER_SIZE]; |
|
|
|
std::copy(std::begin(module->pointBuffer), std::end(module->pointBuffer), std::begin(pointBuffer)); |
|
|
|
if (module) { |
|
|
|
std::copy(std::begin(module->pointBuffer), std::end(module->pointBuffer), std::begin(pointBuffer)); |
|
|
|
} |
|
|
|
else { |
|
|
|
for (size_t i = 0; i < BUFFER_SIZE; i++) { |
|
|
|
float phase = float(i) / BUFFER_SIZE; |
|
|
|
Scope::Point point; |
|
|
|
point.minX[0] = point.maxX[0] = 4.f * std::sin(2 * M_PI * phase * 2.f) + 5.f; |
|
|
|
point.minY[0] = point.maxY[0] = 4.f * std::sin(2 * M_PI * phase * 2.f) - 5.f; |
|
|
|
pointBuffer[i] = point; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
nvgSave(args.vg); |
|
|
|
Rect b = box.zeroPos().shrink(Vec(0, 15)); |
|
|
@@ -415,26 +426,27 @@ struct ScopeDisplay : LedDisplay { |
|
|
|
// Background lines |
|
|
|
drawBackground(args); |
|
|
|
|
|
|
|
if (!module) |
|
|
|
return; |
|
|
|
|
|
|
|
float gainX = std::pow(2.f, std::round(module->params[Scope::X_SCALE_PARAM].getValue())) / 10.f; |
|
|
|
float gainY = std::pow(2.f, std::round(module->params[Scope::Y_SCALE_PARAM].getValue())) / 10.f; |
|
|
|
float offsetX = module->params[Scope::X_POS_PARAM].getValue(); |
|
|
|
float offsetY = module->params[Scope::Y_POS_PARAM].getValue(); |
|
|
|
float gainX = module ? module->params[Scope::X_SCALE_PARAM].getValue() : 0.f; |
|
|
|
gainX = std::pow(2.f, std::round(gainX)) / 10.f; |
|
|
|
float gainY = module ? module->params[Scope::Y_SCALE_PARAM].getValue() : 0.f; |
|
|
|
gainY = std::pow(2.f, std::round(gainY)) / 10.f; |
|
|
|
float offsetX = module ? module->params[Scope::X_POS_PARAM].getValue() : 0.f; |
|
|
|
float offsetY = module ? module->params[Scope::Y_POS_PARAM].getValue() : 0.f; |
|
|
|
|
|
|
|
// Get input colors |
|
|
|
PortWidget* inputX = moduleWidget->getInput(Scope::X_INPUT); |
|
|
|
PortWidget* inputY = moduleWidget->getInput(Scope::Y_INPUT); |
|
|
|
CableWidget* inputXCable = APP->scene->rack->getTopCable(inputX); |
|
|
|
CableWidget* inputYCable = APP->scene->rack->getTopCable(inputY); |
|
|
|
NVGcolor inputXColor = inputXCable ? inputXCable->color : color::WHITE; |
|
|
|
NVGcolor inputYColor = inputYCable ? inputYCable->color : color::WHITE; |
|
|
|
NVGcolor inputXColor = inputXCable ? inputXCable->color : SCHEME_YELLOW; |
|
|
|
NVGcolor inputYColor = inputYCable ? inputYCable->color : SCHEME_YELLOW; |
|
|
|
|
|
|
|
// Draw waveforms |
|
|
|
if (module->isLissajous()) { |
|
|
|
int channelsY = module ? module->channelsY : 1; |
|
|
|
int channelsX = module ? module->channelsX : 1; |
|
|
|
if (module && module->isLissajous()) { |
|
|
|
// X x Y |
|
|
|
int lissajousChannels = std::min(module->channelsX, module->channelsY); |
|
|
|
int lissajousChannels = std::min(channelsX, channelsY); |
|
|
|
for (int c = 0; c < lissajousChannels; c++) { |
|
|
|
nvgStrokeColor(args.vg, SCHEME_YELLOW); |
|
|
|
drawLissajous(args, c, offsetX, gainX, offsetY, gainY); |
|
|
@@ -442,29 +454,30 @@ struct ScopeDisplay : LedDisplay { |
|
|
|
} |
|
|
|
else { |
|
|
|
// Y |
|
|
|
for (int c = 0; c < module->channelsY; c++) { |
|
|
|
for (int c = 0; c < channelsY; c++) { |
|
|
|
nvgFillColor(args.vg, inputYColor); |
|
|
|
drawWave(args, 1, c, offsetY, gainY); |
|
|
|
} |
|
|
|
|
|
|
|
// X |
|
|
|
for (int c = 0; c < module->channelsX; c++) { |
|
|
|
for (int c = 0; c < channelsX; c++) { |
|
|
|
nvgFillColor(args.vg, inputXColor); |
|
|
|
drawWave(args, 0, c, offsetX, gainX); |
|
|
|
} |
|
|
|
|
|
|
|
// Trigger |
|
|
|
float trigThreshold = module->params[Scope::THRESH_PARAM].getValue(); |
|
|
|
float trigThreshold = module ? module->params[Scope::THRESH_PARAM].getValue() : 0.f; |
|
|
|
trigThreshold = (trigThreshold + offsetX) * gainX; |
|
|
|
drawTrig(args, trigThreshold); |
|
|
|
} |
|
|
|
|
|
|
|
// Calculate and draw stats |
|
|
|
if (++statsFrame >= 4) { |
|
|
|
statsFrame = 0; |
|
|
|
calculateStats(statsX, 0, module->channelsX); |
|
|
|
calculateStats(statsY, 1, module->channelsY); |
|
|
|
if (statsFrame == 0) { |
|
|
|
calculateStats(statsX, 0, channelsX); |
|
|
|
calculateStats(statsY, 1, channelsY); |
|
|
|
} |
|
|
|
statsFrame = (statsFrame + 1) % 4; |
|
|
|
|
|
|
|
drawStats(args, Vec(0, 0 + 1), "1", statsX); |
|
|
|
drawStats(args, Vec(0, box.size.y - 15 - 1), "2", statsY); |
|
|
|
} |
|
|
|