From b12d4864572ced80e0f1ad1bd3bbc36829c14832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Thu, 26 Dec 2024 20:39:20 -0500 Subject: [PATCH] patternist: add support for accent and slide out --- .../graphics/widgets/QGraphicsNoteChooser.cpp | 24 +++++++++++-- .../graphics/widgets/QGraphicsNoteChooser.hpp | 4 +-- .../Curve/Commands/MovePoint.cpp | 1 - .../Patternist/PatternExecutor.cpp | 25 ++++++++++++- .../Patternist/PatternModel.cpp | 35 ++++++++++++++++--- .../Patternist/PatternModel.hpp | 6 ++++ .../Patternist/PatternParsing.cpp | 11 ++++++ 7 files changed, 96 insertions(+), 10 deletions(-) diff --git a/src/lib/score/graphics/widgets/QGraphicsNoteChooser.cpp b/src/lib/score/graphics/widgets/QGraphicsNoteChooser.cpp index 5b55fcfa15..e31dcb0cc9 100644 --- a/src/lib/score/graphics/widgets/QGraphicsNoteChooser.cpp +++ b/src/lib/score/graphics/widgets/QGraphicsNoteChooser.cpp @@ -26,7 +26,19 @@ QGraphicsNoteChooser::QGraphicsNoteChooser(QGraphicsItem* parent) void QGraphicsNoteChooser::setValue(int v) { - m_value = ossia::clamp(v, m_min, m_max); + switch(v) + { + case 255: + m_value = -1; + break; + case 254: + m_value = -2; + break; + default: + m_value = ossia::clamp(v, m_min, m_max); + break; + } + update(); } @@ -91,7 +103,15 @@ static QString noteText(int n) { static constexpr QStringView lit[12]{u"C", u"C#", u"D", u"D#", u"E", u"F", u"F#", u"G", u"G#", u"A", u"A#", u"B"}; - return QString{"%1%2"}.arg(lit[n % 12]).arg(n / 12 - 1); + switch(n) + { + case -1: + return "AC"; + case -2: + return "SL"; + default: + return QString{"%1%2"}.arg(lit[n % 12]).arg(n / 12 - 1); + } } void QGraphicsNoteChooser::paint( diff --git a/src/lib/score/graphics/widgets/QGraphicsNoteChooser.hpp b/src/lib/score/graphics/widgets/QGraphicsNoteChooser.hpp index d85d27f84e..07918343fa 100644 --- a/src/lib/score/graphics/widgets/QGraphicsNoteChooser.hpp +++ b/src/lib/score/graphics/widgets/QGraphicsNoteChooser.hpp @@ -18,7 +18,7 @@ class SCORE_LIB_BASE_EXPORT QGraphicsNoteChooser final W_OBJECT(QGraphicsNoteChooser) SCORE_GRAPHICS_ITEM_TYPE(120) - static constexpr int m_min = 0; + static constexpr int m_min = -2; static constexpr int m_max = 127; static constexpr double m_width = 30; static constexpr double m_height = 28; @@ -28,7 +28,7 @@ class SCORE_LIB_BASE_EXPORT QGraphicsNoteChooser final bool m_grab{}; public: - QGraphicsNoteChooser(QGraphicsItem* parent); + explicit QGraphicsNoteChooser(QGraphicsItem* parent); void setValue(int v); int value() const; diff --git a/src/plugins/score-plugin-curve/Curve/Commands/MovePoint.cpp b/src/plugins/score-plugin-curve/Curve/Commands/MovePoint.cpp index 5d6197b471..9f73b69263 100644 --- a/src/plugins/score-plugin-curve/Curve/Commands/MovePoint.cpp +++ b/src/plugins/score-plugin-curve/Curve/Commands/MovePoint.cpp @@ -32,7 +32,6 @@ MovePoint::MovePoint( // another if(std::abs(m_oldPoint.x() - m_newPoint.x()) < 0.0001) { - qDebug() << m_oldPoint.x() - m_newPoint.x(); m_newPoint.rx() = m_oldPoint.x(); } diff --git a/src/plugins/score-plugin-midi/Patternist/PatternExecutor.cpp b/src/plugins/score-plugin-midi/Patternist/PatternExecutor.cpp index 14474ed0ce..7c9a763a95 100644 --- a/src/plugins/score-plugin-midi/Patternist/PatternExecutor.cpp +++ b/src/plugins/score-plugin-midi/Patternist/PatternExecutor.cpp @@ -17,6 +17,8 @@ class pattern_node : public ossia::nonowning_graph_node { public: ossia::midi_outlet out; + ossia::value_outlet accent_out; + ossia::value_outlet slide_out; Pattern pattern; ossia::flat_set in_flight; @@ -28,6 +30,8 @@ class pattern_node : public ossia::nonowning_graph_node { in_flight.reserve(32); m_outlets.push_back(&out); + m_outlets.push_back(&accent_out); + m_outlets.push_back(&slide_out); } std::string label() const noexcept override { return "pattern_node"; } @@ -65,13 +69,32 @@ class pattern_node : public ossia::nonowning_graph_node for(Lane& lane : pattern.lanes) { - if(lane.pattern[current]) + if(lane.note <= 127 && lane.pattern[current]) { mess.push_back(libremidi::channel_events::note_on(channel, lane.note, 64)); mess.back().timestamp = date; in_flight.insert(lane.note); } } + + for(Lane& lane : pattern.lanes) + { + if(lane.note == 255) + { + if(lane.pattern[current]) + accent_out->write_value(1., date); + else + accent_out->write_value(0., date); + } + else if(lane.note == 254) + { + if(lane.pattern[current]) + slide_out->write_value(1., date); + else + slide_out->write_value(0., date); + } + } + current = (current + 1) % pattern.length; } } diff --git a/src/plugins/score-plugin-midi/Patternist/PatternModel.cpp b/src/plugins/score-plugin-midi/Patternist/PatternModel.cpp index fc17511f32..f027b222bc 100644 --- a/src/plugins/score-plugin-midi/Patternist/PatternModel.cpp +++ b/src/plugins/score-plugin-midi/Patternist/PatternModel.cpp @@ -20,8 +20,10 @@ namespace Patternist ProcessModel::ProcessModel( const TimeVal& duration, const Id& id, QObject* parent) : Process:: - ProcessModel{duration, id, Metadata::get(), parent} + ProcessModel{duration, id, Metadata::get(), parent} , outlet{Process::make_midi_outlet(Id(0), this)} + , accent{Process::make_value_outlet(Id(1), this)} + , slide{Process::make_value_outlet(Id(2), this)} { Pattern pattern; pattern.length = 4; @@ -37,7 +39,6 @@ ProcessModel::ProcessModel( const Id& id, QObject* parent) : Patternist::ProcessModel{duration, id, parent} { - if(QFile f{customData}; f.open(QIODevice::ReadOnly)) if(auto data = score::mapAsByteArray(f); !data.isEmpty()) if(auto pat = parsePattern(data); pat.lanes.size() > 0) @@ -47,6 +48,8 @@ ProcessModel::ProcessModel( void ProcessModel::init() { m_outlets.push_back(outlet.get()); + m_outlets.push_back(accent.get()); + m_outlets.push_back(slide.get()); } ProcessModel::~ProcessModel() { } @@ -196,7 +199,8 @@ void JSONWriter::write(Patternist::Pattern& proc) template <> void DataStreamReader::read(const Patternist::ProcessModel& proc) { - m_stream << *proc.outlet << proc.m_channel << proc.m_currentPattern << proc.m_patterns; + m_stream << *proc.outlet << *proc.accent << *proc.slide << proc.m_channel + << proc.m_currentPattern << proc.m_patterns; insertDelimiter(); } @@ -205,7 +209,8 @@ template <> void DataStreamWriter::write(Patternist::ProcessModel& proc) { proc.outlet = Process::load_midi_outlet(*this, &proc); - m_stream >> proc.m_channel >> proc.m_currentPattern >> proc.m_patterns; + m_stream >> proc.m_channel >> *proc.accent >> *proc.slide >> proc.m_currentPattern + >> proc.m_patterns; checkDelimiter(); } @@ -214,6 +219,8 @@ template <> void JSONReader::read(const Patternist::ProcessModel& proc) { obj["Outlet"] = *proc.outlet; + obj["Accent"] = *proc.accent; + obj["Slide"] = *proc.slide; obj["Channel"] = proc.m_channel; obj["Pattern"] = proc.m_currentPattern; obj["Patterns"] = proc.m_patterns; @@ -226,6 +233,26 @@ void JSONWriter::write(Patternist::ProcessModel& proc) JSONWriter writer{obj["Outlet"]}; proc.outlet = Process::load_midi_outlet(writer, &proc); } + + if(auto port = obj.tryGet("Accent")) + { + JSONWriter writer{*port}; + proc.accent = Process::load_value_outlet(writer, &proc); + } + else + { + proc.accent = Process::make_value_outlet(Id(1), &proc); + } + + if(auto port = obj.tryGet("Slide")) + { + JSONWriter writer{*port}; + proc.slide = Process::load_value_outlet(writer, &proc); + } + else + { + proc.slide = Process::make_value_outlet(Id(2), &proc); + } proc.m_channel = obj["Channel"].toInt(); proc.m_currentPattern = obj["Pattern"].toInt(); proc.m_patterns <<= obj["Patterns"]; diff --git a/src/plugins/score-plugin-midi/Patternist/PatternModel.hpp b/src/plugins/score-plugin-midi/Patternist/PatternModel.hpp index c7044544dd..b71f73f17b 100644 --- a/src/plugins/score-plugin-midi/Patternist/PatternModel.hpp +++ b/src/plugins/score-plugin-midi/Patternist/PatternModel.hpp @@ -7,6 +7,10 @@ #include +namespace Process +{ +class ValueOutlet; +} namespace Patternist { struct Lane @@ -68,6 +72,8 @@ class SCORE_PLUGIN_MIDI_EXPORT ProcessModel final : public Process::ProcessModel const std::vector& patterns() const noexcept; std::unique_ptr outlet; + std::unique_ptr accent; + std::unique_ptr slide; public: void channelChanged(int arg_1) W_SIGNAL(channelChanged, arg_1); diff --git a/src/plugins/score-plugin-midi/Patternist/PatternParsing.cpp b/src/plugins/score-plugin-midi/Patternist/PatternParsing.cpp index da7d59df78..311f8ae009 100644 --- a/src/plugins/score-plugin-midi/Patternist/PatternParsing.cpp +++ b/src/plugins/score-plugin-midi/Patternist/PatternParsing.cpp @@ -31,6 +31,17 @@ Pattern parsePattern(const QByteArray& data) noexcept Lane lane; bool ok = false; lane.note = split[0].toInt(&ok); + if(!ok && split[0] == "AC") + { + lane.note = 255; + ok = true; + } + if(!ok && split[0] == "SL") + { + lane.note = 254; + ok = true; + } + if(ok) { p.length = split[1].size();