From 84574403beb35825da33fc0140613da19ef64fab Mon Sep 17 00:00:00 2001 From: Paul Walker Date: Fri, 4 Oct 2024 16:48:48 -0400 Subject: [PATCH 1/2] Group Trigger stuff streams (but still does nothing) Group trigger streaming in place. Its still all nulls all the time, isn't queried, doesn't evaluate, etc... mostly because I ddin't code much today but lets commit this for the weekend Streaming also meant a split from operator and storage, just like LFO etc... and so this puts the Storage idiom in place --- src/engine/group.cpp | 2 + src/engine/group_triggers.cpp | 121 ++++++++++++++++++++++++++++++++++ src/engine/group_triggers.h | 70 ++++++++++++++++---- src/json/engine_traits.h | 40 ++++++++++- src/utils.h | 2 +- 5 files changed, 222 insertions(+), 13 deletions(-) diff --git a/src/engine/group.cpp b/src/engine/group.cpp index 430b5d40..a76a76bb 100644 --- a/src/engine/group.cpp +++ b/src/engine/group.cpp @@ -464,6 +464,8 @@ void Group::setupOnUnstream(const engine::Engine &e) { lfo.UpdatePhaseIncrement(); } + + triggerConditions.setupOnUnstream(parentPart->groupTriggerInstrumentState); } void Group::onSampleRateChanged() { diff --git a/src/engine/group_triggers.cpp b/src/engine/group_triggers.cpp index 26217df9..b3f610c1 100644 --- a/src/engine/group_triggers.cpp +++ b/src/engine/group_triggers.cpp @@ -26,3 +26,124 @@ */ #include "group_triggers.h" +#include "utils.h" + +namespace scxt::engine +{ + +std::string toStringGroupTriggerID(const GroupTriggerID &p) +{ + switch (p) + { + // lesson learned earlier was long names are not that handy debugging now the infra works + // and just make big files so use compact ones here + case GroupTriggerID::NONE: + return "n"; + case GroupTriggerID::MACRO: + return "mcr"; + case GroupTriggerID::MIDICC: + return "mcc"; + } +} +GroupTriggerID fromStringGroupTriggerID(const std::string &s) +{ + static auto inverse = makeEnumInverse( + GroupTriggerID::NONE, GroupTriggerID::MIDICC); + auto p = inverse.find(s); + if (p == inverse.end()) + return GroupTriggerID::NONE; + return p->second; +} + +std::string GroupTriggerConditions::toStringGroupConditionsConjunction(const Conjunction &p) +{ + switch (p) + { + case Conjunction::AND: + return "a"; + case Conjunction::OR: + return "o"; + case Conjunction::AND_NOT: + return "a!"; + case Conjunction::OR_NOT: + return "o!"; + } + return ""; +} +GroupTriggerConditions::Conjunction fromStringConditionsConjunction(const std::string &s) +{ + static auto inverse = + makeEnumInverse( + GroupTriggerConditions::Conjunction::AND, GroupTriggerConditions::Conjunction::OR_NOT); + auto p = inverse.find(s); + if (p == inverse.end()) + return GroupTriggerConditions::Conjunction::AND; + return p->second; +} + +struct GTMacro : GroupTrigger +{ + + GTMacro(GroupTriggerInstrumentState &onState, GroupTriggerStorage &onStorage) + : GroupTrigger(onState, onStorage) + { + } + + bool value(const std::unique_ptr &, const std::unique_ptr &) const override + { + return true; + } + datamodel::pmd argMetadata(int argNo) const override { return {}; } +}; +struct GTMIDI1CC : GroupTrigger +{ + GTMIDI1CC(GroupTriggerInstrumentState &onState, GroupTriggerStorage &onStorage) + : GroupTrigger(onState, onStorage) + { + } + + bool value(const std::unique_ptr &, const std::unique_ptr &) const override + { + return true; + } + datamodel::pmd argMetadata(int argNo) const override { return {}; } +}; + +GroupTrigger *makeGroupTrigger(GroupTriggerID id, GroupTriggerInstrumentState &gis, + GroupTriggerStorage &st, GroupTriggerBuffer &bf) +{ +#define CS(id, tp) \ + static_assert(sizeof(tp) < sizeof(GroupTriggerBuffer)); \ + case id: \ + return new (bf) tp(gis, st); + switch (id) + { + CS(GroupTriggerID::MIDICC, GTMIDI1CC); + CS(GroupTriggerID::MACRO, GTMacro); + case GroupTriggerID::NONE: + return nullptr; + } + return nullptr; +} + +// THIS NEEDS ARGUMENTS of the state and so on +void GroupTriggerConditions::setupOnUnstream(GroupTriggerInstrumentState &gis) +{ + for (int i = 0; i < triggerConditionsPerGroup; ++i) + { + auto &s = storage[i]; + if (s.id == GroupTriggerID::NONE) + { + if (conditions[i]) + conditions[i]->~GroupTrigger(); + conditions[i] = nullptr; + } + else + { + conditions[i] = makeGroupTrigger(s.id, gis, s, conditionBuffers[i]); + } + } +} + +} // namespace scxt::engine \ No newline at end of file diff --git a/src/engine/group_triggers.h b/src/engine/group_triggers.h index 8d023b1c..937405d1 100644 --- a/src/engine/group_triggers.h +++ b/src/engine/group_triggers.h @@ -30,13 +30,18 @@ #include #include +#include + #include "configuration.h" +#include "utils.h" #include "datamodel/metadata.h" namespace scxt::engine { +struct Engine; +struct Part; struct Group; /** @@ -46,33 +51,76 @@ struct GroupTriggerInstrumentState { }; +enum struct GroupTriggerID : int32_t +{ + NONE, + + MACRO, + MIDICC // if MIDICC is no longer last, adjust fromStringGfroupTRiggerID iteration +}; + +std::string toStringGroupTriggerID(const GroupTriggerID &p); +GroupTriggerID fromStringGroupTriggerID(const std::string &p); + +struct GroupTriggerStorage +{ + GroupTriggerID id{GroupTriggerID::NONE}; + using argInterface_t = int32_t; // for now and just use ms for miliseconds and scale + + static constexpr int32_t numArgs{2}; + std::array args{0, 0}; +}; /** * Calculate if a group is triggered */ struct GroupTrigger { GroupTriggerInstrumentState &state; - GroupTrigger(GroupTriggerInstrumentState &onState) : state(onState) {} + GroupTriggerStorage &storage; + GroupTrigger(GroupTriggerInstrumentState &onState, GroupTriggerStorage &onStorage) + : state(onState), storage(onStorage) + { + } virtual ~GroupTrigger() = default; - virtual bool value(const std::unique_ptr &) const = 0; - - datamodel::pmd argMetadata(int argNo) const; - std::string displayName; + virtual bool value(const std::unique_ptr &, const std::unique_ptr &) const = 0; + virtual datamodel::pmd argMetadata(int argNo) const = 0; }; -std::unique_ptr makeMacroGroupTrigger(GroupTriggerInstrumentState &); -std::unique_ptr makeMIDI1CCGroupTrigger(GroupTriggerInstrumentState &); +// FIXME - make this sized more intelligently +using GroupTriggerBuffer = uint8_t[2048]; + +GroupTrigger *makeGroupTrigger(GroupTriggerID, GroupTriggerInstrumentState &, GroupTriggerStorage &, + GroupTriggerBuffer &); +std::string getGroupTriggerDisplayName(GroupTriggerID); struct GroupTriggerConditions { - std::array, scxt::triggerConditionsPerGroup> conditions; - std::array active; - enum Conjunction + GroupTriggerConditions() + { + std::fill(conditions.begin(), conditions.end(), nullptr); + std::fill(active.begin(), active.end(), false); + } + std::array storage{}; + std::array active{}; + + enum struct Conjunction : int32_t { AND, - OR + OR, + AND_NOT, + OR_NOT // add one to end or change position update the from in fromString }; + + static std::string toStringGroupConditionsConjunction(const Conjunction &p); + static Conjunction fromStringConditionsConjunction(const std::string &p); + std::array conjunctions; + + void setupOnUnstream(GroupTriggerInstrumentState &); + + protected: + std::array conditionBuffers; + std::array conditions{}; }; } // namespace scxt::engine diff --git a/src/json/engine_traits.h b/src/json/engine_traits.h index cf6a3771..125c6495 100644 --- a/src/json/engine_traits.h +++ b/src/json/engine_traits.h @@ -42,6 +42,7 @@ #include "engine/keyboard.h" #include "engine/macros.h" #include "engine/engine.h" +#include "engine/group_triggers.h" #include "scxt_traits.h" @@ -226,6 +227,42 @@ SC_STREAMDEF( } })) +STREAM_ENUM(engine::GroupTriggerID, engine::toStringGroupTriggerID, + engine::fromStringGroupTriggerID); + +SC_STREAMDEF(scxt::engine::GroupTriggerStorage, SC_FROM({ + v = {{"id", from.id}, {"args", from.args}}; + }), + SC_TO({ + findIf(v, "id", to.id); + findIf(v, "args", to.args); + })); + +STREAM_ENUM(engine::GroupTriggerConditions::Conjunction, + engine::GroupTriggerConditions::toStringGroupConditionsConjunction, + engine::GroupTriggerConditions::fromStringConditionsConjunction); + +SC_STREAMDEF(scxt::engine::GroupTriggerConditions, SC_FROM({ + bool anyConfigured{false}; + for (const auto &c : from.storage) + { + anyConfigured |= (c.id != scxt::engine::GroupTriggerID::NONE); + } + if (anyConfigured) + { + v = {{"st", from.storage}, {"ac", from.active}, {"conj", from.conjunctions}}; + } + else + { + v = tao::json::empty_object; + } + }), + SC_TO({ + findIf(v, "st", to.storage); + findIf(v, "ac", to.active); + findIf(v, "conj", to.conjunctions); + })); + SC_STREAMDEF(scxt::engine::Group::GroupOutputInfo, SC_FROM({ v = {{"amplitude", t.amplitude}, {"pan", t.pan}, {"oversample", t.oversample}, {"velocitySensitivity", t.velocitySensitivity}, @@ -251,7 +288,8 @@ SC_STREAMDEF(scxt::engine::Group, SC_FROM({ {"routingTable", t.routingTable}, {"gegStorage", t.gegStorage}, {"modulatorStorage", t.modulatorStorage}, - {"processorStorage", t.processorStorage}}; + {"processorStorage", t.processorStorage}, + {"triggerConditions", t.triggerConditions}}; }), SC_TO({ auto &group = to; diff --git a/src/utils.h b/src/utils.h index 62e34eaf..6e59b9b1 100644 --- a/src/utils.h +++ b/src/utils.h @@ -314,7 +314,7 @@ template inline std::unordered_map makeEnumInverse(const E &from, const E &to) { std::unordered_map res; - for (auto i = (int32_t)from; i <= to; ++i) + for (auto i = (int32_t)from; i <= (int32_t)to; ++i) { res[F((E)i)] = (E)i; } From 0161837209092174aaafae05a7252cf29c704add Mon Sep 17 00:00:00 2001 From: Paul Walker Date: Sat, 5 Oct 2024 11:14:36 -0400 Subject: [PATCH 2/2] fx --- src/engine/group_triggers.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/group_triggers.cpp b/src/engine/group_triggers.cpp index b3f610c1..cc9a81a8 100644 --- a/src/engine/group_triggers.cpp +++ b/src/engine/group_triggers.cpp @@ -44,6 +44,7 @@ std::string toStringGroupTriggerID(const GroupTriggerID &p) case GroupTriggerID::MIDICC: return "mcc"; } + return "n"; } GroupTriggerID fromStringGroupTriggerID(const std::string &s) { @@ -68,7 +69,7 @@ std::string GroupTriggerConditions::toStringGroupConditionsConjunction(const Con case Conjunction::OR_NOT: return "o!"; } - return ""; + return "a"; } GroupTriggerConditions::Conjunction fromStringConditionsConjunction(const std::string &s) {