Skip to content

Commit

Permalink
Final undo gestures on stack
Browse files Browse the repository at this point in the history
1. Parameter temposync etc
2. Full LFO on LFO menu reset

Addresses surge-synthesizer#694
  • Loading branch information
baconpaul committed Apr 23, 2022
1 parent 24bfd69 commit aab7c06
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 13 deletions.
9 changes: 8 additions & 1 deletion src/surge-xt/gui/SurgeGUIEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<void(Parameter *)> 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)
{
Expand Down Expand Up @@ -2876,6 +2882,7 @@ juce::PopupMenu SurgeGUIEditor::makeLfoMenu(const juce::Point<int> &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);

Expand Down
1 change: 1 addition & 0 deletions src/surge-xt/gui/SurgeGUIEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,7 @@ class SurgeGUIEditor : public Surge::GUI::IComponentTagValue::Listener,
const std::unique_ptr<Surge::GUI::UndoManager> &undoManager();
void setParamFromUndo(int paramId, pdata val);
void pushParamToUndoRedo(int paramId, Surge::GUI::UndoManager::Target which);
void applyToParamForUndo(int paramId, std::function<void(Parameter *)> 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,
Expand Down
167 changes: 155 additions & 12 deletions src/surge-xt/gui/UndoManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -76,13 +78,13 @@ struct UndoManagerImpl
int oscNum;
int scene;
int type;
std::vector<std::pair<int, pdata>> paramIdValues;
std::vector<UndoParam> undoParamValues;
};
struct UndoFX
{
int fxslot;
int type;
std::vector<std::pair<int, pdata>> paramIdValues;
std::vector<UndoParam> undoParamValues;
};
struct UndoStep
{
Expand All @@ -102,6 +104,13 @@ struct UndoManagerImpl
int lfoid;
FormulaModulatorStorage storageCopy;
};
struct UndoFullLFO
{
int scene;
int lfoid;
std::vector<UndoParam> undoParamValues;
std::variant<bool, MSEGStorage, StepSequencerStorage, FormulaModulatorStorage> extraStorage;
};
struct UndoRename
{
bool isMacro;
Expand Down Expand Up @@ -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<UndoParam, UndoModulation, UndoOscillator, UndoFX, UndoStep, UndoMSEG,
UndoFormula, UndoRename, UndoMacro, UndoTuning, UndoPatch>
UndoFormula, UndoRename, UndoMacro, UndoTuning, UndoPatch, UndoFullLFO>
UndoAction;
struct UndoRecord
{
Expand Down Expand Up @@ -212,6 +221,11 @@ struct UndoManagerImpl
// UndoPatch is always different
return false;
}
if (auto pa = std::get_if<UndoFullLFO>(&a))
{
// No way to generate these other than discretely
return false;
}
return false;
}

Expand Down Expand Up @@ -266,6 +280,10 @@ struct UndoManagerImpl
{
return fmt::format("Patch[]");
}
if (auto pa = std::get_if<UndoFullLFO>(&a))
{
return fmt::format("FullLFO[]");
}
return "UNK";
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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++;
}

Expand All @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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<UndoParam>(&q))
if (auto pa = std::get_if<UndoParam>(&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<UndoModulation>(&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<UndoOscillator>(&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<UndoFullLFO>(&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<MSEGStorage>(&p->extraStorage);
if (ms)
{
editor->setMSEGFromUndo(p->scene, p->lfoid, *ms);
}
}
else if (lf->shape.val.i == lt_formula)
{
auto ms = std::get_if<FormulaModulatorStorage>(&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<StepSequencerStorage>(&p->extraStorage);
if (ms)
{
editor->setStepSequencerFromUndo(p->scene, p->lfoid, *ms);
}
}
return true;
}
if (auto p = std::get_if<UndoFX>(&q))
{
pushFX(p->fxslot, opposite);
auto spg = SelfPushGuard(this);
std::lock_guard<std::mutex> g(synth->fxSpawnMutex);

int cge = p->fxslot;
Expand All @@ -581,27 +710,36 @@ 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;
}
if (auto p = std::get_if<UndoStep>(&q))
{
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<UndoMSEG>(&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;
}
if (auto p = std::get_if<UndoFormula>(&q))
{
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;
}
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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(); }
Expand Down
1 change: 1 addition & 0 deletions src/surge-xt/gui/UndoManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit aab7c06

Please sign in to comment.