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