Loading...
Searching...
No Matches
PatternModel.hpp
1#pragma once
2#include <Process/Process.hpp>
3
4#include <Patternist/PatternMetadata.hpp>
5
6#include <score_plugin_midi_export.h>
7
8#include <verdigris>
9
10namespace Process
11{
12class ControlInlet;
13class ValueOutlet;
14}
15namespace Patternist
16{
17
18enum class Note : uint8_t
19{
20 Rest,
21 Note,
22 Legato
23};
24}
25
26Q_DECLARE_METATYPE(Patternist::Note)
27W_REGISTER_ARGTYPE(Patternist::Note)
28
29namespace Patternist
30{
31
33enum class Condition : uint8_t
34{
35 Always,
37 Fill,
38 NotFill,
40 First,
41 NotFirst,
43 Cycle
44};
45
49{
51 float velocity{1.f};
54 float velocityRandom{0.f};
56 float chance{1.f};
58 float offset{0.f};
61 float offsetRandom{0.f};
63 float gate{1.f};
66 float gateRandom{0.f};
68 uint8_t ratchet{1};
71 float pace{0.f};
73 int8_t pitch{0};
76 uint8_t pitchRandom{0};
77 Condition condition{Condition::Always};
78 uint8_t cycleA{1};
79 uint8_t cycleB{2};
80
81 bool operator==(const StepParams&) const noexcept = default;
82 bool isDefault() const noexcept { return *this == StepParams{}; }
83};
84
87inline bool euclidHit(int i, int steps, int pulses, int rotation) noexcept
88{
89 if(steps <= 0 || pulses <= 0)
90 return false;
91 if(pulses >= steps)
92 return true;
93 const int j = (((i - rotation) % steps) + steps) % steps;
94 return (j * pulses) % steps < pulses;
95}
96
97struct Lane
98{
99 std::vector<Patternist::Note> pattern;
101 uint8_t note{};
102 bool mute{};
103 bool solo{};
105 int length{};
107 int division{};
109 float velocity{100.f / 127.f};
111 std::vector<StepParams> params;
114 enum RandomPerHit : uint8_t
115 {
116 VelocityPerHit = 1,
117 PitchPerHit = 2,
118 TimingPerHit = 4,
119 GatePerHit = 8
120 };
121 uint8_t randomPerHit{};
122
123 bool operator==(const Lane& other) const noexcept = default;
124};
125
131inline constexpr uint8_t accentLane = 255;
132inline constexpr uint8_t slideLane = 254;
133inline bool isControlLane(const Lane& l) noexcept
134{
135 return l.note == accentLane || l.note == slideLane;
136}
137
139{
140 static const constexpr int maxLength = 128;
141 static const constexpr int maxLanes = 128;
143 static const constexpr int maxDivision = 64;
144
145 int length{16};
146 int division{16};
147 std::vector<Lane> lanes;
148
149 bool operator==(const Pattern& other) const noexcept
150 {
151 return length == other.length && division == other.division && lanes == other.lanes;
152 }
153};
154
158SCORE_PLUGIN_MIDI_TEST_EXPORT void normalize(Pattern& p) noexcept;
159
160inline bool anySolo(const Pattern& p) noexcept
161{
162 for(const Lane& l : p.lanes)
163 if(l.solo)
164 return true;
165 return false;
166}
167
168inline int laneLength(const Pattern& p, const Lane& l) noexcept
169{
170 return l.length > 0 ? l.length : p.length;
171}
172
173inline int laneDivision(const Pattern& p, const Lane& l) noexcept
174{
175 return l.division > 0 ? l.division : p.division;
176}
177
179inline Note writtenNote(const Pattern& p, const Lane& l, int step) noexcept
180{
181 return (step >= 0 && step < int(l.pattern.size())) ? l.pattern[step] : Note::Rest;
182}
183
184inline const StepParams& stepParams(const Lane& l, int step) noexcept
185{
186 static const StepParams defaults;
187 return (step >= 0 && step < int(l.params.size())) ? l.params[step] : defaults;
188}
189
193inline bool tieStrikes(const Pattern& p, const Lane& l, int step) noexcept
194{
195 const int len = laneLength(p, l);
196 if(len <= 0)
197 return true;
198 const int prev = ((step - 1) % len + len) % len;
199 if(writtenNote(p, l, prev) == Note::Rest)
200 return true;
201 const StepParams& sp = stepParams(l, step);
202 const StepParams& pp = stepParams(l, prev);
203 const bool spread
204 = !(l.randomPerHit & Lane::PitchPerHit) && (sp.pitchRandom > 0 || pp.pitchRandom > 0);
205 return sp.ratchet > 1 || sp.pitch != pp.pitch || spread;
206}
207
210inline int struckStep(const Pattern& p, const Lane& l, int step) noexcept
211{
212 const int len = laneLength(p, l);
213 for(int k = 0; k < len; k++)
214 {
215 if(writtenNote(p, l, step) != Note::Legato || tieStrikes(p, l, step))
216 return step;
217 step = ((step - 1) % len + len) % len;
218 }
219 return step;
220}
221
223inline Note audibleNote(const Pattern& p, const Lane& l, int step, bool anySolo) noexcept
224{
225 if(l.mute || (anySolo && !l.solo))
226 return Note::Rest;
227 return writtenNote(p, l, step);
228}
229
231enum class LaneLabels : uint8_t
232{
233 NameAndNumber,
234 Name,
235 Number,
236 DrumName
237};
238}
239
240Q_DECLARE_METATYPE(Patternist::LaneLabels)
241W_REGISTER_ARGTYPE(Patternist::LaneLabels)
242
243namespace Patternist
244{
245
246class SCORE_PLUGIN_MIDI_EXPORT ProcessModel final : public Process::ProcessModel
247{
248 SCORE_SERIALIZE_FRIENDS
249 W_OBJECT(ProcessModel)
250
251public:
253 static const constexpr int maxPatterns = 128;
254
255 PROCESS_METADATA_IMPL(Patternist::ProcessModel)
256 explicit ProcessModel(
257 const TimeVal& duration, const Id<Process::ProcessModel>& id, QObject* parent);
258 explicit ProcessModel(
259 const TimeVal& duration, const QString& custom,
260 const Id<Process::ProcessModel>& id, QObject* parent);
261
262 template <typename Impl>
263 explicit ProcessModel(Impl& vis, QObject* parent)
264 : Process::ProcessModel{vis, parent}
265 {
266 vis.writeTo(*this);
267 init();
268 }
269
270 void init();
272 void sanitize();
273
274 ~ProcessModel() override;
275
276 void setChannel(int n);
277 int channel() const noexcept;
278
279 void setCurrentPattern(int n);
280 int currentPattern() const noexcept;
281
282 void setLaneLabels(LaneLabels l);
283 LaneLabels laneLabels() const noexcept;
284
287 const std::vector<int64_t>& execSteps() const noexcept { return m_execSteps; }
288 void setExecSteps(std::vector<int64_t> s) { m_execSteps = std::move(s); }
289
290 void setPattern(int n, Pattern p);
291 void setPatterns(const std::vector<Pattern>& n);
292 const std::vector<Pattern>& patterns() const noexcept;
293
297 void loadPreset(const Process::Preset& preset) override;
298 Process::Preset savePreset() const noexcept override;
299
300 std::unique_ptr<Process::ControlInlet> patternSelect;
301 std::unique_ptr<Process::ControlInlet> switchQuantification;
303 std::unique_ptr<Process::ControlInlet> fill;
305 std::unique_ptr<Process::ControlInlet> density;
307 std::unique_ptr<Process::ControlInlet> velocity;
309 std::unique_ptr<Process::ControlInlet> swing;
311 std::unique_ptr<Process::ControlInlet> ratchet;
313 std::unique_ptr<Process::ControlInlet> pace;
315 std::unique_ptr<Process::ControlInlet> repeatTime;
316 std::unique_ptr<Process::MidiOutlet> outlet;
317 std::unique_ptr<Process::Outlet> accent;
318 std::unique_ptr<Process::Outlet> slide;
319
320public:
321 void channelChanged(int arg_1) W_SIGNAL(channelChanged, arg_1);
322 void currentPatternChanged(int arg_1) W_SIGNAL(currentPatternChanged, arg_1);
324 void execStepsChanged() W_SIGNAL(execStepsChanged);
327 void execPattern(int current, int pending) W_SIGNAL(execPattern, current, pending);
328 void patternsChanged() W_SIGNAL(patternsChanged);
329 void laneLabelsChanged(LaneLabels arg_1) W_SIGNAL(laneLabelsChanged, arg_1);
331 void timeGridChanged() W_SIGNAL(timeGridChanged);
332
333 PROPERTY(int, channel READ channel WRITE setChannel NOTIFY channelChanged, W_Final)
334 PROPERTY(
335 int,
336 currentPattern READ currentPattern WRITE setCurrentPattern NOTIFY
337 currentPatternChanged,
338 W_Final)
339 PROPERTY(
340 LaneLabels,
341 laneLabels READ laneLabels WRITE setLaneLabels NOTIFY laneLabelsChanged, W_Final)
342private:
343 void ancestorStartDateChanged() override;
344 void ancestorTempoChanged() override;
345 void setDurationAndScale(const TimeVal& newDuration) noexcept override;
346 void setDurationAndGrow(const TimeVal& newDuration) noexcept override;
347 void setDurationAndShrink(const TimeVal& newDuration) noexcept override;
348
349 int m_channel{1};
350 int m_currentPattern{};
351 LaneLabels m_laneLabels{LaneLabels::NameAndNumber};
352 std::vector<int64_t> m_execSteps;
354 std::vector<bool> m_grown;
355 std::vector<Pattern> m_patterns;
356};
357}
Definition PatternModel.hpp:247
The Process class.
Definition score-lib-process/Process/Process.hpp:82
The id_base_t class.
Definition Identifier.hpp:59
Base classes and tools to implement processes and layers.
Definition JSONVisitor.hpp:1115
STL namespace.
Definition PatternModel.hpp:98
std::vector< StepParams > params
Same size as pattern.
Definition PatternModel.hpp:111
uint8_t note
A MIDI note, or accentLane or slideLane.
Definition PatternModel.hpp:101
RandomPerHit
Definition PatternModel.hpp:115
int division
Steps per whole note; 0 follows the pattern.
Definition PatternModel.hpp:107
int length
Steps before the lane loops; 0 follows the pattern.
Definition PatternModel.hpp:105
float velocity
0 - 1.
Definition PatternModel.hpp:109
Definition PatternModel.hpp:139
static const constexpr int maxDivision
Steps per whole note, at most.
Definition PatternModel.hpp:143
Definition PatternModel.hpp:49
float chance
0 - 1, scaled by the Density input.
Definition PatternModel.hpp:56
uint8_t ratchet
Notes played within the step, 1 - 8.
Definition PatternModel.hpp:68
float gate
0 - 1 of a step; a tie, or 1, holds the note until the next step.
Definition PatternModel.hpp:63
float pace
Definition PatternModel.hpp:71
int8_t pitch
Semitones added to the lane's note.
Definition PatternModel.hpp:73
float gateRandom
Definition PatternModel.hpp:66
uint8_t pitchRandom
Definition PatternModel.hpp:76
float velocity
0 - 1, scaled by the lane's velocity and the Velocity input.
Definition PatternModel.hpp:51
float velocityRandom
Definition PatternModel.hpp:54
float offsetRandom
Definition PatternModel.hpp:61
float offset
-0.5 - 0.5 of a step: early or late.
Definition PatternModel.hpp:58
Definition TimeValue.hpp:21