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