Ardour  9.2-79-gba93f2fe52
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 "pbd/pool.h"
28 #include "pbd/ringbuffer.h"
29 #include "pbd/stateful.h"
30 
31 #include "evoral/Event.h"
32 
33 #include "temporal/types.h"
34 #include "temporal/beats.h"
35 
36 #include "ardour/mode.h"
38 #include "ardour/types.h"
39 
40 #include "midi++/types.h"
41 
42 namespace ARDOUR {
43 
44 class MidiBuffer;
45 class MidiNoteTracker;
46 class StepSequencer;
47 class StepSequence;
48 class TempoMap;
49 class SMFSource;
50 
51 typedef std::pair<Temporal::Beats,samplepos_t> BeatPosition;
52 typedef std::vector<BeatPosition> BeatPositions;
53 
55 typedef std::vector<MusicTimeEvent*> MusicTimeEvents;
56 
57 class Step : public PBD::Stateful {
58  public:
59  enum Mode {
62  };
63 
64  typedef boost::rational<int> DurationRatio;
65 
66  Step (StepSequence&, size_t n, Temporal::Beats const & beat, int notenum);
67  ~Step ();
68 
69  size_t index() const { return _index; }
70 
71  void set_note (double note, double velocity = 0.5, int n = 0);
72  void set_chord (size_t note_cnt, double* notes);
73  void set_parameter (int number, double value, int n = 0);
74 
75  void adjust_velocity (int amt);
76  void adjust_pitch (int amt);
77  void adjust_duration (DurationRatio const & amt);
78  void adjust_octave (int amt);
79  void adjust_offset (double fraction);
80 
81  Mode mode() const { return _mode; }
82  void set_mode (Mode m);
83 
84  double note (size_t n = 0) const { return _notes[n].number; }
85  double velocity (size_t n = 0) const { return _notes[n].velocity; }
86  void set_velocity (double, size_t n = 0);
87 
88  DurationRatio duration () const { return _duration; }
89  void set_duration (DurationRatio const &);
90 
91  void set_offset (Temporal::Beats const &, size_t n = 0);
92  Temporal::Beats offset (size_t n = 0) const { return _notes[n].offset; }
93 
94  int parameter (size_t n = 0) const { return _parameters[n].parameter; }
95  int parameter_value (size_t n = 0) const { return _parameters[n].value; }
96 
97  void set_enabled (bool);
98  bool enabled() const { return _enabled; }
99 
100  void set_repeat (size_t r);
101  size_t repeat() const { return _repeat; }
102 
103  void set_beat (Temporal::Beats const & beat);
104  Temporal::Beats beat () const { return _nominal_beat; }
105 
107 
108  bool skipped() const { return _skipped; }
109  void set_skipped (bool);
110 
111  void reschedule (Temporal::Beats const &, Temporal::Beats const &);
112 
113  int octave_shift() const { return _octave_shift; }
114  void set_octave_shift (int);
115 
116  XMLNode& get_state() const;
117  int set_state (XMLNode const &, int);
118 
119  void dump (MusicTimeEvents&, Temporal::Beats const&) const;
120 
121  static const int _notes_per_step = 5;
122  static const int _parameters_per_step = 5;
123 
124  private:
125  friend class StepSequence; /* HACK */
126 
128  size_t _index;
129  bool _enabled;
132  bool _skipped;
136 
137  struct ParameterValue {
139  double value;
140  };
141 
142  struct Note {
143  union {
144  double number; /* typically MIDI note number */
145  double interval; /* semitones */
146  };
147  double velocity;
150 
151  Note () : number (-1), velocity (0.0) {}
152  Note (double n, double v,Temporal::Beats const & o) : number (n), velocity (v), offset (o) {}
153  };
154 
157  size_t _repeat;
158 
160  void check_parameter (size_t n, MidiBuffer& buf, bool, samplepos_t, samplepos_t);
161  void dump_note (MusicTimeEvents&, size_t n, Temporal::Beats const &) const;
162  void dump_parameter (MusicTimeEvents&, size_t n, Temporal::Beats const &) const;
163 
165 };
166 
168 {
169  public:
170  enum Direction {
171  forwards = 0,
174  rd_random = 3
175  };
176 
177  StepSequence (StepSequencer &myseq, size_t index, size_t nsteps, Temporal::Beats const & step_size, Temporal::Beats const & bar_size, int notenum);
179 
180  size_t index() const { return _index; }
181  size_t nsteps() const { return _steps.size(); }
182 
183  Step& step (size_t n) const;
184 
185  void startup (Temporal::Beats const & start, Temporal::Beats const & offset);
186 
187  int root() const { return _root; }
188  void set_root (int n);
189 
190  int channel() const { return _channel; }
191  void set_channel (int);
192 
194 
195  MusicalMode mode() const { return _mode; }
197 
198  void shift_left (size_t n = 1);
199  void shift_right (size_t n = 1);
200 
201  void reset ();
202  void reschedule (Temporal::Beats const &, Temporal::Beats const &);
203  void schedule (Temporal::Beats const &);
204 
206 
207  StepSequencer& sequencer() const { return _sequencer; }
208 
209  XMLNode& get_state() const;
210  int set_state (XMLNode const &, int);
211 
212  void dump (MusicTimeEvents&, Temporal::Beats const &) const;
213 
214  private:
216  int _index;
218  typedef std::vector<Step*> Steps;
219 
221  int _channel; /* MIDI channel */
222  int _root;
224 };
225 
227 {
228  public:
229  StepSequencer (TempoMap&, size_t nseqs, size_t nsteps, Temporal::Beats const & step_size, Temporal::Beats const & bar_size, int notenum);
231 
232  size_t step_capacity() const { return _step_capacity; }
233  size_t nsteps() const { return _end_step - _start_step; }
234  size_t nsequences() const { return _sequences.size(); }
235 
236  int last_step() const;
237 
238  StepSequence& sequence (size_t n) const;
239 
241 
242  Temporal::Beats step_size () const { return _step_size; }
244 
245  void set_start_step (size_t);
246  void set_end_step (size_t);
247 
248  size_t start_step() const { return _start_step; }
249  size_t end_step() const { return _end_step; }
250 
251  void sync (); /* return all rows to start step */
252  void reset (); /* return entire state to default */
253 
254  bool run (MidiBuffer& buf, samplepos_t, samplepos_t, double, pframes_t, bool);
255 
256  TempoMap& tempo_map() const { return _tempo_map; }
257 
258  XMLNode& get_state() const;
259  int set_state (XMLNode const &, int);
260 
261  void queue_note_off (Temporal::Beats const &, uint8_t note, uint8_t velocity, uint8_t channel);
262 
263  std::shared_ptr<Source> write_to_source (Session& s, std::string p = std::string()) const;
264 
265  private:
268 
269  typedef std::vector<StepSequence*> StepSequences;
271 
272  Temporal::Beats _last_startup; /* last time we started running */
273  size_t _last_step; /* last step that we executed */
275  size_t _start_step;
276  size_t _end_step;
278  samplepos_t last_end; /* end sample time of last run() call */
279  bool _running;
281 
283 
284  struct Request {
285 
286  /* bitwise types, so we can combine multiple in one
287  */
288 
289  enum Type {
291  SetEndStep = 0x2,
293  SetStepSize = 0x8,
294  };
295 
297 
299  size_t nsequences;
300  size_t start_step;
301  size_t end_step;
302 
304 
305  void *operator new (size_t) {
306  return pool.alloc ();
307  }
308 
309  void operator delete (void* ptr, size_t /* size */) {
310  pool.release (ptr);
311  }
312  };
313 
315  bool check_requests ();
317 
318  struct NoteOffBlob : public boost::intrusive::list_base_hook<> {
319 
320  NoteOffBlob (Temporal::Beats const & w, uint8_t n, uint8_t v, uint8_t c)
321  : when (w) { buf[0] = 0x80|c; buf[1] = n; buf[2] = v; }
322 
324  uint8_t buf[3];
325 
326  static PBD::Pool pool;
327 
328  void *operator new (size_t) {
329  return pool.alloc ();
330  }
331 
332  void operator delete (void* ptr, size_t /* size */) {
333  pool.release (ptr);
334  }
335 
336  bool operator< (NoteOffBlob const & other) const {
337  return when < other.when;
338  }
339  };
340 
341  typedef boost::intrusive::list<NoteOffBlob> NoteOffList;
342 
344  void check_note_offs (ARDOUR::MidiBuffer&, samplepos_t start_sample, samplepos_t last_sample);
346 
347  bool fill_midi_source (std::shared_ptr<SMFSource> src) const;
348 
349 };
350 
351 } /* namespace */
352 
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)
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
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