From aab7c06ec0cd92c98fa4d56fd30e92c538b3512d Mon Sep 17 00:00:00 2001 From: Paul Walker Date: Sat, 23 Apr 2022 12:41:01 -0400 Subject: [PATCH] Final undo gestures on stack 1. Parameter temposync etc 2. Full LFO on LFO menu reset Addresses #694 --- src/surge-xt/gui/SurgeGUIEditor.cpp | 9 +- src/surge-xt/gui/SurgeGUIEditor.h | 1 + src/surge-xt/gui/UndoManager.cpp | 167 ++++++++++++++++++++++++++-- src/surge-xt/gui/UndoManager.h | 1 + 4 files changed, 165 insertions(+), 13 deletions(-) diff --git a/src/surge-xt/gui/SurgeGUIEditor.cpp b/src/surge-xt/gui/SurgeGUIEditor.cpp index 1723efbe578..6dcddf93a00 100644 --- a/src/surge-xt/gui/SurgeGUIEditor.cpp +++ b/src/surge-xt/gui/SurgeGUIEditor.cpp @@ -2460,10 +2460,16 @@ void SurgeGUIEditor::setMacroValueFromUndo(int ccid, float val) void SurgeGUIEditor::pushParamToUndoRedo(int paramId, Surge::GUI::UndoManager::Target which) { auto p = synth->storage.getPatch().param_ptr[paramId]; - auto id = synth->idForParameter(p); undoManager()->pushParameterChange(paramId, p, p->val, which); } +void SurgeGUIEditor::applyToParamForUndo(int paramId, std::function f) +{ + auto p = synth->storage.getPatch().param_ptr[paramId]; + f(p); + synth->refresh_editor = true; +} + void SurgeGUIEditor::setModulationFromUndo(int paramId, modsources ms, int scene, int idx, float val, bool muted) { @@ -2876,6 +2882,7 @@ juce::PopupMenu SurgeGUIEditor::makeLfoMenu(const juce::Point &where) for (const auto &p : cat.presets) { auto action = [this, p, currentLfoId]() { + undoManager()->pushFullLFO(current_scene, currentLfoId); this->synth->storage.modulatorPreset->loadPresetFrom( p.path, &(this->synth->storage), current_scene, currentLfoId); diff --git a/src/surge-xt/gui/SurgeGUIEditor.h b/src/surge-xt/gui/SurgeGUIEditor.h index c67198d010c..54af63b54d1 100644 --- a/src/surge-xt/gui/SurgeGUIEditor.h +++ b/src/surge-xt/gui/SurgeGUIEditor.h @@ -489,6 +489,7 @@ class SurgeGUIEditor : public Surge::GUI::IComponentTagValue::Listener, const std::unique_ptr &undoManager(); void setParamFromUndo(int paramId, pdata val); void pushParamToUndoRedo(int paramId, Surge::GUI::UndoManager::Target which); + void applyToParamForUndo(int paramId, std::function f); void setModulationFromUndo(int paramId, modsources ms, int scene, int idx, float val, bool muted); void pushModulationToUndoRedo(int paramId, modsources ms, int scene, int idx, diff --git a/src/surge-xt/gui/UndoManager.cpp b/src/surge-xt/gui/UndoManager.cpp index 33fcecf83de..d36c4ff95d0 100644 --- a/src/surge-xt/gui/UndoManager.cpp +++ b/src/surge-xt/gui/UndoManager.cpp @@ -60,6 +60,8 @@ struct UndoManagerImpl struct UndoParam { int paramId; + std::string name; + bool temposync, absolute, deactivated, extend_range, deform_type; pdata val; }; struct UndoModulation @@ -76,13 +78,13 @@ struct UndoManagerImpl int oscNum; int scene; int type; - std::vector> paramIdValues; + std::vector undoParamValues; }; struct UndoFX { int fxslot; int type; - std::vector> paramIdValues; + std::vector undoParamValues; }; struct UndoStep { @@ -102,6 +104,13 @@ struct UndoManagerImpl int lfoid; FormulaModulatorStorage storageCopy; }; + struct UndoFullLFO + { + int scene; + int lfoid; + std::vector undoParamValues; + std::variant extraStorage; + }; struct UndoRename { bool isMacro; @@ -129,7 +138,7 @@ struct UndoManagerImpl // If you add a new type here add it both to aboutTheSameThing, toString, and // to undo. typedef std::variant + UndoFormula, UndoRename, UndoMacro, UndoTuning, UndoPatch, UndoFullLFO> UndoAction; struct UndoRecord { @@ -212,6 +221,11 @@ struct UndoManagerImpl // UndoPatch is always different return false; } + if (auto pa = std::get_if(&a)) + { + // No way to generate these other than discretely + return false; + } return false; } @@ -266,6 +280,10 @@ struct UndoManagerImpl { return fmt::format("Patch[]"); } + if (auto pa = std::get_if(&a)) + { + return fmt::format("FullLFO[]"); + } return "UNK"; } @@ -332,11 +350,35 @@ struct UndoManagerImpl } } + void populateUndoParamFromP(const Parameter *p, pdata val, UndoParam &r) + { + r.name = p->fullname; + r.temposync = p->temposync; + r.absolute = p->absolute; + r.deactivated = p->deactivated; + r.extend_range = p->extend_range; + r.deform_type = p->deform_type; + + r.val = val; + } + + void restoreParamToEditor(const UndoParam *pa) + { + editor->setParamFromUndo(pa->paramId, pa->val); + editor->applyToParamForUndo(pa->paramId, [pa](Parameter *p) { + p->temposync = pa->temposync; + p->absolute = pa->absolute; + p->deactivated = pa->deactivated; + p->set_extend_range(pa->extend_range); + p->deform_type = pa->deform_type; + }); + } + void pushParameterChange(int paramId, const Parameter *p, pdata val, UndoManager::Target to) { auto r = UndoParam(); r.paramId = paramId; - r.val = val; + populateUndoParamFromP(p, val, r); if (to == UndoManager::UNDO) pushUndo(r); else @@ -371,7 +413,10 @@ struct UndoManagerImpl p++; while (p <= &(os->retrigger)) { - r.paramIdValues.emplace_back(p->id, p->val); + auto pu = UndoParam(); + pu.paramId = p->id; + populateUndoParamFromP(p, p->val, pu); + r.undoParamValues.emplace_back(pu); p++; } @@ -390,7 +435,11 @@ struct UndoManagerImpl for (int i = 0; i < n_fx_params; ++i) { - r.paramIdValues.emplace_back(fx->p[i].id, fx->p[i].val); + auto *p = &(fx->p[i]); + auto pu = UndoParam(); + pu.paramId = p->id; + populateUndoParamFromP(p, p->val, pu); + r.undoParamValues.emplace_back(pu); } if (to == UndoManager::UNDO) @@ -425,6 +474,46 @@ struct UndoManagerImpl pushRedo(r); } + void pushFullLFO(int scene, int lfoid, UndoManager::Target to = UndoManager::UNDO) + { + UndoFullLFO r; + r.scene = scene; + r.lfoid = lfoid; + auto lf = &(editor->getPatch().scene[scene].lfo[lfoid]); + if (lf->shape.val.i == lt_mseg) + { + r.extraStorage = editor->getPatch().msegs[scene][lfoid]; + } + else if (lf->shape.val.i == lt_formula) + { + r.extraStorage = editor->getPatch().formulamods[scene][lfoid]; + } + else if (lf->shape.val.i == lt_stepseq) + { + r.extraStorage = editor->getPatch().stepsequences[scene][lfoid]; + } + else + { + r.extraStorage = false; + } + + Parameter *p = &(lf->rate); + + while (p <= &(lf->release)) + { + auto pu = UndoParam(); + pu.paramId = p->id; + populateUndoParamFromP(p, p->val, pu); + r.undoParamValues.emplace_back(pu); + p++; + } + + if (to == UndoManager::UNDO) + pushUndo(r); + else + pushRedo(r); + } + void pushFormula(int scene, int lfoid, const FormulaModulatorStorage &pushValue, UndoManager::Target to = UndoManager::UNDO) { @@ -534,34 +623,74 @@ struct UndoManagerImpl auto opposite = (which == UndoManager::UNDO ? UndoManager::REDO : UndoManager::UNDO); // this would be cleaner with std:visit but visit isn't in macos libc until 10.13 - if (auto p = std::get_if(&q)) + if (auto pa = std::get_if(&q)) { - editor->pushParamToUndoRedo(p->paramId, opposite); - editor->setParamFromUndo(p->paramId, p->val); + editor->pushParamToUndoRedo(pa->paramId, opposite); + auto g = SelfPushGuard(this); + restoreParamToEditor(pa); return true; } if (auto p = std::get_if(&q)) { editor->pushModulationToUndoRedo(p->paramId, p->ms, p->scene, p->index, opposite); + auto g = SelfPushGuard(this); editor->setModulationFromUndo(p->paramId, p->ms, p->scene, p->index, p->val, p->muted); return true; } if (auto p = std::get_if(&q)) { pushOscillator(p->scene, p->oscNum, opposite); + auto g = SelfPushGuard(this); auto os = &(synth->storage.getPatch().scene[p->scene].osc[p->oscNum]); os->type.val.i = p->type; synth->storage.getPatch().update_controls(false, os, false); - for (auto q : p->paramIdValues) + for (const auto &qp : p->undoParamValues) + { + restoreParamToEditor(&qp); + } + return true; + } + if (auto p = std::get_if(&q)) + { + pushFullLFO(p->scene, p->lfoid, opposite); + auto g = SelfPushGuard(this); + auto lf = &(synth->storage.getPatch().scene[p->scene].lfo[p->lfoid]); + + for (const auto &qp : p->undoParamValues) + { + restoreParamToEditor(&qp); + } + if (lf->shape.val.i == lt_mseg) + { + auto ms = std::get_if(&p->extraStorage); + if (ms) + { + editor->setMSEGFromUndo(p->scene, p->lfoid, *ms); + } + } + else if (lf->shape.val.i == lt_formula) + { + auto ms = std::get_if(&p->extraStorage); + if (ms) + { + editor->setFormulaFromUndo(p->scene, p->lfoid, *ms); + } + } + else if (lf->shape.val.i == lt_stepseq) { - editor->setParamFromUndo(q.first, q.second); + auto ms = std::get_if(&p->extraStorage); + if (ms) + { + editor->setStepSequencerFromUndo(p->scene, p->lfoid, *ms); + } } return true; } if (auto p = std::get_if(&q)) { pushFX(p->fxslot, opposite); + auto spg = SelfPushGuard(this); std::lock_guard g(synth->fxSpawnMutex); int cge = p->fxslot; @@ -581,7 +710,13 @@ struct UndoManagerImpl synth->fx_reload[cge] = true; for (int i = 0; i < n_fx_params; ++i) { - synth->fxsync[cge].p[i].val = p->paramIdValues[i].second; + auto *pa = &(synth->fxsync[cge].p[i]); + pa->val = p->undoParamValues[i].val; + pa->temposync = p->undoParamValues[i].temposync; + pa->absolute = p->undoParamValues[i].absolute; + pa->deactivated = p->undoParamValues[i].deactivated; + pa->set_extend_range(p->undoParamValues[i].extend_range); + pa->deform_type = p->undoParamValues[i].deform_type; } return true; } @@ -589,12 +724,14 @@ struct UndoManagerImpl { pushStepSequencer(p->scene, p->lfoid, editor->getPatch().stepsequences[p->scene][p->lfoid], opposite); + auto g = SelfPushGuard(this); editor->setStepSequencerFromUndo(p->scene, p->lfoid, p->storageCopy); return true; } if (auto p = std::get_if(&q)) { pushMSEG(p->scene, p->lfoid, editor->getPatch().msegs[p->scene][p->lfoid], opposite); + auto g = SelfPushGuard(this); editor->setMSEGFromUndo(p->scene, p->lfoid, p->storageCopy); return true; } @@ -602,6 +739,7 @@ struct UndoManagerImpl { pushFormula(p->scene, p->lfoid, editor->getPatch().formulamods[p->scene][p->lfoid], opposite); + auto g = SelfPushGuard(this); editor->setFormulaFromUndo(p->scene, p->lfoid, p->storageCopy); return true; } @@ -611,12 +749,14 @@ struct UndoManagerImpl { auto nm = editor->getPatch().CustomControllerLabel[p->itemid]; pushMacroOrLFORename(true, nm, -1, p->itemid, -1, opposite); + auto g = SelfPushGuard(this); editor->setMacroNameFromUndo(p->itemid, p->name); } else { auto nm = editor->getPatch().LFOBankLabel[p->scene][p->itemid][p->index]; pushMacroOrLFORename(false, nm, p->scene, p->itemid, p->index, opposite); + auto g = SelfPushGuard(this); editor->setLFONameFromUndo(p->scene, p->itemid, p->index, p->name); } return true; @@ -627,6 +767,7 @@ struct UndoManagerImpl .scene[editor->current_scene] .modsources[p->macro + ms_ctrl1]); pushMacroChange(p->macro, cms->get_target01(0), opposite); + auto g = SelfPushGuard(this); editor->setMacroValueFromUndo(p->macro, p->val); return true; } @@ -737,6 +878,8 @@ void UndoManager::pushMacroChange(int macroid, float val) { impl->pushMacroChang void UndoManager::pushPatch() { impl->pushPatch(); } +void UndoManager::pushFullLFO(int scene, int lfoid) { impl->pushFullLFO(scene, lfoid); } + bool UndoManager::canUndo() { return !impl->undoStack.empty(); } bool UndoManager::canRedo() { return !impl->redoStack.empty(); } diff --git a/src/surge-xt/gui/UndoManager.h b/src/surge-xt/gui/UndoManager.h index fca3000cc74..ae0caf358e3 100644 --- a/src/surge-xt/gui/UndoManager.h +++ b/src/surge-xt/gui/UndoManager.h @@ -52,6 +52,7 @@ struct UndoManager void pushOscillator(int scene, int oscnum); void pushStepSequencer(int scene, int lfoid, const StepSequencerStorage &pushValue); void pushMSEG(int scene, int lfoid, const MSEGStorage &pushValue); + void pushFullLFO(int scene, int lfoid); void pushFormula(int scene, int lfoid, const FormulaModulatorStorage &pushValue); void pushFX(int fxslot);