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