attempt to handle poly-pressure (polyphonic aftertouch) similarly to other MIDI messages
[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
30 #include "evoral/visibility.h"
31 #include "evoral/Note.hpp"
32 #include "evoral/ControlSet.hpp"
33 #include "evoral/ControlList.hpp"
34 #include "evoral/PatchChange.hpp"
35
36 namespace Evoral {
37
38 class Parameter;
39 class TypeMap;
40 template<typename Time> class EventSink;
41 template<typename Time> class Note;
42 template<typename Time> class Event;
43
44 /** An iterator over (the x axis of) a 2-d double coordinate space.
45  */
46 class /*LIBEVORAL_API*/ ControlIterator {
47 public:
48         ControlIterator(boost::shared_ptr<const ControlList> al, double ax, double ay)
49                 : list(al)
50                 , x(ax)
51                 , y(ay)
52         {}
53
54         boost::shared_ptr<const ControlList> list;
55         double x;
56         double y;
57 };
58
59
60 /** This is a higher level view of events, with separate representations for
61  * notes (instead of just unassociated note on/off events) and controller data.
62  * Controller data is represented as a list of time-stamped float values. */
63 template<typename Time>
64 class LIBEVORAL_API Sequence : virtual public ControlSet {
65 public:
66         Sequence(const TypeMap& type_map);
67         Sequence(const Sequence<Time>& other);
68
69 protected:
70         struct WriteLockImpl {
71                 WriteLockImpl(Glib::Threads::RWLock& s, Glib::Threads::Mutex& c)
72                         : sequence_lock(new Glib::Threads::RWLock::WriterLock(s))
73                         , control_lock(new Glib::Threads::Mutex::Lock(c)) { }
74                 ~WriteLockImpl() {
75                         delete sequence_lock;
76                         delete control_lock;
77                 }
78                 Glib::Threads::RWLock::WriterLock* sequence_lock;
79                 Glib::Threads::Mutex::Lock*        control_lock;
80         };
81
82 public:
83
84         typedef typename boost::shared_ptr<Evoral::Note<Time> >       NotePtr;
85         typedef typename boost::weak_ptr<Evoral::Note<Time> >         WeakNotePtr;
86         typedef typename boost::shared_ptr<const Evoral::Note<Time> > constNotePtr;
87
88         typedef boost::shared_ptr<Glib::Threads::RWLock::ReaderLock> ReadLock;
89         typedef boost::shared_ptr<WriteLockImpl>                     WriteLock;
90
91         virtual ReadLock  read_lock() const { return ReadLock(new Glib::Threads::RWLock::ReaderLock(_lock)); }
92         virtual WriteLock write_lock()      { return WriteLock(new WriteLockImpl(_lock, _control_lock)); }
93
94         void clear();
95
96         bool percussive() const     { return _percussive; }
97         void set_percussive(bool p) { _percussive = p; }
98
99         void start_write();
100         bool writing() const { return _writing; }
101
102         enum StuckNoteOption {
103                 Relax,
104                 DeleteStuckNotes,
105                 ResolveStuckNotes
106         };
107
108         void end_write (StuckNoteOption, Time when = Time());
109
110         void append(const Event<Time>& ev, Evoral::event_id_t evid);
111
112         const TypeMap& type_map() const { return _type_map; }
113
114         inline size_t n_notes() const { return _notes.size(); }
115         inline bool   empty()   const { return _notes.empty() && _sysexes.empty() && _patch_changes.empty() && ControlSet::controls_empty(); }
116
117         inline static bool note_time_comparator(const boost::shared_ptr< const Note<Time> >& a,
118                                                 const boost::shared_ptr< const Note<Time> >& b) {
119                 return a->time() < b->time();
120         }
121
122         struct NoteNumberComparator {
123                 inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
124                                        const boost::shared_ptr< const Note<Time> > b) const {
125                         return a->note() < b->note();
126                 }
127         };
128
129         struct EarlierNoteComparator {
130                 inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
131                                        const boost::shared_ptr< const Note<Time> > b) const {
132                         return a->time() < b->time();
133                 }
134         };
135
136 #if 0 // NOT USED
137         struct LaterNoteComparator {
138                 typedef const Note<Time>* value_type;
139                 inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
140                                        const boost::shared_ptr< const Note<Time> > b) const {
141                         return a->time() > b->time();
142                 }
143         };
144 #endif
145
146         struct LaterNoteEndComparator {
147                 typedef const Note<Time>* value_type;
148                 inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
149                                        const boost::shared_ptr< const Note<Time> > b) const {
150                         return a->end_time().to_double() > b->end_time().to_double();
151                 }
152         };
153
154         typedef std::multiset<NotePtr, EarlierNoteComparator> Notes;
155         inline       Notes& notes()       { return _notes; }
156         inline const Notes& notes() const { return _notes; }
157
158         enum NoteOperator {
159                 PitchEqual,
160                 PitchLessThan,
161                 PitchLessThanOrEqual,
162                 PitchGreater,
163                 PitchGreaterThanOrEqual,
164                 VelocityEqual,
165                 VelocityLessThan,
166                 VelocityLessThanOrEqual,
167                 VelocityGreater,
168                 VelocityGreaterThanOrEqual,
169         };
170
171         void get_notes (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;
172
173         void remove_overlapping_notes ();
174         void trim_overlapping_notes ();
175         void remove_duplicate_notes ();
176
177         enum OverlapPitchResolution {
178                 LastOnFirstOff,
179                 FirstOnFirstOff
180         };
181
182         bool overlapping_pitches_accepted() const { return _overlapping_pitches_accepted; }
183         void overlapping_pitches_accepted(bool yn)  { _overlapping_pitches_accepted = yn; }
184         OverlapPitchResolution overlap_pitch_resolution() const { return _overlap_pitch_resolution; }
185         void set_overlap_pitch_resolution(OverlapPitchResolution opr);
186
187         void set_notes (const typename Sequence<Time>::Notes& n);
188
189         typedef boost::shared_ptr< Event<Time> > SysExPtr;
190         typedef boost::shared_ptr<const Event<Time> > constSysExPtr;
191
192         struct EarlierSysExComparator {
193                 inline bool operator() (constSysExPtr a, constSysExPtr b) const {
194                         return a->time() < b->time();
195                 }
196         };
197
198         typedef std::multiset<SysExPtr, EarlierSysExComparator> SysExes;
199         inline       SysExes& sysexes()       { return _sysexes; }
200         inline const SysExes& sysexes() const { return _sysexes; }
201
202         typedef boost::shared_ptr<PatchChange<Time> > PatchChangePtr;
203         typedef boost::shared_ptr<const PatchChange<Time> > constPatchChangePtr;
204
205         struct EarlierPatchChangeComparator {
206                 inline bool operator() (constPatchChangePtr a, constPatchChangePtr b) const {
207                         return a->time() < b->time();
208                 }
209         };
210
211         typedef std::multiset<PatchChangePtr, EarlierPatchChangeComparator> PatchChanges;
212         inline       PatchChanges& patch_changes ()       { return _patch_changes; }
213         inline const PatchChanges& patch_changes () const { return _patch_changes; }
214
215         void dump (std::ostream&) const;
216
217 private:
218         typedef std::priority_queue<NotePtr, std::deque<NotePtr>, LaterNoteEndComparator> ActiveNotes;
219 public:
220
221         /** Read iterator */
222         class LIBEVORAL_API const_iterator {
223         public:
224                 const_iterator();
225                 const_iterator(const Sequence<Time>&              seq,
226                                Time                               t,
227                                bool                               force_discrete,
228                                const std::set<Evoral::Parameter>& filtered,
229                                const std::set<WeakNotePtr>*       active_notes=NULL);
230
231                 inline bool valid() const { return !_is_end && _event; }
232
233                 void invalidate(std::set<WeakNotePtr>* notes);
234
235                 const Event<Time>& operator*()  const { return *_event;  }
236                 const boost::shared_ptr< Event<Time> > operator->() const  { return _event; }
237                 const boost::shared_ptr< Event<Time> > get_event_pointer() { return _event; }
238
239                 const const_iterator& operator++(); // prefix only
240
241                 bool operator==(const const_iterator& other) const;
242                 bool operator!=(const const_iterator& other) const { return ! operator==(other); }
243
244                 const_iterator& operator=(const const_iterator& other);
245
246         private:
247                 friend class Sequence<Time>;
248
249                 Time choose_next(Time earliest_t);
250                 void set_event();
251
252                 typedef std::vector<ControlIterator> ControlIterators;
253                 enum MIDIMessageType { NIL, NOTE_ON, NOTE_OFF, CONTROL, SYSEX, PATCH_CHANGE };
254
255                 const Sequence<Time>*                 _seq;
256                 boost::shared_ptr< Event<Time> >      _event;
257                 mutable ActiveNotes                   _active_notes;
258                 /** If the iterator is pointing at a patch change, this is the index of the
259                  *  sub-message within that change.
260                  */
261                 int                                   _active_patch_change_message;
262                 MIDIMessageType                       _type;
263                 bool                                  _is_end;
264                 typename Sequence::ReadLock           _lock;
265                 typename Notes::const_iterator        _note_iter;
266                 typename SysExes::const_iterator      _sysex_iter;
267                 typename PatchChanges::const_iterator _patch_change_iter;
268                 ControlIterators                      _control_iters;
269                 ControlIterators::iterator            _control_iter;
270                 bool                                  _force_discrete;
271         };
272
273         const_iterator begin (
274                 Time                               t              = Time(),
275                 bool                               force_discrete = false,
276                 const std::set<Evoral::Parameter>& f              = std::set<Evoral::Parameter>(),
277                 const std::set<WeakNotePtr>*       active_notes   = NULL) const {
278                 return const_iterator (*this, t, force_discrete, f, active_notes);
279         }
280
281         const const_iterator& end() const { return _end_iter; }
282
283         // CONST iterator implementations (x3)
284         typename Notes::const_iterator note_lower_bound (Time t) const;
285         typename PatchChanges::const_iterator patch_change_lower_bound (Time t) const;
286         typename SysExes::const_iterator sysex_lower_bound (Time t) const;
287
288         // NON-CONST iterator implementations (x3)
289         typename Notes::iterator note_lower_bound (Time t);
290         typename PatchChanges::iterator patch_change_lower_bound (Time t);
291         typename SysExes::iterator sysex_lower_bound (Time t);
292
293         bool control_to_midi_event(boost::shared_ptr< Event<Time> >& ev,
294                                    const ControlIterator&            iter) const;
295
296         bool edited() const      { return _edited; }
297         void set_edited(bool yn) { _edited = yn; }
298
299         bool overlaps (const NotePtr& ev,
300                        const NotePtr& ignore_this_note) const;
301         bool contains (const NotePtr& ev) const;
302
303         bool add_note_unlocked (const NotePtr note, void* arg = 0);
304         void remove_note_unlocked(const constNotePtr note);
305
306         void add_patch_change_unlocked (const PatchChangePtr);
307         void remove_patch_change_unlocked (const constPatchChangePtr);
308
309         void add_sysex_unlocked (const SysExPtr);
310         void remove_sysex_unlocked (const SysExPtr);
311
312         uint8_t lowest_note()  const { return _lowest_note; }
313         uint8_t highest_note() const { return _highest_note; }
314
315
316 protected:
317         bool                   _edited;
318         bool                   _overlapping_pitches_accepted;
319         OverlapPitchResolution _overlap_pitch_resolution;
320         mutable Glib::Threads::RWLock   _lock;
321         bool                   _writing;
322
323         virtual int resolve_overlaps_unlocked (const NotePtr, void* /* arg */ = 0) {
324                 return 0;
325         }
326
327         typedef std::multiset<NotePtr, NoteNumberComparator>  Pitches;
328         inline       Pitches& pitches(uint8_t chan)       { return _pitches[chan&0xf]; }
329         inline const Pitches& pitches(uint8_t chan) const { return _pitches[chan&0xf]; }
330
331         virtual void control_list_marked_dirty ();
332
333 private:
334         friend class const_iterator;
335
336         bool overlaps_unlocked (const NotePtr& ev, const NotePtr& ignore_this_note) const;
337         bool contains_unlocked (const NotePtr& ev) const;
338
339         void append_note_on_unlocked(const MIDIEvent<Time>& event, Evoral::event_id_t);
340         void append_note_off_unlocked(const MIDIEvent<Time>& event);
341         void append_control_unlocked(const Parameter& param, Time time, double value, Evoral::event_id_t);
342         void append_sysex_unlocked(const MIDIEvent<Time>& ev, Evoral::event_id_t);
343         void append_patch_change_unlocked(const PatchChange<Time>&, Evoral::event_id_t);
344
345         void get_notes_by_pitch (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;
346         void get_notes_by_velocity (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;
347
348         const TypeMap& _type_map;
349
350         Notes        _notes;       // notes indexed by time
351         Pitches      _pitches[16]; // notes indexed by channel+pitch
352         SysExes      _sysexes;
353         PatchChanges _patch_changes;
354
355         typedef std::multiset<NotePtr, EarlierNoteComparator> WriteNotes;
356         WriteNotes _write_notes[16];
357
358         /** Current bank number on each channel so that we know what
359          *  to put in PatchChange events when program changes are
360          *  seen.
361          */
362         int _bank[16];
363
364         const   const_iterator _end_iter;
365         bool                   _percussive;
366
367         uint8_t _lowest_note;
368         uint8_t _highest_note;
369 };
370
371
372 } // namespace Evoral
373
374 template<typename Time> /*LIBEVORAL_API*/ std::ostream& operator<<(std::ostream& o, const Evoral::Sequence<Time>& s) { s.dump (o); return o; }
375
376
377 #endif // EVORAL_SEQUENCE_HPP
378