change default overlapping note strategy to "relax" (i.e. do nothing); fix crash...
[ardour2.git] / libs / evoral / evoral / Sequence.hpp
blob922b7594d4e42f21d6b6c768231d1da674dcd8a5
1 /* This file is part of Evoral.
2 * Copyright (C) 2008 David Robillard <http://drobilla.net>
3 * Copyright (C) 2000-2008 Paul Davis
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.
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.
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
19 #ifndef EVORAL_SEQUENCE_HPP
20 #define EVORAL_SEQUENCE_HPP
22 #include <vector>
23 #include <queue>
24 #include <set>
25 #include <list>
26 #include <utility>
27 #include <boost/shared_ptr.hpp>
28 #include <glibmm/thread.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"
36 namespace Evoral {
38 class TypeMap;
39 template<typename Time> class EventSink;
40 template<typename Time> class Note;
41 template<typename Time> class Event;
43 /** An iterator over (the x axis of) a 2-d double coordinate space.
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)
53 boost::shared_ptr<const ControlList> list;
54 double x;
55 double y;
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);
68 protected:
69 struct WriteLockImpl {
70 WriteLockImpl(Glib::RWLock& s, Glib::Mutex& c)
71 : sequence_lock(new Glib::RWLock::WriterLock(s))
72 , control_lock(new Glib::Mutex::Lock(c))
73 { }
74 ~WriteLockImpl() {
75 delete sequence_lock;
76 delete control_lock;
78 Glib::RWLock::WriterLock* sequence_lock;
79 Glib::Mutex::Lock* control_lock;
82 public:
84 typedef typename boost::shared_ptr<Evoral::Note<Time> > NotePtr;
85 typedef typename boost::shared_ptr<const Evoral::Note<Time> > constNotePtr;
87 typedef boost::shared_ptr<Glib::RWLock::ReaderLock> ReadLock;
88 typedef boost::shared_ptr<WriteLockImpl> WriteLock;
90 virtual ReadLock read_lock() const { return ReadLock(new Glib::RWLock::ReaderLock(_lock)); }
91 virtual WriteLock write_lock() { return WriteLock(new WriteLockImpl(_lock, _control_lock)); }
93 void clear();
95 bool percussive() const { return _percussive; }
96 void set_percussive(bool p) { _percussive = p; }
98 void start_write();
99 bool writing() const { return _writing; }
100 void end_write(bool delete_stuck=false);
102 void append(const Event<Time>& ev, Evoral::event_id_t evid);
104 inline size_t n_notes() const { return _notes.size(); }
105 inline bool empty() const { return _notes.empty() && _sysexes.empty() && _patch_changes.empty() && ControlSet::controls_empty(); }
107 inline static bool note_time_comparator(const boost::shared_ptr< const Note<Time> >& a,
108 const boost::shared_ptr< const Note<Time> >& b) {
109 return a->time() < b->time();
112 struct NoteNumberComparator {
113 inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
114 const boost::shared_ptr< const Note<Time> > b) const {
115 return a->note() < b->note();
119 struct EarlierNoteComparator {
120 inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
121 const boost::shared_ptr< const Note<Time> > b) const {
122 return a->time() < b->time();
126 struct LaterNoteComparator {
127 typedef const Note<Time>* value_type;
128 inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
129 const boost::shared_ptr< const Note<Time> > b) const {
130 return a->time() > b->time();
134 struct LaterNoteEndComparator {
135 typedef const Note<Time>* value_type;
136 inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
137 const boost::shared_ptr< const Note<Time> > b) const {
138 return a->end_time() > b->end_time();
142 typedef std::multiset<NotePtr, EarlierNoteComparator> Notes;
143 inline Notes& notes() { return _notes; }
144 inline const Notes& notes() const { return _notes; }
146 enum NoteOperator {
147 PitchEqual,
148 PitchLessThan,
149 PitchLessThanOrEqual,
150 PitchGreater,
151 PitchGreaterThanOrEqual,
152 VelocityEqual,
153 VelocityLessThan,
154 VelocityLessThanOrEqual,
155 VelocityGreater,
156 VelocityGreaterThanOrEqual,
159 void get_notes (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;
161 void remove_overlapping_notes ();
162 void trim_overlapping_notes ();
163 void remove_duplicate_notes ();
165 enum OverlapPitchResolution {
166 LastOnFirstOff,
167 FirstOnFirstOff
170 bool overlapping_pitches_accepted() const { return _overlapping_pitches_accepted; }
171 void overlapping_pitches_accepted(bool yn) { _overlapping_pitches_accepted = yn; }
172 OverlapPitchResolution overlap_pitch_resolution() const { return _overlap_pitch_resolution; }
173 void set_overlap_pitch_resolution(OverlapPitchResolution opr);
175 void set_notes (const Sequence<Time>::Notes& n);
177 typedef std::vector< boost::shared_ptr< Event<Time> > > SysExes;
178 inline SysExes& sysexes() { return _sysexes; }
179 inline const SysExes& sysexes() const { return _sysexes; }
181 typedef boost::shared_ptr<PatchChange<Time> > PatchChangePtr;
182 typedef boost::shared_ptr<const PatchChange<Time> > constPatchChangePtr;
184 struct EarlierPatchChangeComparator {
185 inline bool operator() (constPatchChangePtr a, constPatchChangePtr b) const {
186 return a->time() < b->time();
190 typedef std::multiset<PatchChangePtr, EarlierPatchChangeComparator> PatchChanges;
191 inline PatchChanges& patch_changes () { return _patch_changes; }
192 inline const PatchChanges& patch_changes () const { return _patch_changes; }
194 void dump (std::ostream&) const;
196 private:
197 typedef std::priority_queue<NotePtr, std::deque<NotePtr>, LaterNoteEndComparator> ActiveNotes;
198 public:
200 /** Read iterator */
201 class const_iterator {
202 public:
203 const_iterator();
204 const_iterator(const Sequence<Time>& seq, Time t, bool, std::set<Evoral::Parameter> const &);
205 ~const_iterator();
207 inline bool valid() const { return !_is_end && _event; }
208 //inline bool locked() const { return _locked; }
210 void invalidate();
212 const Event<Time>& operator*() const { return *_event; }
213 const boost::shared_ptr< Event<Time> > operator->() const { return _event; }
214 const boost::shared_ptr< Event<Time> > get_event_pointer() { return _event; }
216 const const_iterator& operator++(); // prefix only
218 bool operator==(const const_iterator& other) const;
219 bool operator!=(const const_iterator& other) const { return ! operator==(other); }
221 const_iterator& operator=(const const_iterator& other);
223 private:
224 friend class Sequence<Time>;
226 typedef std::vector<ControlIterator> ControlIterators;
227 enum MIDIMessageType { NIL, NOTE_ON, NOTE_OFF, CONTROL, SYSEX, PATCH_CHANGE };
229 const Sequence<Time>* _seq;
230 boost::shared_ptr< Event<Time> > _event;
231 mutable ActiveNotes _active_notes;
232 /** If the iterator is pointing at a patch change, this is the index of the
233 * sub-message within that change.
235 int _active_patch_change_message;
236 MIDIMessageType _type;
237 bool _is_end;
238 typename Sequence::ReadLock _lock;
239 typename Notes::const_iterator _note_iter;
240 typename SysExes::const_iterator _sysex_iter;
241 typename PatchChanges::const_iterator _patch_change_iter;
242 ControlIterators _control_iters;
243 ControlIterators::iterator _control_iter;
244 bool _force_discrete;
247 const_iterator begin (
248 Time t = 0,
249 bool force_discrete = false,
250 std::set<Evoral::Parameter> const & f = std::set<Evoral::Parameter> ()) const {
251 return const_iterator (*this, t, force_discrete, f);
254 const const_iterator& end() const { return _end_iter; }
256 typename Notes::const_iterator note_lower_bound (Time t) const;
257 typename PatchChanges::const_iterator patch_change_lower_bound (Time t) const;
259 bool control_to_midi_event(boost::shared_ptr< Event<Time> >& ev,
260 const ControlIterator& iter) const;
262 bool edited() const { return _edited; }
263 void set_edited(bool yn) { _edited = yn; }
265 bool overlaps (const NotePtr& ev,
266 const NotePtr& ignore_this_note) const;
267 bool contains (const NotePtr& ev) const;
269 bool add_note_unlocked (const NotePtr note, void* arg = 0);
270 void remove_note_unlocked(const constNotePtr note);
272 void add_patch_change_unlocked (const PatchChangePtr);
273 void remove_patch_change_unlocked (const constPatchChangePtr);
275 uint8_t lowest_note() const { return _lowest_note; }
276 uint8_t highest_note() const { return _highest_note; }
279 protected:
280 bool _edited;
281 bool _overlapping_pitches_accepted;
282 OverlapPitchResolution _overlap_pitch_resolution;
283 mutable Glib::RWLock _lock;
284 bool _writing;
286 virtual int resolve_overlaps_unlocked (const NotePtr, void* /* arg */ = 0) {
287 return 0;
290 typedef std::multiset<NotePtr, NoteNumberComparator> Pitches;
291 inline Pitches& pitches(uint8_t chan) { return _pitches[chan&0xf]; }
292 inline const Pitches& pitches(uint8_t chan) const { return _pitches[chan&0xf]; }
294 private:
295 friend class const_iterator;
297 bool overlaps_unlocked (const NotePtr& ev, const NotePtr& ignore_this_note) const;
298 bool contains_unlocked (const NotePtr& ev) const;
300 void append_note_on_unlocked (NotePtr, Evoral::event_id_t);
301 void append_note_off_unlocked(NotePtr);
302 void append_control_unlocked(const Parameter& param, Time time, double value, Evoral::event_id_t);
303 void append_sysex_unlocked(const MIDIEvent<Time>& ev, Evoral::event_id_t);
304 void append_patch_change_unlocked (const PatchChange<Time>&, Evoral::event_id_t);
306 void get_notes_by_pitch (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;
307 void get_notes_by_velocity (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;
309 void control_list_marked_dirty ();
311 const TypeMap& _type_map;
313 Notes _notes; // notes indexed by time
314 Pitches _pitches[16]; // notes indexed by channel+pitch
315 SysExes _sysexes;
316 PatchChanges _patch_changes;
318 typedef std::multiset<NotePtr, EarlierNoteComparator> WriteNotes;
319 WriteNotes _write_notes[16];
321 /** Current bank number on each channel so that we know what
322 * to put in PatchChange events when program changes are
323 * seen.
325 int _bank[16];
327 const const_iterator _end_iter;
328 bool _percussive;
330 uint8_t _lowest_note;
331 uint8_t _highest_note;
335 } // namespace Evoral
337 // template<typename Time> std::ostream& operator<<(std::ostream& o, const Evoral::Sequence<Time>& s) { s.dump (o); return o; }
339 #endif // EVORAL_SEQUENCE_HPP