diff --git a/src/common/SurgePatch.cpp b/src/common/SurgePatch.cpp index cb823b460e2..660f5048ac1 100644 --- a/src/common/SurgePatch.cpp +++ b/src/common/SurgePatch.cpp @@ -2354,6 +2354,36 @@ void SurgePatch::load_xml(const void *data, int datasize, bool is_preset) scene[0].modsources[ms_ctrl1 + i]->reset(); } + { + /* + * Reset to UNSCALED then try and read + */ + for (int sc = 0; sc < n_scenes; sc++) + { + for (int l = 0; l < n_lfos; l++) + { + scene[sc].lfo[l].lfoExtraAmplitude = LFOStorage::UNSCALED; + } + } + auto *el = TINYXML_SAFE_TO_ELEMENT(patch->FirstChild("extralfo")); + if (el) + { + auto l = TINYXML_SAFE_TO_ELEMENT(el->FirstChild("lfo")); + while (l) + { + int sc, id, val; + if (l->QueryIntAttribute("scene", &sc) == TIXML_SUCCESS && + l->QueryIntAttribute("i", &id) == TIXML_SUCCESS && + l->QueryIntAttribute("extraAmplitude", &val) == TIXML_SUCCESS && sc >= 0 && + id >= 0 && sc < n_scenes && id < n_lfos) + { + scene[sc].lfo[id].lfoExtraAmplitude = (LFOStorage::LFOExtraOutputAmplitude)val; + } + l = TINYXML_SAFE_TO_ELEMENT(l->NextSiblingElement("lfo")); + } + } + } + TiXmlElement *cc = TINYXML_SAFE_TO_ELEMENT(patch->FirstChild("customcontroller")); if (cc) @@ -3181,6 +3211,21 @@ unsigned int SurgePatch::save_xml(void **data) // allocates mem, must be freed b } patch.InsertEndChild(formulae); + TiXmlElement extralfo("extralfo"); + for (int sc = 0; sc < n_scenes; sc++) + { + for (int l = 0; l < n_lfos; l++) + { + TiXmlElement p("lfo"); + p.SetAttribute("scene", sc); + p.SetAttribute("i", l); + + p.SetAttribute("extraAmplitude", scene[sc].lfo[l].lfoExtraAmplitude); + extralfo.InsertEndChild(p); + } + } + patch.InsertEndChild(extralfo); + TiXmlElement cc("customcontroller"); for (int l = 0; l < n_customcontrollers; l++) { diff --git a/src/common/SurgeStorage.h b/src/common/SurgeStorage.h index 08528634808..beee784c3dc 100644 --- a/src/common/SurgeStorage.h +++ b/src/common/SurgeStorage.h @@ -607,6 +607,12 @@ struct LFOStorage Parameter rate, shape, start_phase, magnitude, deform; Parameter trigmode, unipolar; Parameter delay, hold, attack, decay, sustain, release; + + enum LFOExtraOutputAmplitude + { + UNSCALED, + SCALED + } lfoExtraAmplitude{UNSCALED}; }; struct FxStorage diff --git a/src/common/dsp/modulators/LFOModulationSource.cpp b/src/common/dsp/modulators/LFOModulationSource.cpp index 5ed50e76450..eeeb57c33fe 100644 --- a/src/common/dsp/modulators/LFOModulationSource.cpp +++ b/src/common/dsp/modulators/LFOModulationSource.cpp @@ -1255,6 +1255,12 @@ void LFOModulationSource::process_block() output_multi[1] = io2; output_multi[2] = outputEnvVal + useenv0; // env_val; + if (lfo->lfoExtraAmplitude == LFOStorage::SCALED) + { + output_multi[1] *= magnf; + output_multi[2] *= magnf; + } + if (s == lt_envelope) { // Additional start mode corrections required diff --git a/src/surge-xt/gui/widgets/ModulationSourceButton.cpp b/src/surge-xt/gui/widgets/ModulationSourceButton.cpp index a763198b240..14bdd175d09 100644 --- a/src/surge-xt/gui/widgets/ModulationSourceButton.cpp +++ b/src/surge-xt/gui/widgets/ModulationSourceButton.cpp @@ -406,6 +406,30 @@ void ModulationSourceButton::buildHamburgerMenu(juce::PopupMenu &menu, idx++; } + + if (modsource >= ms_lfo1 && modsource <= ms_slfo6) + { + auto &lf = + sge->getStorage()->getPatch().scene[sge->current_scene].lfo[modsource - ms_lfo1]; + + auto sh = lf.shape.val.i; + if (sh != lt_formula) + { + menu.addSeparator(); + bool sc = lf.lfoExtraAmplitude == LFOStorage::SCALED; + menu.addItem(Surge::GUI::toOSCase("Scale Raw / EG By Amplitude"), true, sc, + [sge, modsource] { + auto &lf = sge->getStorage() + ->getPatch() + .scene[sge->current_scene] + .lfo[modsource - ms_lfo1]; + if (lf.lfoExtraAmplitude == LFOStorage::SCALED) + lf.lfoExtraAmplitude = LFOStorage::UNSCALED; + else + lf.lfoExtraAmplitude = LFOStorage::SCALED; + }); + } + } } }