diff --git a/src/synth/mod_matrix.cpp b/src/synth/mod_matrix.cpp index 3d9de25..dca0010 100644 --- a/src/synth/mod_matrix.cpp +++ b/src/synth/mod_matrix.cpp @@ -14,18 +14,18 @@ */ #include "mod_matrix.h" -#include "sst/cpputils/constructors.h" +#include namespace baconpaul::six_sines { ModMatrixConfig::ModMatrixConfig() { - add(OFF, "", "OFF"); + add(OFF, "", "Off"); add(CHANNEL_AT, "MIDI", "Channel AT"); add(PITCH_BEND, "MIDI", "Pitch Bend"); for (int cc = 0; cc < 128; ++cc) - add(MIDICC_0 + cc, "MIDI CC", "CC " + std::to_string(cc + 1)); + add(MIDICC_0 + cc, "MIDI CC", fmt::format("CC {:03d}", cc + 1)); for (int mc = 0; mc < numMacros; ++mc) add(MACRO_0 + mc, "Macros", "Macro " + std::to_string(mc + 1)); @@ -37,8 +37,25 @@ ModMatrixConfig::ModMatrixConfig() add(MPE_PRESSURE, "MPE", "Pressure"); add(MPE_TIMBRE, "MPE", "Timbre"); + + std::sort(sources.begin(), sources.end(), + [](const SourceObj &a, const SourceObj &b) + { + if (a.group != b.group) + return a.group < b.group; + if (a.name != b.name) + return a.name < b.name; + return a.id < b.id; + }); + for (auto &s : sources) + { + sourceByID[s.id] = s; + } } -void ModMatrixConfig::add(int s, const std::string &group, const std::string &nm) {} +void ModMatrixConfig::add(int s, const std::string &group, const std::string &nm) +{ + sources.push_back({s, group, nm}); +} } // namespace baconpaul::six_sines \ No newline at end of file diff --git a/src/synth/mod_matrix.h b/src/synth/mod_matrix.h index faf68cb..8362a8a 100644 --- a/src/synth/mod_matrix.h +++ b/src/synth/mod_matrix.h @@ -57,6 +57,14 @@ struct ModMatrixConfig ModMatrixConfig(); void add(int s, const std::string &group, const std::string &nm); + struct SourceObj + { + int id; + std::string group; + std::string name; + }; + std::vector sources; + std::unordered_map sourceByID; }; } // namespace baconpaul::six_sines #endif // MOD_MATRIX_H diff --git a/src/ui/modulation-components.h b/src/ui/modulation-components.h index 9d990f0..694a337 100644 --- a/src/ui/modulation-components.h +++ b/src/ui/modulation-components.h @@ -30,8 +30,11 @@ template struct ModulationComponents { Comp *asComp() { return static_cast(this); } ModulationComponents() {} + + const Patch *patchPtr{nullptr}; void setupModulation(SixSinesEditor &e, const Patch &v) { + patchPtr = &v; auto c = asComp(); modTitleLab = std::make_unique(); modTitleLab->setText("Modulation"); @@ -42,6 +45,13 @@ template struct ModulationComponents createComponent(e, *c, v.moddepth[i], depthSlider[i], depthSliderD[i]); sourceMenu[i] = std::make_unique(); resetSourceLabel(i); + sourceMenu[i]->setOnCallback( + [w = juce::Component::SafePointer(asComp())]() + { + if (!w) + return; + w->showSourceMenu(); + }); e.componentRefreshByID[v.modsource[i].meta.id] = [i, w = juce::Component::SafePointer(c)]() { @@ -67,7 +77,25 @@ template struct ModulationComponents } } - void resetSourceLabel(int i) { sourceMenu[i]->setLabel("Src " + std::to_string(i + 1)); } + void resetSourceLabel(int i) + { + if (!patchPtr) + { + sourceMenu[i]->setLabel(""); + return; + } + auto v = (uint32_t)std::round(patchPtr->modsource[i].value); + + auto p = asComp()->editor.modMatrixConfig.sourceByID.find(v); + if (p != asComp()->editor.modMatrixConfig.sourceByID.end()) + { + sourceMenu[i]->setLabel(p->second.name); + } + else + { + sourceMenu[i]->setLabel("UNK " + std::to_string(v)); + } + } void resetTargetLabel(int i) { targetMenu[i]->setLabel("Tgt " + std::to_string(i + 1)); } @@ -93,6 +121,38 @@ template struct ModulationComponents } } + void showSourceMenu() + { + SXSNLOG("Show Source Menu"); + auto p = juce::PopupMenu(); + p.addSectionHeader("Modulation Source"); + p.addSeparator(); + std::string currCat{}; + auto s = juce::PopupMenu(); + for (const auto &so : asComp()->editor.modMatrixConfig.sources) + { + if (so.group.empty()) + { + p.addItem(so.name, [i = so.id]() { SXSNLOG("With " << i); }); + } + else + { + if (so.group != currCat && s.getNumItems() > 0) + { + p.addSubMenu(currCat, s); + s = juce::PopupMenu(); + } + currCat = so.group; + s.addItem(so.name, [i = so.id]() { SXSNLOG("With " << i); }); + } + } + if (s.getNumItems() > 0) + { + p.addSubMenu(currCat, s); + } + p.showMenuAsync(juce::PopupMenu::Options().withParentComponent(&asComp()->editor)); + } + std::unique_ptr modTitleLab; std::array, numModsPer> sourceMenu; diff --git a/src/ui/six-sines-editor.h b/src/ui/six-sines-editor.h index 6dfef30..db02c76 100644 --- a/src/ui/six-sines-editor.h +++ b/src/ui/six-sines-editor.h @@ -51,6 +51,8 @@ struct SixSinesJuceLookAndFeel; struct SixSinesEditor : jcmp::WindowPanel { Patch patchCopy; + ModMatrixConfig modMatrixConfig; + Synth::audioToUIQueue_t &audioToUI; Synth::uiToAudioQueue_T &uiToAudio; std::function flushOperator;