26bef20232a04a1ce5af757d8c9c312c887a0861
[ardour.git] / libs / evoral / evoral / Sequence.hpp
1 /* This file is part of Evoral.
2  * Copyright (C) 2008 David Robillard <http://drobilla.net>
3  * Copyright (C) 2000-2008 Paul Davis
4  *
5  * Evoral is free software; you can redistribute it and/or modify it under the
6  * terms of the GNU General Public License as published by the Free Software
7  * Foundation; either version 2 of the License, or (at your option) any later
8  * version.
9  *
10  * Evoral is distributed in the hope that it will be useful, but WITHOUT ANY
11  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #ifndef EVORAL_SEQUENCE_HPP
20 #define EVORAL_SEQUENCE_HPP
21
22 #include <vector>
23 #include <queue>
24 #include <set>
25 #include <list>
26 #include <utility>
27 #include <boost/shared_ptr.hpp>
28 #include <glibmm/threads.h>
29 #include "evoral/types.hpp"
30 #include "evoral/Note.hpp"
31 #include "evoral/Parameter.hpp"
32 #include "evoral/ControlSet.hpp"
33 #include "evoral/ControlList.hpp"
34 #include "evoral/PatchChange.hpp"
35
36 namespace Evoral {
37
38 class TypeMap;
39 template<typename Time> class EventSink;
40 template<typename Time> class Note;
41 template<typename Time> class Event;
42
43 /** An iterator over (the x axis of) a 2-d double coordinate space.
44  */
45 class ControlIterator {
46 public:
47         ControlIterator(boost::shared_ptr<const ControlList> al, double ax, double ay)
48                 : list(al)
49                 , x(ax)
50                 , y(ay)
51         {}
52
53         boost::shared_ptr<const ControlList> list;
54         double x;
55         double y;
56 };
57
58
59 /** This is a higher level view of events, with separate representations for
60  * notes (instead of just unassociated note on/off events) and controller data.
61  * Controller data is represented as a list of time-stamped float values. */
62 template<typename Time>
63 class Sequence : virtual public ControlSet {
64 public:
65         Sequence(const TypeMap& type_map);
66         Sequence(const Sequence<Time>& other);
67
68 protected:
69         struct WriteLockImpl {
70                 WriteLockImpl(Glib::Threads::RWLock& s, Glib::Threads::Mutex& c)
71                         : sequence_lock(new Glib::Threads::RWLock::WriterLock(s))
72                         , control_lock(new Glib::Threads::Mutex::Lock(c)) { }
73                 ~WriteLockImpl() {
74                         delete sequence_lock;
75                         delete control_lock;
76                 }
77                 Glib::Threads::RWLock::WriterLock* sequence_lock;
78                 Glib::Threads::Mutex::Lock*        control_lock;
79         };
80
81 public:
82
83         typedef typename boost::shared_ptr<Evoral::Note<Time> >  NotePtr;
84         typedef typename boost::shared_ptr<const Evoral::Note<Time> >  constNotePtr;
85
86         typedef boost::shared_ptr<Glib::Threads::RWLock::ReaderLock> ReadLock;
87         typedef boost::shared_ptr<WriteLockImpl>            WriteLock;
88
89         virtual ReadLock  read_lock() const { return ReadLock(new Glib::Threads::RWLock::ReaderLock(_lock)); }
90         virtual WriteLock write_lock()      { return WriteLock(new WriteLockImpl(_lock, _control_lock)); }
91
92         void clear();
93
94         bool percussive() const     { return _percussive; }
95         void set_percussive(bool p) { _percussive = p; }
96
97         void start_write();
98         bool writing() const { return _writing; }
99
100         enum StuckNoteOption {
101                 Relax,
102                 DeleteStuckNotes,
103                 ResolveStuckNotes
104         };
105
106         void end_write (StuckNoteOption, Time when = 0);
107
108         void append(const Event<Time>& ev, Evoral::event_id_t evid);
109
110         inline size_t n_notes() const { return _notes.size(); }
111         inline bool   empty()   const { return _notes.empty() && _sysexes.empty() && _patch_changes.empty() && ControlSet::controls_empty(); }
112
113         inline static bool note_time_comparator(const boost::shared_ptr< const Note<Time> >& a,
114                                                 const boost::shared_ptr< const Note<Time> >& b) {
115                 return a->time() < b->time();
116         }
117
118         struct NoteNumberComparator {
119                 inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
120                                        const boost::shared_ptr< const Note<Time> > b) const {
121                         return a->note() < b->note();
122                 }
123         };
124
125         struct EarlierNoteComparator {
126                 inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
127                                        const boost::shared_ptr< const Note<Time> > b) const {
128                         return musical_time_less_than (a->time(), b->time());
129                 }
130         };
131
132         struct LaterNoteComparator {
133                 typedef const Note<Time>* value_type;
134                 inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
135                                        const boost::shared_ptr< const Note<Time> > b) const {
136                         return musical_time_greater_than (a->time(), b->time());
137                         return a->time() > b->time();
138                 }
139         };
140
141         struct LaterNoteEndComparator {
142                 typedef const Note<Time>* value_type;
143                 inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
144                                        const boost::shared_ptr< const Note<Time> > b) const {
145                         return musical_time_less_than (a->end_time(), b->end_time());
146                 }
147         };
148
149         typedef std::multiset<NotePtr, EarlierNoteComparator> Notes;
150         inline       Notes& notes()       { return _notes; }
151         inline const Notes& notes() const { return _notes; }
152
153         enum NoteOperator {
154                 PitchEqual,
155                 PitchLessThan,
156                 PitchLessThanOrEqual,
157                 PitchGreater,
158                 PitchGreaterThanOrEqual,
159                 VelocityEqual,
160                 VelocityLessThan,
161                 VelocityLessThanOrEqual,
162                 VelocityGreater,
163                 VelocityGreaterThanOrEqual,
164         };
165
166         void get_notes (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;
167
168         void remove_overlapping_notes ();
169         void trim_overlapping_notes ();
170         void remove_duplicate_notes ();
171
172         enum OverlapPitchResolution {
173                 LastOnFirstOff,
174                 FirstOnFirstOff
175         };
176
177         bool overlapping_pitches_accepted() const { return _overlapping_pitches_accepted; }
178         void overlapping_pitches_accepted(bool yn)  { _overlapping_pitches_accepted = yn; }
179         OverlapPitchResolution overlap_pitch_resolution() const { return _overlap_pitch_resolution; }
180         void set_overlap_pitch_resolution(OverlapPitchResolution opr);
181
182         void set_notes (const Sequence<Time>::Notes& n);
183
184         typedef boost::shared_ptr< Event<Time> > SysExPtr;
185         typedef boost::shared_ptr<const Event<Time> > constSysExPtr;
186
187         struct EarlierSysExComparator {
188                 inline bool operator() (constSysExPtr a, constSysExPtr b) const {
189                         return musical_time_less_than (a->time(), b->time());
190                 }
191         };
192
193         typedef std::multiset<SysExPtr, EarlierSysExComparator> SysExes;
194         inline       SysExes& sysexes()       { return _sysexes; }
195         inline const SysExes& sysexes() const { return _sysexes; }
196
197         typedef boost::shared_ptr<PatchChange<Time> > PatchChangePtr;
198         typedef boost::shared_ptr<const PatchChange<Time> > constPatchChangePtr;
199
200         struct EarlierPatchChangeComparator {
201                 inline bool operator() (constPatchChangePtr a, constPatchChangePtr b) const {
202                         return musical_time_less_than (a->time(), b->time());
203                 }
204         };
205
206         typedef std::multiset<PatchChangePtr, EarlierPatchChangeComparator> PatchChanges;
207         inline       PatchChanges& patch_changes ()       { return _patch_changes; }
208         inline const PatchChanges& patch_changes () const { return _patch_changes; }
209
210         void dump (std::ostream&) const;
211
212 private:
213         typedef std::priority_queue<NotePtr, std::deque<NotePtr>, LaterNoteEndComparator> ActiveNotes;
214 public:
215
216         /** Read iterator */
217         class const_iterator {
218         public:
219                 const_iterator();
220                 const_iterator(const Sequence<Time>& seq, Time t, bool, std::set<Evoral::Parameter> const &);
221                 ~const_iterator();
222
223                 inline bool valid() const { return !_is_end && _event; }
224                 //inline bool locked() const { return _locked; }
225
226                 void invalidate();
227
228                 const Event<Time>& operator*()  const { return *_event;  }
229                 const boost::shared_ptr< Event<Time> > operator->() const  { return _event; }
230                 const boost::shared_ptr< Event<Time> > get_event_pointer() { return _event; }
231
232                 const const_iterator& operator++(); // prefix only
233
234                 bool operator==(const const_iterator& other) const;
235                 bool operator!=(const const_iterator& other) const { return ! operator==(other); }
236
237                 const_iterator& operator=(const const_iterator& other);
238
239         private:
240                 friend class Sequence<Time>;
241
242                 typedef std::vector<ControlIterator> ControlIterators;
243                 enum MIDIMessageType { NIL, NOTE_ON, NOTE_OFF, CONTROL, SYSEX, PATCH_CHANGE };
244
245                 const Sequence<Time>*                 _seq;
246                 boost::shared_ptr< Event<Time> >      _event;
247                 mutable ActiveNotes                   _active_notes;
248                 /** If the iterator is pointing at a patch change, this is the index of the
249                  *  sub-message within that change.
250                  */
251                 int                                   _active_patch_change_message;
252                 MIDIMessageType                       _type;
253                 bool                                  _is_end;
254                 typename Sequence::ReadLock           _lock;
255                 typename Notes::const_iterator        _note_iter;
256                 typename SysExes::const_iterator      _sysex_iter;
257                 typename PatchChanges::const_iterator _patch_change_iter;
258                 ControlIterators                      _control_iters;
259                 ControlIterators::iterator            _control_iter;
260                 bool                                  _force_discrete;
261         };
262
263         const_iterator begin (
264                 Time t = 0,
265                 bool force_discrete = false,
266                 std::set<Evoral::Parameter> const & f = std::set<Evoral::Parameter> ()) const {
267                 return const_iterator (*this, t, force_discrete, f);
268         }
269
270         const const_iterator& end() const { return _end_iter; }
271
272         typename Notes::const_iterator note_lower_bound (Time t) const;
273         typename PatchChanges::const_iterator patch_change_lower_bound (Time t) const;
274         typename SysExes::const_iterator sysex_lower_bound (Time t) const;
275
276         bool control_to_midi_event(boost::shared_ptr< Event<Time> >& ev,
277                                    const ControlIterator&            iter) const;
278
279         bool edited() const      { return _edited; }
280         void set_edited(bool yn) { _edited = yn; }
281
282         bool overlaps (const NotePtr& ev,
283                        const NotePtr& ignore_this_note) const;
284         bool contains (const NotePtr& ev) const;
285
286         bool add_note_unlocked (const NotePtr note, void* arg = 0);
287         void remove_note_unlocked(const constNotePtr note);
288
289         void add_patch_change_unlocked (const PatchChangePtr);
290         void remove_patch_change_unlocked (const constPatchChangePtr);
291
292         void add_sysex_unlocked (const SysExPtr);
293         void remove_sysex_unlocked (const SysExPtr);
294
295         uint8_t lowest_note()  const { return _lowest_note; }
296         uint8_t highest_note() const { return _highest_note; }
297
298
299 protected:
300         bool                   _edited;
301         bool                   _overlapping_pitches_accepted;
302         OverlapPitchResolution _overlap_pitch_resolution;
303         mutable Glib::Threads::RWLock   _lock;
304         bool                   _writing;
305
306         virtual int resolve_overlaps_unlocked (const NotePtr, void* /* arg */ = 0) {
307                 return 0;
308         }
309
310         typedef std::multiset<NotePtr, NoteNumberComparator>  Pitches;
311         inline       Pitches& pitches(uint8_t chan)       { return _pitches[chan&0xf]; }
312         inline const Pitches& pitches(uint8_t chan) const { return _pitches[chan&0xf]; }
313
314         virtual void control_list_marked_dirty ();
315
316 private:
317         friend class const_iterator;
318
319         bool overlaps_unlocked (const NotePtr& ev, const NotePtr& ignore_this_note) const;
320         bool contains_unlocked (const NotePtr& ev) const;
321
322         void append_note_on_unlocked (NotePtr, Evoral::event_id_t);
323         void append_note_off_unlocked(NotePtr);
324         void append_control_unlocked(const Parameter& param, Time time, double value, Evoral::event_id_t);
325         void append_sysex_unlocked(const MIDIEvent<Time>& ev, Evoral::event_id_t);
326         void append_patch_change_unlocked (const PatchChange<Time>&, Evoral::event_id_t);
327
328         void get_notes_by_pitch (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;
329         void get_notes_by_velocity (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;
330
331         const TypeMap& _type_map;
332
333         Notes        _notes;       // notes indexed by time
334         Pitches      _pitches[16]; // notes indexed by channel+pitch
335         SysExes      _sysexes;
336         PatchChanges _patch_changes;
337
338         typedef std::multiset<NotePtr, EarlierNoteComparator> WriteNotes;
339         WriteNotes _write_notes[16];
340
341         /** Current bank number on each channel so that we know what
342          *  to put in PatchChange events when program changes are
343          *  seen.
344          */
345         int _bank[16];
346
347         const   const_iterator _end_iter;
348         bool                   _percussive;
349
350         uint8_t _lowest_note;
351         uint8_t _highest_note;
352 };
353
354
355 } // namespace Evoral
356
357 template<typename Time> std::ostream& operator<<(std::ostream& o, const Evoral::Sequence<Time>& s) { s.dump (o); return o; }
358
359 #endif // EVORAL_SEQUENCE_HPP
360