From 964dae8eac0abf7224930c877ed4055ebf5d39fd Mon Sep 17 00:00:00 2001 From: blancoberg Date: Wed, 4 Dec 2024 09:04:41 +0100 Subject: [PATCH 1/3] lfo display caching * caches the display to a bitmap * only updates when parameters are changed or lua new code is applied --- src/surge-xt/gui/SurgeGUIEditor.cpp | 14 +++ src/surge-xt/gui/SurgeGUIEditor.h | 2 + src/surge-xt/gui/overlays/LuaEditors.cpp | 1 + .../gui/widgets/LFOAndStepDisplay.cpp | 107 +++++++++++++++++- src/surge-xt/gui/widgets/LFOAndStepDisplay.h | 11 ++ 5 files changed, 133 insertions(+), 2 deletions(-) diff --git a/src/surge-xt/gui/SurgeGUIEditor.cpp b/src/surge-xt/gui/SurgeGUIEditor.cpp index be36ae8369f..66f2c4b9c08 100644 --- a/src/surge-xt/gui/SurgeGUIEditor.cpp +++ b/src/surge-xt/gui/SurgeGUIEditor.cpp @@ -3008,6 +3008,17 @@ void SurgeGUIEditor::moveTopLeftTo(float tx, float ty) void SurgeGUIEditor::resizeWindow(float zf) { setZoomFactor(zf, true); } +/* + Called when compiling the lua code from formula editor. + It is called before the draw call. +*/ + +void SurgeGUIEditor::updateAfterApplyCodeFromFormula() +{ + if (lfoDisplay) + lfoDisplay->forceRepaint = true; +} + void SurgeGUIEditor::setZoomFactor(float zf) { setZoomFactor(zf, false); } void SurgeGUIEditor::setZoomFactor(float zf, bool resizeWindow) @@ -3043,6 +3054,9 @@ void SurgeGUIEditor::setZoomFactor(float zf, bool resizeWindow) if (oscWaveform) oscWaveform->setZoomFactor(zoomFactor); + if (lfoDisplay) + lfoDisplay->setZoomFactor(zoomFactor); + setBitmapZoomFactor(zoomFactor); rezoomOverlays(); } diff --git a/src/surge-xt/gui/SurgeGUIEditor.h b/src/surge-xt/gui/SurgeGUIEditor.h index 4b420396d6a..69302445081 100644 --- a/src/surge-xt/gui/SurgeGUIEditor.h +++ b/src/surge-xt/gui/SurgeGUIEditor.h @@ -261,6 +261,8 @@ class SurgeGUIEditor : public Surge::GUI::IComponentTagValue::Listener, SurgeSynthesizer *synth = nullptr; + void updateAfterApplyCodeFromFormula(); + private: void openOrRecreateEditor(); std::unique_ptr makeStorePatchDialog(); diff --git a/src/surge-xt/gui/overlays/LuaEditors.cpp b/src/surge-xt/gui/overlays/LuaEditors.cpp index 9ef18d77b74..e51a044a4e4 100644 --- a/src/surge-xt/gui/overlays/LuaEditors.cpp +++ b/src/surge-xt/gui/overlays/LuaEditors.cpp @@ -950,6 +950,7 @@ void FormulaModulatorEditor::applyCode() editor->undoManager()->pushFormula(scene, lfo_id, *formulastorage); formulastorage->setFormula(mainDocument->getAllContent().toStdString()); storage->getPatch().isDirty = true; + editor->updateAfterApplyCodeFromFormula(); updateDebuggerIfNeeded(); editor->repaintFrame(); juce::SystemClipboard::copyTextToClipboard(formulastorage->formulaString); diff --git a/src/surge-xt/gui/widgets/LFOAndStepDisplay.cpp b/src/surge-xt/gui/widgets/LFOAndStepDisplay.cpp index 2b957d87672..8bbdd340221 100644 --- a/src/surge-xt/gui/widgets/LFOAndStepDisplay.cpp +++ b/src/surge-xt/gui/widgets/LFOAndStepDisplay.cpp @@ -63,6 +63,9 @@ LFOAndStepDisplay::LFOAndStepDisplay(SurgeGUIEditor *e) setAccessible(true); setFocusContainerType(juce::Component::FocusContainerType::focusContainer); + backingImage = std::make_unique(juce::Image::PixelFormat::ARGB, 50, 50, true); + waveformIsUpdated = true; + typeLayer = std::make_unique("LFO Type"); addAndMakeVisible(*typeLayer); for (int i = 0; i < n_lfo_types; ++i) @@ -414,12 +417,112 @@ void LFOAndStepDisplay::paint(juce::Graphics &g) } else { - paintWaveform(g); + + if (!paramsHasChanged()) + { + g.drawImage(*backingImage, getLocalBounds().toFloat(), + juce::RectanglePlacement::fillDestination); + paintTypeSelector(g); + return; + } + else + { + juce::Colour color = + juce::Colour((unsigned char)0, (unsigned char)0, (unsigned char)0, 0.f); + + backingImage->clear(backingImage->getBounds()); + } + + juce::Graphics gr = juce::Graphics(*backingImage); + float zoomFloat = (float)zoomFactor / 100.f; + + gr.addTransform(juce::AffineTransform().scale(zoomFloat * 2.f)); + + paintWaveform(gr); + + g.drawImage(*backingImage, getLocalBounds().toFloat(), + juce::RectanglePlacement::fillDestination); + waveformIsUpdated = false; } paintTypeSelector(g); } +bool LFOAndStepDisplay::paramsHasChanged() +{ + bool hasChanged = false; + + if (paramsFromLastDrawCall[lfodata->delay.param_id_in_scene].i != lfodata->delay.val.i) + hasChanged = true; + if (paramsFromLastDrawCall[lfodata->attack.param_id_in_scene].i != lfodata->attack.val.i) + hasChanged = true; + if (paramsFromLastDrawCall[lfodata->hold.param_id_in_scene].i != lfodata->hold.val.i) + hasChanged = true; + if (paramsFromLastDrawCall[lfodata->decay.param_id_in_scene].i != lfodata->decay.val.i) + hasChanged = true; + if (paramsFromLastDrawCall[lfodata->sustain.param_id_in_scene].i != lfodata->sustain.val.i) + hasChanged = true; + if (paramsFromLastDrawCall[lfodata->release.param_id_in_scene].i != lfodata->release.val.i) + hasChanged = true; + if (paramsFromLastDrawCall[lfodata->magnitude.param_id_in_scene].i != lfodata->magnitude.val.i) + hasChanged = true; + if (paramsFromLastDrawCall[lfodata->rate.param_id_in_scene].i != lfodata->rate.val.i) + hasChanged = true; + if (paramsFromLastDrawCall[lfodata->shape.param_id_in_scene].i != lfodata->shape.val.i) + hasChanged = true; + if (paramsFromLastDrawCall[lfodata->start_phase.param_id_in_scene].i != + lfodata->start_phase.val.i) + hasChanged = true; + if (paramsFromLastDrawCall[lfodata->deform.param_id_in_scene].i != lfodata->deform.val.i) + hasChanged = true; + if (paramsFromLastDrawCall[lfodata->trigmode.param_id_in_scene].i != lm_keytrigger) + hasChanged = true; + if (paramsFromLastDrawCall[lfodata->shape.param_id_in_scene].i != lfodata->shape.val.i) + hasChanged = true; + if (lfoStorageFromLastDrawingCall != lfodata) + hasChanged = true; + + if (forceRepaint) + { + hasChanged = true; + forceRepaint = false; + } + + lfoStorageFromLastDrawingCall = lfodata; + + paramsFromLastDrawCall[lfodata->delay.param_id_in_scene].i = lfodata->delay.val.i; + paramsFromLastDrawCall[lfodata->attack.param_id_in_scene].i = lfodata->attack.val.i; + paramsFromLastDrawCall[lfodata->hold.param_id_in_scene].i = lfodata->hold.val.i; + paramsFromLastDrawCall[lfodata->decay.param_id_in_scene].i = lfodata->decay.val.i; + paramsFromLastDrawCall[lfodata->sustain.param_id_in_scene].i = lfodata->sustain.val.i; + paramsFromLastDrawCall[lfodata->release.param_id_in_scene].i = lfodata->release.val.i; + + paramsFromLastDrawCall[lfodata->magnitude.param_id_in_scene].i = lfodata->magnitude.val.i; + paramsFromLastDrawCall[lfodata->rate.param_id_in_scene].i = lfodata->rate.val.i; + paramsFromLastDrawCall[lfodata->shape.param_id_in_scene].i = lfodata->shape.val.i; + paramsFromLastDrawCall[lfodata->start_phase.param_id_in_scene].i = lfodata->start_phase.val.i; + paramsFromLastDrawCall[lfodata->deform.param_id_in_scene].i = lfodata->deform.val.i; + paramsFromLastDrawCall[lfodata->trigmode.param_id_in_scene].i = lm_keytrigger; + paramsFromLastDrawCall[lfodata->shape.param_id_in_scene].i = lfodata->shape.val.i; + + return hasChanged; +} + +void LFOAndStepDisplay::setZoomFactor(int zoom) +{ + + if (zoomFactor != zoom) + { + float zoomFloat = (float)zoom / 100.f; + forceRepaint = true; + backingImage = std::make_unique(juce::Image::PixelFormat::ARGB, + outer.getWidth() * zoomFloat * 2, + outer.getHeight() * zoomFloat * 2, true); + } + + zoomFactor = zoom; +} + void LFOAndStepDisplay::paintWaveform(juce::Graphics &g) { TimeB mainTimer("-- paintWaveform"); @@ -2440,7 +2543,7 @@ void LFOAndStepDisplay::updateShapeTo(int i) sge->refresh_mod(); sge->broadcastPluginAutomationChangeFor(&(lfodata->shape)); - + forceRepaint = true; repaint(); sge->lfoShapeChanged(prior, i); diff --git a/src/surge-xt/gui/widgets/LFOAndStepDisplay.h b/src/surge-xt/gui/widgets/LFOAndStepDisplay.h index ee0c2088cc6..f6f2694e798 100644 --- a/src/surge-xt/gui/widgets/LFOAndStepDisplay.h +++ b/src/surge-xt/gui/widgets/LFOAndStepDisplay.h @@ -56,6 +56,17 @@ struct LFOAndStepDisplay : public juce::Component, bool isFormula() { return lfodata->shape.val.i == lt_formula; } bool isUnipolar() { return lfodata->unipolar.val.b; } + void setZoomFactor(int); + int zoomFactor; + std::unique_ptr backingImage; + bool waveformIsUpdated; + bool forceRepaint; + LFOStorage *lfoStorageFromLastDrawingCall; + pdata paramsFromLastDrawCall[n_scene_params]; + int zoomFactorFromLastDrawCall; + + bool paramsHasChanged(); + void repaintIfIdIsInRange(int id) { auto *firstLfoParam = &lfodata->rate; From d1e1c25ad895982d8166caa218583348606783dc Mon Sep 17 00:00:00 2001 From: blancoberg Date: Wed, 4 Dec 2024 16:43:17 +0100 Subject: [PATCH 2/3] paramHasChanged() cleanup neat --- .../gui/widgets/LFOAndStepDisplay.cpp | 53 ++++--------------- 1 file changed, 11 insertions(+), 42 deletions(-) diff --git a/src/surge-xt/gui/widgets/LFOAndStepDisplay.cpp b/src/surge-xt/gui/widgets/LFOAndStepDisplay.cpp index 8bbdd340221..095c5695776 100644 --- a/src/surge-xt/gui/widgets/LFOAndStepDisplay.cpp +++ b/src/surge-xt/gui/widgets/LFOAndStepDisplay.cpp @@ -452,33 +452,17 @@ bool LFOAndStepDisplay::paramsHasChanged() { bool hasChanged = false; - if (paramsFromLastDrawCall[lfodata->delay.param_id_in_scene].i != lfodata->delay.val.i) - hasChanged = true; - if (paramsFromLastDrawCall[lfodata->attack.param_id_in_scene].i != lfodata->attack.val.i) - hasChanged = true; - if (paramsFromLastDrawCall[lfodata->hold.param_id_in_scene].i != lfodata->hold.val.i) - hasChanged = true; - if (paramsFromLastDrawCall[lfodata->decay.param_id_in_scene].i != lfodata->decay.val.i) - hasChanged = true; - if (paramsFromLastDrawCall[lfodata->sustain.param_id_in_scene].i != lfodata->sustain.val.i) - hasChanged = true; - if (paramsFromLastDrawCall[lfodata->release.param_id_in_scene].i != lfodata->release.val.i) - hasChanged = true; - if (paramsFromLastDrawCall[lfodata->magnitude.param_id_in_scene].i != lfodata->magnitude.val.i) - hasChanged = true; - if (paramsFromLastDrawCall[lfodata->rate.param_id_in_scene].i != lfodata->rate.val.i) - hasChanged = true; - if (paramsFromLastDrawCall[lfodata->shape.param_id_in_scene].i != lfodata->shape.val.i) - hasChanged = true; - if (paramsFromLastDrawCall[lfodata->start_phase.param_id_in_scene].i != - lfodata->start_phase.val.i) - hasChanged = true; - if (paramsFromLastDrawCall[lfodata->deform.param_id_in_scene].i != lfodata->deform.val.i) - hasChanged = true; - if (paramsFromLastDrawCall[lfodata->trigmode.param_id_in_scene].i != lm_keytrigger) - hasChanged = true; - if (paramsFromLastDrawCall[lfodata->shape.param_id_in_scene].i != lfodata->shape.val.i) - hasChanged = true; + auto *p = &lfodata->rate; // look in the definition of LFOStorage for which param is first + while (p <= &lfodata->release) // and last + { + + if (paramsFromLastDrawCall[p->param_id_in_scene].i != p->val.i) + hasChanged = true; + + paramsFromLastDrawCall[p->param_id_in_scene].i = p->val.i; + ++p; + }; + if (lfoStorageFromLastDrawingCall != lfodata) hasChanged = true; @@ -490,21 +474,6 @@ bool LFOAndStepDisplay::paramsHasChanged() lfoStorageFromLastDrawingCall = lfodata; - paramsFromLastDrawCall[lfodata->delay.param_id_in_scene].i = lfodata->delay.val.i; - paramsFromLastDrawCall[lfodata->attack.param_id_in_scene].i = lfodata->attack.val.i; - paramsFromLastDrawCall[lfodata->hold.param_id_in_scene].i = lfodata->hold.val.i; - paramsFromLastDrawCall[lfodata->decay.param_id_in_scene].i = lfodata->decay.val.i; - paramsFromLastDrawCall[lfodata->sustain.param_id_in_scene].i = lfodata->sustain.val.i; - paramsFromLastDrawCall[lfodata->release.param_id_in_scene].i = lfodata->release.val.i; - - paramsFromLastDrawCall[lfodata->magnitude.param_id_in_scene].i = lfodata->magnitude.val.i; - paramsFromLastDrawCall[lfodata->rate.param_id_in_scene].i = lfodata->rate.val.i; - paramsFromLastDrawCall[lfodata->shape.param_id_in_scene].i = lfodata->shape.val.i; - paramsFromLastDrawCall[lfodata->start_phase.param_id_in_scene].i = lfodata->start_phase.val.i; - paramsFromLastDrawCall[lfodata->deform.param_id_in_scene].i = lfodata->deform.val.i; - paramsFromLastDrawCall[lfodata->trigmode.param_id_in_scene].i = lm_keytrigger; - paramsFromLastDrawCall[lfodata->shape.param_id_in_scene].i = lfodata->shape.val.i; - return hasChanged; } From 55ac0f894c7883d3a5597ad1f49a7e79239d011c Mon Sep 17 00:00:00 2001 From: blancoberg Date: Wed, 4 Dec 2024 21:00:45 +0100 Subject: [PATCH 3/3] repaint addon * Repaints on tempo changed * Repaints on MSEG editor change --- src/surge-xt/gui/SurgeGUIEditor.cpp | 2 +- src/surge-xt/gui/SurgeGUIEditor.h | 2 +- src/surge-xt/gui/overlays/LuaEditors.cpp | 2 +- src/surge-xt/gui/overlays/MSEGEditor.cpp | 1 + src/surge-xt/gui/widgets/LFOAndStepDisplay.h | 1 + 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/surge-xt/gui/SurgeGUIEditor.cpp b/src/surge-xt/gui/SurgeGUIEditor.cpp index 66f2c4b9c08..7dea5ae03d4 100644 --- a/src/surge-xt/gui/SurgeGUIEditor.cpp +++ b/src/surge-xt/gui/SurgeGUIEditor.cpp @@ -3013,7 +3013,7 @@ void SurgeGUIEditor::resizeWindow(float zf) { setZoomFactor(zf, true); } It is called before the draw call. */ -void SurgeGUIEditor::updateAfterApplyCodeFromFormula() +void SurgeGUIEditor::forceLfoDisplayRepaint() { if (lfoDisplay) lfoDisplay->forceRepaint = true; diff --git a/src/surge-xt/gui/SurgeGUIEditor.h b/src/surge-xt/gui/SurgeGUIEditor.h index 69302445081..3160767a429 100644 --- a/src/surge-xt/gui/SurgeGUIEditor.h +++ b/src/surge-xt/gui/SurgeGUIEditor.h @@ -261,7 +261,7 @@ class SurgeGUIEditor : public Surge::GUI::IComponentTagValue::Listener, SurgeSynthesizer *synth = nullptr; - void updateAfterApplyCodeFromFormula(); + void forceLfoDisplayRepaint(); private: void openOrRecreateEditor(); diff --git a/src/surge-xt/gui/overlays/LuaEditors.cpp b/src/surge-xt/gui/overlays/LuaEditors.cpp index e51a044a4e4..f0b04d2a4bd 100644 --- a/src/surge-xt/gui/overlays/LuaEditors.cpp +++ b/src/surge-xt/gui/overlays/LuaEditors.cpp @@ -950,7 +950,7 @@ void FormulaModulatorEditor::applyCode() editor->undoManager()->pushFormula(scene, lfo_id, *formulastorage); formulastorage->setFormula(mainDocument->getAllContent().toStdString()); storage->getPatch().isDirty = true; - editor->updateAfterApplyCodeFromFormula(); + editor->forceLfoDisplayRepaint(); updateDebuggerIfNeeded(); editor->repaintFrame(); juce::SystemClipboard::copyTextToClipboard(formulastorage->formulaString); diff --git a/src/surge-xt/gui/overlays/MSEGEditor.cpp b/src/surge-xt/gui/overlays/MSEGEditor.cpp index 10581fb0a6a..c510ee900eb 100644 --- a/src/surge-xt/gui/overlays/MSEGEditor.cpp +++ b/src/surge-xt/gui/overlays/MSEGEditor.cpp @@ -2791,6 +2791,7 @@ struct MSEGCanvas : public juce::Component, public Surge::GUI::SkinConsumingComp storage->getPatch().isDirty = true; tagForUndo(); } + this->sge->forceLfoDisplayRepaint(); onModelChanged(); repaint(); } diff --git a/src/surge-xt/gui/widgets/LFOAndStepDisplay.h b/src/surge-xt/gui/widgets/LFOAndStepDisplay.h index f6f2694e798..27086d26039 100644 --- a/src/surge-xt/gui/widgets/LFOAndStepDisplay.h +++ b/src/surge-xt/gui/widgets/LFOAndStepDisplay.h @@ -94,6 +94,7 @@ struct LFOAndStepDisplay : public juce::Component, { if (isAnythingTemposynced()) { + forceRepaint = true; repaint(); } }