Ardour  9.0-pre0-582-g084a23a80d
step_sequencer.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2018 Paul Davis <paul@linuxaudiosystems.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #pragma once
20 
21 #include <vector>
22 #include <unistd.h>
23 
24 #include <boost/intrusive/list.hpp>
25 #include <boost/rational.hpp>
26 
27 #include <glibmm/threads.h>
28 
29 #include "pbd/pool.h"
30 #include "pbd/ringbuffer.h"
31 #include "pbd/stateful.h"
32 
33 #include "evoral/Event.h"
34 
35 #include "temporal/types.h"
36 #include "temporal/beats.h"
37 
38 #include "ardour/mode.h"
40 #include "ardour/types.h"
41 
42 #include "midi++/types.h"
43 
44 namespace ARDOUR {
45 
46 class MidiBuffer;
47 class MidiNoteTracker;
48 class StepSequencer;
49 class StepSequence;
50 class TempoMap;
51 class SMFSource;
52 
53 typedef std::pair<Temporal::Beats,samplepos_t> BeatPosition;
54 typedef std::vector<BeatPosition> BeatPositions;
55 
57 typedef std::vector<MusicTimeEvent*> MusicTimeEvents;
58 
59 class Step : public PBD::Stateful {
60  public:
61  enum Mode {
64  };
65 
66  typedef boost::rational<int> DurationRatio;
67 
68  Step (StepSequence&, size_t n, Temporal::Beats const & beat, int notenum);
69  ~Step ();
70 
71  size_t index() const { return _index; }
72 
73  void set_note (double note, double velocity = 0.5, int n = 0);
74  void set_chord (size_t note_cnt, double* notes);
75  void set_parameter (int number, double value, int n = 0);
76 
77  void adjust_velocity (int amt);
78  void adjust_pitch (int amt);
79  void adjust_duration (DurationRatio const & amt);
80  void adjust_octave (int amt);
81  void adjust_offset (double fraction);
82 
83  Mode mode() const { return _mode; }
84  void set_mode (Mode m);
85 
86  double note (size_t n = 0) const { return _notes[n].number; }
87  double velocity (size_t n = 0) const { return _notes[n].velocity; }
88  void set_velocity (double, size_t n = 0);
89 
90  DurationRatio duration () const { return _duration; }
91  void set_duration (DurationRatio const &);
92 
93  void set_offset (Temporal::Beats const &, size_t n = 0);
94  Temporal::Beats offset (size_t n = 0) const { return _notes[n].offset; }
95 
96  int parameter (size_t n = 0) const { return _parameters[n].parameter; }
97  int parameter_value (size_t n = 0) const { return _parameters[n].value; }
98 
99  void set_enabled (bool);
100  bool enabled() const { return _enabled; }
101 
102  void set_repeat (size_t r);
103  size_t repeat() const { return _repeat; }
104 
105  void set_beat (Temporal::Beats const & beat);
106  Temporal::Beats beat () const { return _nominal_beat; }
107 
109 
110  bool skipped() const { return _skipped; }
111  void set_skipped (bool);
112 
113  void reschedule (Temporal::Beats const &, Temporal::Beats const &);
114 
115  int octave_shift() const { return _octave_shift; }
116  void set_octave_shift (int);
117 
118  XMLNode& get_state() const;
119  int set_state (XMLNode const &, int);
120 
121  void dump (MusicTimeEvents&, Temporal::Beats const&) const;
122 
123  static const int _notes_per_step = 5;
124  static const int _parameters_per_step = 5;
125 
126  private:
127  friend class StepSequence; /* HACK */
128 
130  size_t _index;
131  bool _enabled;
134  bool _skipped;
138 
139  struct ParameterValue {
141  double value;
142  };
143 
144  struct Note {
145  union {
146  double number; /* typically MIDI note number */
147  double interval; /* semitones */
148  };
149  double velocity;
152 
153  Note () : number (-1), velocity (0.0) {}
154  Note (double n, double v,Temporal::Beats const & o) : number (n), velocity (v), offset (o) {}
155  };
156 
159  size_t _repeat;
160 
162  void check_parameter (size_t n, MidiBuffer& buf, bool, samplepos_t, samplepos_t);
163  void dump_note (MusicTimeEvents&, size_t n, Temporal::Beats const &) const;
164  void dump_parameter (MusicTimeEvents&, size_t n, Temporal::Beats const &) const;
165 
167 };
168 
170 {
171  public:
172  enum Direction {
173  forwards = 0,
176  rd_random = 3
177  };
178 
179  StepSequence (StepSequencer &myseq, size_t index, size_t nsteps, Temporal::Beats const & step_size, Temporal::Beats const & bar_size, int notenum);
181 
182  size_t index() const { return _index; }
183  size_t nsteps() const { return _steps.size(); }
184 
185  Step& step (size_t n) const;
186 
187  void startup (Temporal::Beats const & start, Temporal::Beats const & offset);
188 
189  int root() const { return _root; }
190  void set_root (int n);
191 
192  int channel() const { return _channel; }
193  void set_channel (int);
194 
196 
197  MusicalMode mode() const { return _mode; }
199 
200  void shift_left (size_t n = 1);
201  void shift_right (size_t n = 1);
202 
203  void reset ();
204  void reschedule (Temporal::Beats const &, Temporal::Beats const &);
205  void schedule (Temporal::Beats const &);
206 
208 
209  StepSequencer& sequencer() const { return _sequencer; }
210 
211  XMLNode& get_state() const;
212  int set_state (XMLNode const &, int);
213 
214  void dump (MusicTimeEvents&, Temporal::Beats const &) const;
215 
216  private:
218  int _index;
219  mutable Glib::Threads::Mutex _step_lock;
220  typedef std::vector<Step*> Steps;
221 
223  int _channel; /* MIDI channel */
224  int _root;
226 };
227 
229 {
230  public:
231  StepSequencer (TempoMap&, size_t nseqs, size_t nsteps, Temporal::Beats const & step_size, Temporal::Beats const & bar_size, int notenum);
233 
234  size_t step_capacity() const { return _step_capacity; }
235  size_t nsteps() const { return _end_step - _start_step; }
236  size_t nsequences() const { return _sequences.size(); }
237 
238  int last_step() const;
239 
240  StepSequence& sequence (size_t n) const;
241 
243 
244  Temporal::Beats step_size () const { return _step_size; }
246 
247  void set_start_step (size_t);
248  void set_end_step (size_t);
249 
250  size_t start_step() const { return _start_step; }
251  size_t end_step() const { return _end_step; }
252 
253  void sync (); /* return all rows to start step */
254  void reset (); /* return entire state to default */
255 
256  bool run (MidiBuffer& buf, samplepos_t, samplepos_t, double, pframes_t, bool);
257 
258  TempoMap& tempo_map() const { return _tempo_map; }
259 
260  XMLNode& get_state() const;
261  int set_state (XMLNode const &, int);
262 
263  void queue_note_off (Temporal::Beats const &, uint8_t note, uint8_t velocity, uint8_t channel);
264 
265  std::shared_ptr<Source> write_to_source (Session& s, std::string p = std::string()) const;
266 
267  private:
268  mutable Glib::Threads::Mutex _sequence_lock;
270 
271  typedef std::vector<StepSequence*> StepSequences;
273 
274  Temporal::Beats _last_startup; /* last time we started running */
275  size_t _last_step; /* last step that we executed */
277  size_t _start_step;
278  size_t _end_step;
280  samplepos_t last_end; /* end sample time of last run() call */
281  bool _running;
283 
285 
286  struct Request {
287 
288  /* bitwise types, so we can combine multiple in one
289  */
290 
291  enum Type {
293  SetEndStep = 0x2,
295  SetStepSize = 0x8,
296  };
297 
299 
301  size_t nsequences;
302  size_t start_step;
303  size_t end_step;
304 
306 
307  void *operator new (size_t) {
308  return pool.alloc ();
309  }
310 
311  void operator delete (void* ptr, size_t /* size */) {
312  pool.release (ptr);
313  }
314  };
315 
317  bool check_requests ();
319 
320  struct NoteOffBlob : public boost::intrusive::list_base_hook<> {
321 
322  NoteOffBlob (Temporal::Beats const & w, uint8_t n, uint8_t v, uint8_t c)
323  : when (w) { buf[0] = 0x80|c; buf[1] = n; buf[2] = v; }
324 
326  uint8_t buf[3];
327 
328  static PBD::Pool pool;
329 
330  void *operator new (size_t) {
331  return pool.alloc ();
332  }
333 
334  void operator delete (void* ptr, size_t /* size */) {
335  pool.release (ptr);
336  }
337 
338  bool operator< (NoteOffBlob const & other) const {
339  return when < other.when;
340  }
341  };
342 
343  typedef boost::intrusive::list<NoteOffBlob> NoteOffList;
344 
346  void check_note_offs (ARDOUR::MidiBuffer&, samplepos_t start_sample, samplepos_t last_sample);
348 
349  bool fill_midi_source (std::shared_ptr<SMFSource> src) const;
350 
351 };
352 
353 } /* namespace */
354 
void shift_right(size_t n=1)
XMLNode & get_state() const
Step & step(size_t n) const
void schedule(Temporal::Beats const &)
size_t index() const
void shift_left(size_t n=1)
StepSequencer & _sequencer
void set_root(int n)
Glib::Threads::Mutex _step_lock
bool run(MidiBuffer &buf, bool running, samplepos_t, samplepos_t, MidiNoteTracker &)
void reschedule(Temporal::Beats const &, Temporal::Beats const &)
void set_mode(MusicalMode m)
void dump(MusicTimeEvents &, Temporal::Beats const &) const
Temporal::Beats wrap(Temporal::Beats const &) const
StepSequence(StepSequencer &myseq, size_t index, size_t nsteps, Temporal::Beats const &step_size, Temporal::Beats const &bar_size, int notenum)
size_t nsteps() const
int set_state(XMLNode const &, int)
MusicalMode mode() const
std::vector< Step * > Steps
StepSequencer & sequencer() const
void startup(Temporal::Beats const &start, Temporal::Beats const &offset)
void check_note_offs(ARDOUR::MidiBuffer &, samplepos_t start_sample, samplepos_t last_sample)
ARDOUR::MidiNoteTracker outbound_tracker
StepSequences _sequences
boost::intrusive::list< NoteOffBlob > NoteOffList
void set_end_step(size_t)
size_t end_step() const
Temporal::Beats _step_size
std::shared_ptr< Source > write_to_source(Session &s, std::string p=std::string()) const
int set_state(XMLNode const &, int)
void set_start_step(size_t)
size_t step_capacity() const
size_t nsequences() const
size_t nsteps() const
PBD::RingBuffer< Request * > requests
TempoMap & tempo_map() const
XMLNode & get_state() const
bool fill_midi_source(std::shared_ptr< SMFSource > src) const
Temporal::Beats reschedule(samplepos_t)
size_t start_step() const
void queue_note_off(Temporal::Beats const &, uint8_t note, uint8_t velocity, uint8_t channel)
std::vector< StepSequence * > StepSequences
bool run(MidiBuffer &buf, samplepos_t, samplepos_t, double, pframes_t, bool)
StepSequencer(TempoMap &, size_t nseqs, size_t nsteps, Temporal::Beats const &step_size, Temporal::Beats const &bar_size, int notenum)
StepSequence & sequence(size_t n) const
Glib::Threads::Mutex _sequence_lock
Temporal::Beats duration() const
Temporal::Beats _last_startup
Temporal::Beats step_size() const
void set_step_size(Temporal::Beats const &)
void adjust_velocity(int amt)
ParameterValue _parameters[_parameters_per_step]
StepSequence & _sequence
boost::rational< int > DurationRatio
Temporal::Beats _scheduled_beat
bool run(MidiBuffer &buf, bool running, samplepos_t, samplepos_t, MidiNoteTracker &)
void adjust_octave(int amt)
void dump_parameter(MusicTimeEvents &, size_t n, Temporal::Beats const &) const
void reschedule(Temporal::Beats const &, Temporal::Beats const &)
Temporal::Beats _nominal_beat
int parameter_value(size_t n=0) const
void adjust_duration(DurationRatio const &amt)
static const int _parameters_per_step
void adjust_pitch(int amt)
void adjust_offset(double fraction)
Mode mode() const
void set_enabled(bool)
void dump(MusicTimeEvents &, Temporal::Beats const &) const
void set_note(double note, double velocity=0.5, int n=0)
XMLNode & get_state() const
void set_velocity(double, size_t n=0)
DurationRatio duration() const
void set_chord(size_t note_cnt, double *notes)
size_t repeat() const
Temporal::Beats offset(size_t n=0) const
DurationRatio _duration
Note _notes[_notes_per_step]
void set_duration(DurationRatio const &)
static const int _notes_per_step
void set_parameter(int number, double value, int n=0)
void dump_note(MusicTimeEvents &, size_t n, Temporal::Beats const &) const
int set_state(XMLNode const &, int)
int parameter(size_t n=0) const
void check_parameter(size_t n, MidiBuffer &buf, bool, samplepos_t, samplepos_t)
int octave_shift() const
double velocity(size_t n=0) const
Step(StepSequence &, size_t n, Temporal::Beats const &beat, int notenum)
void set_mode(Mode m)
double note(size_t n=0) const
void set_skipped(bool)
void set_repeat(size_t r)
void set_beat(Temporal::Beats const &beat)
StepSequencer & sequencer() const
size_t index() const
void set_offset(Temporal::Beats const &, size_t n=0)
void set_octave_shift(int)
bool enabled() const
void check_note(size_t n, MidiBuffer &buf, bool, samplepos_t, samplepos_t, MidiNoteTracker &)
bool skipped() const
Temporal::Beats beat() const
virtual void release(void *)
Definition: pool.h:40
virtual void * alloc()
virtual void release(void *)
Definition: xml++.h:114
PBD::PropertyDescriptor< bool > running
PBD::PropertyDescriptor< timepos_t > start
std::vector< MusicTimeEvent * > MusicTimeEvents
uint32_t pframes_t
Evoral::Event< Temporal::Beats > MusicTimeEvent
std::pair< Temporal::Beats, samplepos_t > BeatPosition
std::vector< BeatPosition > BeatPositions
Temporal::samplepos_t samplepos_t
bool operator<(NoteOffBlob const &other) const
NoteOffBlob(Temporal::Beats const &w, uint8_t n, uint8_t v, uint8_t c)
static PBD::MultiAllocSingleReleasePool pool
Note(double n, double v, Temporal::Beats const &o)
MIDI::byte off_msg[3]
Temporal::Beats offset