diff --git a/res/Scope.svg b/res/Scope.svg
index b93a5a0..ba59dff 100644
--- a/res/Scope.svg
+++ b/res/Scope.svg
@@ -9,15 +9,15 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="51.671444mm"
- height="100.54166mm"
- viewBox="0 0 51.671444 100.54168"
+ width="195.29379"
+ height="380.00003"
+ viewBox="0 0 51.671483 100.54167"
version="1.1"
- id="svg4541"
- sodipodi:docname="Scope.svg"
- inkscape:version="0.92.2 5c3e80d, 2017-08-06">
+ id="svg8630"
+ inkscape:version="0.92.2 5c3e80d, 2017-08-06"
+ sodipodi:docname="Scope.svg">
+ id="defs8624" />
+ id="metadata8627">
image/svg+xml
-
+
@@ -56,366 +57,341 @@
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
- transform="translate(10.012165,-99.047014)">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ transform="translate(-44.467833,-88.735117)">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Scope.cpp b/src/Scope.cpp
index 12492df..1476d8a 100644
--- a/src/Scope.cpp
+++ b/src/Scope.cpp
@@ -12,9 +12,9 @@ struct Scope : Module {
Y_SCALE_PARAM,
Y_POS_PARAM,
TIME_PARAM,
- MODE_PARAM,
+ LISSAJOUS_PARAM,
TRIG_PARAM,
- EXT_PARAM,
+ EXTERNAL_PARAM,
NUM_PARAMS
};
enum InputIds {
@@ -34,8 +34,8 @@ struct Scope : Module {
SchmittTrigger sumTrigger;
SchmittTrigger extTrigger;
- bool sum = false;
- bool ext = false;
+ bool lissajous = false;
+ bool external = false;
float lights[4] = {};
SchmittTrigger resetTrigger;
@@ -44,41 +44,41 @@ struct Scope : Module {
json_t *toJson() {
json_t *rootJ = json_object();
- json_object_set_new(rootJ, "sum", json_integer((int) sum));
- json_object_set_new(rootJ, "ext", json_integer((int) ext));
+ json_object_set_new(rootJ, "lissajous", json_integer((int) lissajous));
+ json_object_set_new(rootJ, "external", json_integer((int) external));
return rootJ;
}
void fromJson(json_t *rootJ) {
- json_t *sumJ = json_object_get(rootJ, "sum");
+ json_t *sumJ = json_object_get(rootJ, "lissajous");
if (sumJ)
- sum = json_integer_value(sumJ);
+ lissajous = json_integer_value(sumJ);
- json_t *extJ = json_object_get(rootJ, "ext");
+ json_t *extJ = json_object_get(rootJ, "external");
if (extJ)
- ext = json_integer_value(extJ);
+ external = json_integer_value(extJ);
}
void initialize() {
- sum = false;
- ext = false;
+ lissajous = false;
+ external = false;
}
};
void Scope::step() {
// Modes
- if (sumTrigger.process(params[MODE_PARAM].value)) {
- sum = !sum;
+ if (sumTrigger.process(params[LISSAJOUS_PARAM].value)) {
+ lissajous = !lissajous;
}
- lights[0] = sum ? 0.0 : 1.0;
- lights[1] = sum ? 1.0 : 0.0;
+ lights[0] = lissajous ? 0.0 : 1.0;
+ lights[1] = lissajous ? 1.0 : 0.0;
- if (extTrigger.process(params[EXT_PARAM].value)) {
- ext = !ext;
+ if (extTrigger.process(params[EXTERNAL_PARAM].value)) {
+ external = !external;
}
- lights[2] = ext ? 0.0 : 1.0;
- lights[3] = ext ? 1.0 : 0.0;
+ lights[2] = external ? 0.0 : 1.0;
+ lights[3] = external ? 1.0 : 0.0;
// Compute time
float deltaTime = powf(2.0, params[TIME_PARAM].value);
@@ -96,9 +96,11 @@ void Scope::step() {
// Are we waiting on the next trigger?
if (bufferIndex >= BUFFER_SIZE) {
- // Trigger immediately if external but nothing plugged in
- if (ext && !inputs[TRIG_INPUT].active) {
- bufferIndex = 0; frameIndex = 0; return;
+ // Trigger immediately if external but nothing plugged in, or in Lissajous mode
+ if (lissajous || (external && !inputs[TRIG_INPUT].active)) {
+ bufferIndex = 0;
+ frameIndex = 0;
+ return;
}
// Reset the Schmitt trigger so we don't trigger immediately if the input is high
@@ -109,7 +111,7 @@ void Scope::step() {
// Must go below 0.1V to trigger
resetTrigger.setThresholds(params[TRIG_PARAM].value - 0.1, params[TRIG_PARAM].value);
- float gate = ext ? inputs[TRIG_INPUT].value : inputs[X_INPUT].value;
+ float gate = external ? inputs[TRIG_INPUT].value : inputs[X_INPUT].value;
// Reset if triggered
float holdTime = 0.1;
@@ -152,15 +154,27 @@ struct ScopeDisplay : TransparentWidget {
font = Font::load(assetPlugin(plugin, "res/DejaVuSansMono.ttf"));
}
- void drawWaveform(NVGcontext *vg, float *values, float gain, float offset) {
+ void drawWaveform(NVGcontext *vg, float *valuesX, float *valuesY) {
+ if (!valuesX)
+ return;
nvgSave(vg);
Rect b = Rect(Vec(0, 15), box.size.minus(Vec(0, 15*2)));
nvgScissor(vg, b.pos.x, b.pos.y, b.size.x, b.size.y);
nvgBeginPath(vg);
// Draw maximum display left to right
for (int i = 0; i < BUFFER_SIZE; i++) {
- float value = values[i] * gain + offset;
- Vec p = Vec(b.pos.x + i * b.size.x / (BUFFER_SIZE-1), b.pos.y + b.size.y * (1 - value) / 2);
+ float x, y;
+ if (valuesY) {
+ x = valuesX[i] / 2.0 + 0.5;
+ y = valuesY[i] / 2.0 + 0.5;
+ }
+ else {
+ x = (float)i / (BUFFER_SIZE - 1);
+ y = valuesX[i] / 2.0 + 0.5;
+ }
+ Vec p;
+ p.x = b.pos.x + b.size.x * x;
+ p.y = b.pos.y + b.size.y * (1.0 - y);
if (i == 0)
nvgMoveTo(vg, p.x, p.y);
else
@@ -168,19 +182,19 @@ struct ScopeDisplay : TransparentWidget {
}
nvgLineCap(vg, NVG_ROUND);
nvgMiterLimit(vg, 2.0);
- nvgStrokeWidth(vg, 1.75);
+ nvgStrokeWidth(vg, 1.5);
nvgGlobalCompositeOperation(vg, NVG_LIGHTER);
nvgStroke(vg);
nvgResetScissor(vg);
nvgRestore(vg);
}
- void drawTrig(NVGcontext *vg, float value, float gain, float offset) {
+ void drawTrig(NVGcontext *vg, float value) {
Rect b = Rect(Vec(0, 15), box.size.minus(Vec(0, 15*2)));
nvgScissor(vg, b.pos.x, b.pos.y, b.size.x, b.size.y);
- value = value * gain + offset;
- Vec p = Vec(box.size.x, b.pos.y + b.size.y * (1 - value) / 2);
+ value = value / 2.0 + 0.5;
+ Vec p = Vec(box.size.x, b.pos.y + b.size.y * (1.0 - value));
// Draw line
nvgStrokeColor(vg, nvgRGBA(0xff, 0xff, 0xff, 0x10));
@@ -227,35 +241,46 @@ struct ScopeDisplay : TransparentWidget {
}
void draw(NVGcontext *vg) {
- float gainX = powf(2.0, roundf(module->params[Scope::X_SCALE_PARAM].value)) / 12.0;
- float gainY = powf(2.0, roundf(module->params[Scope::Y_SCALE_PARAM].value)) / 12.0;
- float posX = module->params[Scope::X_POS_PARAM].value;
- float posY = module->params[Scope::Y_POS_PARAM].value;
+ float gainX = powf(2.0, roundf(module->params[Scope::X_SCALE_PARAM].value));
+ float gainY = powf(2.0, roundf(module->params[Scope::Y_SCALE_PARAM].value));
+ float offsetX = module->params[Scope::X_POS_PARAM].value;
+ float offsetY = module->params[Scope::Y_POS_PARAM].value;
+
+ float valuesX[BUFFER_SIZE];
+ float valuesY[BUFFER_SIZE];
+ for (int i = 0; i < BUFFER_SIZE; i++) {
+ int j = i;
+ // Lock display to buffer if buffer update deltaTime <= 2^-11
+ if (module->lissajous)
+ j = (i + module->bufferIndex) % BUFFER_SIZE;
+ valuesX[i] = (module->bufferX[j] + offsetX) * gainX / 10.0;
+ valuesY[i] = (module->bufferY[j] + offsetY) * gainY / 10.0;
+ }
// Draw waveforms
- if (module->sum) {
- float sumBuffer[BUFFER_SIZE];
- for (int i = 0; i < BUFFER_SIZE; i++) {
- sumBuffer[i] = module->bufferX[i] + module->bufferY[i];
+ if (module->lissajous) {
+ // X x Y
+ if (module->inputs[Scope::X_INPUT].active || module->inputs[Scope::Y_INPUT].active) {
+ nvgStrokeColor(vg, nvgRGBA(0x9f, 0xe4, 0x36, 0xc0));
+ drawWaveform(vg, valuesX, valuesY);
}
- // X + Y
- nvgStrokeColor(vg, nvgRGBA(0x9f, 0xe4, 0x36, 0xc0));
- drawWaveform(vg, sumBuffer, gainX, posX);
}
else {
// Y
if (module->inputs[Scope::Y_INPUT].active) {
nvgStrokeColor(vg, nvgRGBA(0xe1, 0x02, 0x78, 0xc0));
- drawWaveform(vg, module->bufferY, gainY, posY);
+ drawWaveform(vg, valuesY, NULL);
}
// X
if (module->inputs[Scope::X_INPUT].active) {
nvgStrokeColor(vg, nvgRGBA(0x28, 0xb0, 0xf3, 0xc0));
- drawWaveform(vg, module->bufferX, gainX, posX);
+ drawWaveform(vg, valuesX, NULL);
}
+
+ float valueTrig = (module->params[Scope::TRIG_PARAM].value + offsetX) * gainX / 10.0;
+ drawTrig(vg, valueTrig);
}
- drawTrig(vg, module->params[Scope::TRIG_PARAM].value, gainX, posX);
// Calculate and draw stats
if (++frame >= 4) {
@@ -294,14 +319,14 @@ ScopeWidget::ScopeWidget() {
addChild(display);
}
- addParam(createParam(Vec(15, 209), module, Scope::X_SCALE_PARAM, -1.0, 9.0, 1.0));
- addParam(createParam(Vec(15, 263), module, Scope::X_POS_PARAM, -1.0, 1.0, 0.0));
- addParam(createParam(Vec(61, 209), module, Scope::Y_SCALE_PARAM, -1.0, 9.0, 1.0));
- addParam(createParam(Vec(61, 263), module, Scope::Y_POS_PARAM, -1.0, 1.0, 0.0));
+ addParam(createParam(Vec(15, 209), module, Scope::X_SCALE_PARAM, -2.0, 8.0, 0.0));
+ addParam(createParam(Vec(15, 263), module, Scope::X_POS_PARAM, -10.0, 10.0, 0.0));
+ addParam(createParam(Vec(61, 209), module, Scope::Y_SCALE_PARAM, -2.0, 8.0, 0.0));
+ addParam(createParam(Vec(61, 263), module, Scope::Y_POS_PARAM, -10.0, 10.0, 0.0));
addParam(createParam(Vec(107, 209), module, Scope::TIME_PARAM, -6.0, -16.0, -14.0));
- addParam(createParam(Vec(106, 262), module, Scope::MODE_PARAM, 0.0, 1.0, 0.0));
- addParam(createParam(Vec(153, 209), module, Scope::TRIG_PARAM, -12.0, 12.0, 0.0));
- addParam(createParam(Vec(152, 262), module, Scope::EXT_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(Vec(106, 262), module, Scope::LISSAJOUS_PARAM, 0.0, 1.0, 0.0));
+ addParam(createParam(Vec(153, 209), module, Scope::TRIG_PARAM, -10.0, 10.0, 0.0));
+ addParam(createParam(Vec(152, 262), module, Scope::EXTERNAL_PARAM, 0.0, 1.0, 0.0));
addInput(createInput(Vec(17, 319), module, Scope::X_INPUT));
addInput(createInput(Vec(63, 319), module, Scope::Y_INPUT));