summaryrefslogtreecommitdiff
path: root/libs/evoral/evoral/Sequence.hpp
blob: 22f75a74edc7469eac994e325ca2582d04731388 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/* This file is part of Evoral.
 * Copyright (C) 2008 Dave Robillard <http://drobilla.net>
 * Copyright (C) 2000-2008 Paul Davis
 * 
 * Evoral is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 * 
 * Evoral is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef EVORAL_SEQUENCE_HPP
#define EVORAL_SEQUENCE_HPP

#include <vector>
#include <queue>
#include <deque>
#include <map>
#include <utility>
#include <boost/shared_ptr.hpp>
#include <glibmm/thread.h>
#include "evoral/types.hpp"
#include "evoral/Note.hpp"
#include "evoral/Parameter.hpp"
#include "evoral/ControlSet.hpp"
#include "evoral/ControlList.hpp"

namespace Evoral {

class TypeMap;
template<typename Time> class EventSink;
template<typename Time> class Note;
template<typename Time> class Event;

/** An iterator over (the x axis of) a 2-d double coordinate space.
 */
class ControlIterator {
public:
	ControlIterator(boost::shared_ptr<const ControlList> al, double ax, double ay)
		: list(al)
		, x(ax)
		, y(ay)
	{}

	boost::shared_ptr<const ControlList> list;
	double x;
	double y;
};


/** This is a higher level view of events, with separate representations for
 * notes (instead of just unassociated note on/off events) and controller data.
 * Controller data is represented as a list of time-stamped float values. */
template<typename Time> 
class Sequence : virtual public ControlSet {
public:
	Sequence(const TypeMap& type_map, size_t size=0);
	
	bool read_locked() { return _read_iter.locked(); }

	void write_lock();
	void write_unlock();

	void read_lock()   const;
	void read_unlock() const;

	void clear();

	bool percussive() const     { return _percussive; }
	void set_percussive(bool p) { _percussive = p; }

	void start_write();
	bool writing() const { return _writing; }
	void end_write(bool delete_stuck=false);

	size_t read(EventSink<Time>& dst,
	            Time             start,
	            Time             length,
	            Time             stamp_offset) const;

	/** Resizes vector if necessary (NOT realtime safe) */
	void append(const Event<Time>& ev);
	
	inline const boost::shared_ptr< const Note<Time> > note_at(unsigned i) const { return _notes[i]; }
	inline const boost::shared_ptr< Note<Time> >       note_at(unsigned i)       { return _notes[i]; }

	inline size_t n_notes() const { return _notes.size(); }
	inline bool   empty()   const { return _notes.size() == 0 && ControlSet::empty(); }

	inline static bool note_time_comparator(const boost::shared_ptr< const Note<Time> >& a,
	                                        const boost::shared_ptr< const Note<Time> >& b) { 
		return a->time() < b->time();
	}

	struct LaterNoteEndComparator {
		typedef const Note<Time>* value_type;
		inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
		                       const boost::shared_ptr< const Note<Time> > b) const { 
			return a->end_time() > b->end_time();
		}
	};

	typedef std::vector< boost::shared_ptr< Note<Time> > > Notes;
	inline       Notes& notes()       { return _notes; }
	inline const Notes& notes() const { return _notes; }

	// useful for storing SysEx / Meta events
	typedef std::vector< boost::shared_ptr< Event<Time> > > SysExes;
	inline       SysExes& sysexes()       { return _sysexes; }
	inline const SysExes& sysexes() const { return _sysexes; }

	/** Read iterator */
	class const_iterator {
	public:
		const_iterator(const Sequence<Time>& seq, Time t);
		~const_iterator();

		inline bool valid() const { return !_is_end && _event; }
		inline bool locked() const { return _locked; }

		const Event<Time>& operator*()  const { return *_event;  }
		const boost::shared_ptr< Event<Time> > operator->() const  { return _event; }
		const boost::shared_ptr< Event<Time> > get_event_pointer() { return _event; }

		const const_iterator& operator++(); // prefix only
		bool operator==(const const_iterator& other) const;
		bool operator!=(const const_iterator& other) const { return ! operator==(other); }
		
		const_iterator& operator=(const const_iterator& other);

	private:
		friend class Sequence<Time>;
		
		enum MIDIMessageType { NIL, NOTE_ON, NOTE_OFF, CONTROL, SYSEX };

		const Sequence<Time>*            _seq;
		boost::shared_ptr< Event<Time> > _event;

		typedef std::priority_queue< boost::shared_ptr< Note<Time> >,
		                             std::deque< boost::shared_ptr< Note<Time> > >,
		                             LaterNoteEndComparator >
			ActiveNotes;
		
		mutable ActiveNotes _active_notes;

		typedef std::vector<ControlIterator> ControlIterators;

		bool                             _is_end;
		bool                             _locked;
		typename Notes::const_iterator   _note_iter;
		typename SysExes::const_iterator _sysex_iter;
		ControlIterators                 _control_iters;
		ControlIterators::iterator       _control_iter;
	};
	
	const_iterator        begin(Time t=0) const { return const_iterator(*this, t); }
	const const_iterator& end()        const { return _end_iter; }
	
	void         read_seek(Time t)    { _read_iter = begin(t); }
	Time         read_time() const    { return _read_iter.valid() ? _read_iter->time() : 0.0; }

	bool control_to_midi_event(boost::shared_ptr< Event<Time> >& ev,
	                           const ControlIterator&         iter) const;
	
	bool edited() const      { return _edited; }
	void set_edited(bool yn) { _edited = yn; }

#ifndef NDEBUG
	bool is_sorted() const;
#endif
	
	void add_note_unlocked(const boost::shared_ptr< Note<Time> > note);
	void remove_note_unlocked(const boost::shared_ptr< const Note<Time> > note);
	
	uint8_t lowest_note()  const { return _lowest_note; }
	uint8_t highest_note() const { return _highest_note; }
	
protected:
	mutable const_iterator _read_iter;
	bool                   _edited;

private:
	friend class const_iterator;
	
	void append_note_on_unlocked(uint8_t chan, Time time, uint8_t note, uint8_t velocity);
	void append_note_off_unlocked(uint8_t chan, Time time, uint8_t note);
	void append_control_unlocked(const Parameter& param, Time time, double value);
	void append_sysex_unlocked(const MIDIEvent<Time>& ev);

	mutable Glib::RWLock _lock;

	const TypeMap& _type_map;
	
	Notes _notes;
	
	SysExes _sysexes;
	
	typedef std::vector<size_t> WriteNotes;
	WriteNotes _write_notes[16];
	bool       _writing;
	
	typedef std::vector< boost::shared_ptr<const ControlList> > ControlLists;
	ControlLists _dirty_controls;

	const   const_iterator _end_iter;
	mutable Time           _next_read;
	bool                   _percussive;

	uint8_t _lowest_note;
	uint8_t _highest_note;

	typedef std::priority_queue<
			boost::shared_ptr< Note<Time> >, std::deque< boost::shared_ptr< Note<Time> > >,
			LaterNoteEndComparator>
		ActiveNotes;
};


} // namespace Evoral

#endif // EVORAL_SEQUENCE_HPP