1 /*
2  * Copyright (C) 2009-2018 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2010-2012 Carl Hetherington <carl@carlh.net>
4  * Copyright (C) 2010-2012 David Robillard <d@drobilla.net>
5  * Copyright (C) 2015-2018 Robin Gareus <robin@gareus.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #ifndef __ardour_session_event_h__
23 #define __ardour_session_event_h__
24 
25 #include <list>
26 #include <boost/function.hpp>
27 #include <boost/shared_ptr.hpp>
28 #include <boost/weak_ptr.hpp>
29 
30 #include "pbd/pool.h"
31 #include "pbd/ringbuffer.h"
32 #include "pbd/event_loop.h"
33 
34 #include "ardour/libardour_visibility.h"
35 #include "ardour/types.h"
36 
37 namespace ARDOUR {
38 
39 class TransportMaster;
40 class Region;
41 class Track;
42 
43 class LIBARDOUR_API SessionEvent {
44 public:
45 	enum Type {
46 		SetTransportSpeed,
47 		Locate,
48 		LocateRoll,
49 		LocateRollLocate,
50 		SetLoop,
51 		PunchIn,
52 		PunchOut,
53 		RangeStop,
54 		RangeLocate,
55 		Overwrite,
56 		OverwriteAll,
57 		Audition,
58 		SetPlayAudioRange,
59 		CancelPlayAudioRange,
60 		RealTimeOperation,
61 		AdjustPlaybackBuffering,
62 		AdjustCaptureBuffering,
63 		SetTimecodeTransmission,
64 		Skip,
65 		SetTransportMaster,
66 		StartRoll,
67 		EndRoll,
68 
69 		/* only one of each of these events can be queued at any one time */
70 
71 		AutoLoop,
72 	};
73 
74 	enum Action {
75 		Add,
76 		Remove,
77 		Replace,
78 		Clear
79 	};
80 
81 	Type       type;
82 	Action     action;
83 	samplepos_t action_sample;
84 	samplepos_t target_sample;
85 	double     speed;
86 
87 	union {
88 		bool             yes_or_no;
89 		samplepos_t      target2_sample;
90 		OverwriteReason  overwrite;
91 	};
92 
93 	boost::weak_ptr<Track> track;
94 
95 	union {
96 		bool second_yes_or_no;
97 		double control_value;
98 		LocateTransportDisposition locate_transport_disposition;
99 	};
100 
101 	union {
102 		bool third_yes_or_no;
103 	};
104 
105 	/* 5 members to handle a multi-group event handled in RT context */
106 
107 	typedef boost::function<void (SessionEvent*)> RTeventCallback;
108 
109 	boost::shared_ptr<ControlList> controls; /* apply to */
110 	boost::shared_ptr<RouteList> routes;     /* apply to */
111 	boost::function<void (void)> rt_slot;    /* what to call in RT context */
112 	RTeventCallback              rt_return;  /* called after rt_slot, with this event as an argument */
113 	PBD::EventLoop*              event_loop;
114 
115 	std::list<AudioRange> audio_range;
116 	std::list<MusicRange> music_range;
117 
118 	boost::shared_ptr<Region> region;
119 	boost::shared_ptr<TransportMaster> transport_master;
120 
121 	SessionEvent (Type t, Action a, samplepos_t when, samplepos_t where, double spd, bool yn = false, bool yn2 = false, bool yn3 = false);
122 
set_track(boost::shared_ptr<Track> t)123 	void set_track (boost::shared_ptr<Track> t) {
124 		track = t;
125 	}
126 
before(const SessionEvent & other)127 	bool before (const SessionEvent& other) const {
128 		return action_sample < other.action_sample;
129 	}
130 
after(const SessionEvent & other)131 	bool after (const SessionEvent& other) const {
132 		return action_sample > other.action_sample;
133 	}
134 
compare(const SessionEvent * e1,const SessionEvent * e2)135 	static bool compare (const SessionEvent *e1, const SessionEvent *e2) {
136 		return e1->before (*e2);
137 	}
138 
139 	void* operator new (size_t);
140 	void  operator delete (void *ptr, size_t /*size*/);
141 
142 	static const samplepos_t Immediate = -1;
143 
144 	static bool has_per_thread_pool ();
145 	static void create_per_thread_pool (const std::string& n, uint32_t nitems);
146 	static void init_event_pool ();
147 
event_pool()148 	CrossThreadPool* event_pool() const { return own_pool; }
149 
150 private:
151 	static PerThreadPool* pool;
152 	CrossThreadPool* own_pool;
153 
154 	friend class Butler;
155 };
156 
157 class SessionEventManager {
158 public:
SessionEventManager()159 	SessionEventManager () : pending_events (2048),
160 	                         auto_loop_event(0), punch_out_event(0), punch_in_event(0) {}
~SessionEventManager()161 	virtual ~SessionEventManager() {}
162 
163 	virtual void queue_event (SessionEvent *ev) = 0;
164 	void clear_events (SessionEvent::Type type);
165 	void clear_events (SessionEvent::Type type, boost::function<void (void)> after);
166 
167 protected:
168 	PBD::RingBuffer<SessionEvent*> pending_events;
169 	typedef std::list<SessionEvent *> Events;
170 	Events           events;
171 	Events           immediate_events;
172 	Events::iterator next_event;
173 
174 	Glib::Threads::Mutex rb_write_lock;
175 
176 	/* there can only ever be one of each of these */
177 
178 	SessionEvent *auto_loop_event;
179 	SessionEvent *punch_out_event;
180 	SessionEvent *punch_in_event;
181 
182 	void dump_events () const;
183 	void merge_event (SessionEvent*);
184 	void replace_event (SessionEvent::Type, samplepos_t action_sample, samplepos_t target = 0);
185 	bool _replace_event (SessionEvent*);
186 	bool _remove_event (SessionEvent *);
187 	void _clear_event_type (SessionEvent::Type);
188 
189 	void add_event (samplepos_t action_sample, SessionEvent::Type type, samplepos_t target_sample = 0);
190 	void remove_event (samplepos_t sample, SessionEvent::Type type);
191 
192 	virtual void process_event(SessionEvent*) = 0;
193 	virtual void set_next_event () = 0;
194 };
195 
196 } /* namespace */
197 
198 #endif /* __ardour_session_event_h__ */
199