1 /*
2  * Copyright (C) 2006-2016 David Robillard <d@drobilla.net>
3  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
4  * Copyright (C) 2007-2017 Paul Davis <paul@linuxaudiosystems.com>
5  * Copyright (C) 2013 John Emmas <john@creativepost.co.uk>
6  * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
7  * Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
8  * Copyright (C) 2015 André Nusser <andre.nusser@googlemail.com>
9  * Copyright (C) 2016-2017 Nick Mainsbridge <mainsbridge@gmail.com>
10  * Copyright (C) 2016-2017 Tim Mayberry <mojofunk@gmail.com>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25  */
26 
27 #ifndef __ardour_playlist_h__
28 #define __ardour_playlist_h__
29 
30 #include <boost/enable_shared_from_this.hpp>
31 #include <boost/optional.hpp>
32 #include <boost/shared_ptr.hpp>
33 #include <boost/utility.hpp>
34 #include <list>
35 #include <map>
36 #include <set>
37 #include <string>
38 
39 #include <sys/stat.h>
40 
41 #include <glib.h>
42 
43 #include "pbd/sequence_property.h"
44 #include "pbd/stateful.h"
45 #include "pbd/statefuldestructible.h"
46 #include "pbd/undo.h"
47 #include "pbd/g_atomic_compat.h"
48 
49 #include "evoral/Range.h"
50 
51 #include "ardour/ardour.h"
52 #include "ardour/data_type.h"
53 #include "ardour/region.h"
54 #include "ardour/session_object.h"
55 #include "ardour/thawlist.h"
56 
57 namespace ARDOUR {
58 
59 class Session;
60 class Playlist;
61 class Crossfade;
62 
63 namespace Properties {
64 	/* fake the type, since regions are handled by SequenceProperty which doesn't
65 	 * care about such things.
66 	 */
67 	LIBARDOUR_API extern PBD::PropertyDescriptor<bool> regions;
68 }
69 
70 class LIBARDOUR_API RegionListProperty : public PBD::SequenceProperty<std::list<boost::shared_ptr<Region> > >
71 {
72 public:
73 	RegionListProperty (Playlist&);
74 
75 	RegionListProperty*       clone () const;
76 	void                      get_content_as_xml (boost::shared_ptr<Region>, XMLNode&) const;
77 	boost::shared_ptr<Region> get_content_from_xml (XMLNode const&) const;
78 
79 private:
80 	RegionListProperty* create () const;
81 
82 	/* copy construction only by ourselves */
83 	RegionListProperty (RegionListProperty const& p);
84 
85 	friend class Playlist;
86 	/* we live and die with our playlist, no lifetime management needed */
87 	Playlist& _playlist;
88 };
89 
90 class LIBARDOUR_API Playlist : public SessionObject, public boost::enable_shared_from_this<Playlist>
91 {
92 public:
93 	static void make_property_quarks ();
94 
95 	Playlist (Session&, const XMLNode&, DataType type, bool hidden = false);
96 	Playlist (Session&, std::string name, DataType type, bool hidden = false);
97 	Playlist (boost::shared_ptr<const Playlist>, std::string name, bool hidden = false);
98 	Playlist (boost::shared_ptr<const Playlist>, samplepos_t start, samplecnt_t cnt, std::string name, bool hidden = false);
99 
100 	virtual ~Playlist ();
101 
102 	void update (const RegionListProperty::ChangeRecord&);
103 	void clear_owned_changes ();
104 	void rdiff (std::vector<Command*>&) const;
105 
106 	boost::shared_ptr<Region> region_by_id (const PBD::ID&) const;
107 
108 	uint32_t max_source_level () const;
109 
110 	bool set_name (const std::string& str);
111 	void set_region_ownership ();
112 
pgroup_id()113 	std::string pgroup_id()                 { return _pgroup_id; }
set_pgroup_id(std::string pgid)114 	void set_pgroup_id(std::string pgid)    { _pgroup_id = pgid; PropertyChanged (Properties::name); }
115 
116 	virtual void clear (bool with_signals = true);
117 	virtual void dump () const;
118 
119 	void use ();
120 	void release ();
121 
122 	bool            empty () const;
used()123 	bool            used () const          { return _refcnt != 0; }
sort_id()124 	int             sort_id () const       { return _sort_id; }
frozen()125 	bool            frozen () const        { return _frozen; }
data_type()126 	const DataType& data_type () const     { return _type; }
hidden()127 	bool            hidden () const        { return _hidden; }
shared()128 	bool            shared () const        { return !_shared_with_ids.empty (); }
get_edit_mode()129 	EditMode        get_edit_mode () const { return _edit_mode; }
130 
131 	void set_frozen (bool yn);
132 	void set_edit_mode (EditMode);
133 
134 	void AddToSoloSelectedList (const Region*);
135 	void RemoveFromSoloSelectedList (const Region*);
136 	bool SoloSelectedListIncludes (const Region*);
137 	bool SoloSelectedActive ();
138 
139 	void share_with (const PBD::ID&);
140 	void unshare_with (const PBD::ID&);
141 	bool shared_with (const PBD::ID&) const;
142 	void reset_shares ();
143 
144 	uint32_t                            n_regions () const;
145 	bool                                all_regions_empty () const;
146 	std::pair<samplepos_t, samplepos_t> get_extent () const;
147 	std::pair<samplepos_t, samplepos_t> get_extent_with_endspace () const;
148 	layer_t                             top_layer () const;
149 
150 	/* Editing operations */
151 
152 	void add_region (boost::shared_ptr<Region>, samplepos_t position, float times = 1, bool auto_partition = false, int32_t sub_num = 0, double quarter_note = 0.0, bool for_music = false);
153 	void remove_region (boost::shared_ptr<Region>);
154 	void get_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
155 	void replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, samplepos_t pos);
156 	void split_region (boost::shared_ptr<Region>, const MusicSample& position);
157 	void split (const MusicSample& at);
158 	void shift (samplepos_t at, sampleoffset_t distance, bool move_intersected, bool ignore_music_glue);
159 	void partition (samplepos_t start, samplepos_t end, bool cut = false);
160 	void duplicate (boost::shared_ptr<Region>, samplepos_t position, float times);
161 	void duplicate (boost::shared_ptr<Region>, samplepos_t position, samplecnt_t gap, float times);
162 	void duplicate_until (boost::shared_ptr<Region>, samplepos_t position, samplecnt_t gap, samplepos_t end);
163 	void duplicate_range (AudioRange&, float times);
164 	void duplicate_ranges (std::list<AudioRange>&, float times);
165 	void nudge_after (samplepos_t start, samplecnt_t distance, bool forwards);
166 	void fade_range (std::list<AudioRange>&);
167 	void remove_gaps (samplepos_t gap_threshold, samplepos_t leave_gap, boost::function<void (samplepos_t, samplecnt_t)> gap_callback);
168 
169 	boost::shared_ptr<Region> combine (const RegionList&);
170 	void                      uncombine (boost::shared_ptr<Region>);
171 
172 	void shuffle (boost::shared_ptr<Region>, int dir);
173 	void ripple (samplepos_t at, samplecnt_t distance, RegionList* exclude);
ripple(samplepos_t at,samplecnt_t distance,boost::shared_ptr<Region> exclude)174 	void ripple (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude)
175 	{
176 		RegionList el;
177 		if (exclude) {
178 			el.push_back (exclude);
179 		}
180 		ripple (at, distance, &el);
181 	}
182 
183 	void update_after_tempo_map_change ();
184 
185 	boost::shared_ptr<Playlist> cut (std::list<AudioRange>&, bool result_is_hidden = true);
186 	boost::shared_ptr<Playlist> copy (std::list<AudioRange>&, bool result_is_hidden = true);
187 	int                         paste (boost::shared_ptr<Playlist>, samplepos_t position, float times, const int32_t sub_num);
188 
region_list_property()189 	const RegionListProperty& region_list_property () const
190 	{
191 		return regions;
192 	}
193 
194 	boost::shared_ptr<RegionList> region_list ();
195 
196 	boost::shared_ptr<RegionList> regions_at (samplepos_t sample);
197 	uint32_t                      count_regions_at (samplepos_t) const;
198 
199 	/** @param start Range start.
200 	 *  @param end Range end.
201 	 *  @return regions which have some part within this range.
202 	 */
203 	boost::shared_ptr<RegionList> regions_touched (samplepos_t start, samplepos_t end);
204 	boost::shared_ptr<RegionList> regions_with_start_within (Evoral::Range<samplepos_t>);
205 	boost::shared_ptr<RegionList> regions_with_end_within (Evoral::Range<samplepos_t>);
206 	uint32_t                      region_use_count (boost::shared_ptr<Region>) const;
207 	boost::shared_ptr<Region>     find_region (const PBD::ID&) const;
208 	boost::shared_ptr<Region>     top_region_at (samplepos_t sample);
209 	boost::shared_ptr<Region>     top_unmuted_region_at (samplepos_t sample);
210 	boost::shared_ptr<Region>     find_next_region (samplepos_t sample, RegionPoint point, int dir);
211 	samplepos_t                   find_next_region_boundary (samplepos_t sample, int dir);
212 	bool                          region_is_shuffle_constrained (boost::shared_ptr<Region>);
213 	bool                          has_region_at (samplepos_t const) const;
214 
215 	bool uses_source (boost::shared_ptr<const Source> src, bool shallow = false) const;
216 	void deep_sources (std::set<boost::shared_ptr<Source> >&) const;
217 
218 	samplepos_t find_next_transient (samplepos_t position, int dir);
219 
220 	void foreach_region (boost::function<void(boost::shared_ptr<Region>)>);
221 
222 	XMLNode&    get_state ();
223 	virtual int set_state (const XMLNode&, int version);
224 	XMLNode&    get_template ();
225 
226 	PBD::Signal1<void, bool>                     InUse;
227 	PBD::Signal0<void>                           ContentsChanged;
228 	PBD::Signal1<void, boost::weak_ptr<Region> > RegionAdded;
229 	PBD::Signal1<void, boost::weak_ptr<Region> > RegionRemoved;
230 	PBD::Signal0<void>                           NameChanged;
231 	PBD::Signal0<void>                           LayeringChanged;
232 
233 	/** Emitted when regions have moved (not when regions have only been trimmed) */
234 	PBD::Signal2<void, std::list<Evoral::RangeMove<samplepos_t> > const&, bool> RangesMoved;
235 
236 	/** Emitted when regions are extended; the ranges passed are the new extra time ranges
237 	    that these regions now occupy.
238 	*/
239 	PBD::Signal1<void, std::list<Evoral::Range<samplepos_t> > const&> RegionsExtended;
240 
241 	static std::string bump_name (std::string old_name, Session&);
242 
243 	void freeze ();
244 	void thaw (bool from_undo = false);
245 
246 	void raise_region (boost::shared_ptr<Region>);
247 	void lower_region (boost::shared_ptr<Region>);
248 	void raise_region_to_top (boost::shared_ptr<Region>);
249 	void lower_region_to_bottom (boost::shared_ptr<Region>);
250 
251 	void set_orig_track_id (const PBD::ID& did);
get_orig_track_id()252 	const PBD::ID& get_orig_track_id () const { return _orig_track_id; }
253 
254 	/* destructive editing */
255 
256 	virtual bool destroy_region (boost::shared_ptr<Region>) = 0;
257 
258 	void sync_all_regions_with_regions ();
259 
260 	/* special case function used by UI selection objects, which have playlists that actually own the regions
261 	   within them.
262 	*/
263 
264 	void drop_regions ();
265 
find_crossfade(const PBD::ID &)266 	virtual boost::shared_ptr<Crossfade> find_crossfade (const PBD::ID&) const
267 	{
268 		return boost::shared_ptr<Crossfade> ();
269 	}
270 
271 	samplepos_t find_next_top_layer_position (samplepos_t) const;
combine_ops()272 	uint32_t    combine_ops () const
273 	{
274 		return _combine_ops;
275 	}
276 
277 	void set_layer (boost::shared_ptr<Region>, double);
278 
279 	void set_capture_insertion_in_progress (bool yn);
280 
281 protected:
282 	friend class Session;
283 
284 protected:
285 
286 	class RegionReadLock : public Glib::Threads::RWLock::ReaderLock
287 	{
288 	public:
RegionReadLock(Playlist * pl)289 		RegionReadLock (Playlist* pl)
290 		    : Glib::Threads::RWLock::ReaderLock (pl->region_lock)
291 		{
292 		}
~RegionReadLock()293 		~RegionReadLock () {}
294 	};
295 
296 	class RegionWriteLock : public Glib::Threads::RWLock::WriterLock
297 	{
298 	public:
299 		RegionWriteLock (Playlist* pl, bool do_block_notify = true)
300 		    : Glib::Threads::RWLock::WriterLock (pl->region_lock)
301 		    , playlist (pl)
302 		    , block_notify (do_block_notify)
303 		{
304 			if (block_notify) {
305 				playlist->delay_notifications ();
306 			}
307 		}
308 
~RegionWriteLock()309 		~RegionWriteLock ()
310 		{
311 			Glib::Threads::RWLock::WriterLock::release ();
312 			thawlist.release ();
313 			if (block_notify) {
314 				playlist->release_notifications ();
315 			}
316 		}
317 
318 		ThawList  thawlist;
319 		Playlist* playlist;
320 		bool      block_notify;
321 	};
322 
323 	RegionListProperty                   regions;     /* the current list of regions in the playlist */
324 	std::set<boost::shared_ptr<Region> > all_regions; /* all regions ever added to this playlist */
325 	PBD::ScopedConnectionList            region_state_changed_connections;
326 	PBD::ScopedConnectionList            region_drop_references_connections;
327 	DataType                             _type;
328 	uint32_t                             _sort_id;
329 	mutable GATOMIC_QUAL gint            block_notifications;
330 	mutable GATOMIC_QUAL gint            ignore_state_changes;
331 	std::set<boost::shared_ptr<Region> > pending_adds;
332 	std::set<boost::shared_ptr<Region> > pending_removes;
333 	RegionList                           pending_bounds;
334 	bool                                 pending_contents_change;
335 	bool                                 pending_layering;
336 
337 	std::set<const Region*> _soloSelectedRegions;
338 
339 	/** Movements of time ranges caused by region moves; note that
340 	 *  region trims are not included in this list; it is used to
341 	 *  do automation-follows-regions.
342 	 */
343 	std::list<Evoral::RangeMove<samplepos_t> > pending_range_moves;
344 
345 	/** Extra sections added to regions during trims */
346 	std::list<Evoral::Range<samplepos_t> > pending_region_extensions;
347 
348 	uint32_t           in_set_state;
349 	bool               in_undo;
350 	bool               first_set_state;
351 	bool               _hidden;
352 	bool               _splicing;
353 	bool               _rippling;
354 	bool               _shuffling;
355 	bool               _nudging;
356 	uint32_t           _refcnt;
357 	EditMode           _edit_mode;
358 	bool               in_flush;
359 	bool               in_partition;
360 	bool               _frozen;
361 	bool               _capture_insertion_underway;
362 	uint32_t           subcnt;
363 	PBD::ID            _orig_track_id;
364 	uint32_t           _combine_ops;
365 	std::list<PBD::ID> _shared_with_ids;
366 
367 	void init (bool hide);
368 
holding_state()369 	bool holding_state () const
370 	{
371 		return g_atomic_int_get (&block_notifications) != 0 ||
372 		       g_atomic_int_get (&ignore_state_changes) != 0;
373 	}
374 
375 	void         delay_notifications ();
376 	void         release_notifications (bool from_undo = false);
377 	virtual void flush_notifications (bool from_undo = false);
378 	void         clear_pending ();
379 
380 	void _set_sort_id ();
381 
382 	boost::shared_ptr<RegionList> regions_touched_locked (samplepos_t start, samplepos_t end);
383 
384 	void notify_region_removed (boost::shared_ptr<Region>);
385 	void notify_region_added (boost::shared_ptr<Region>);
386 	void notify_layering_changed ();
387 	void notify_contents_changed ();
388 	void notify_state_changed (const PBD::PropertyChange&);
389 	void notify_region_moved (boost::shared_ptr<Region>);
390 	void notify_region_start_trimmed (boost::shared_ptr<Region>);
391 	void notify_region_end_trimmed (boost::shared_ptr<Region>);
392 
393 	void mark_session_dirty ();
394 
395 	void         region_changed_proxy (const PBD::PropertyChange&, boost::weak_ptr<Region>);
396 	virtual bool region_changed (const PBD::PropertyChange&, boost::shared_ptr<Region>);
397 
398 	void region_bounds_changed (const PBD::PropertyChange&, boost::shared_ptr<Region>);
399 	void region_deleted (boost::shared_ptr<Region>);
400 
401 	void sort_regions ();
402 
403 	void possibly_splice (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude = boost::shared_ptr<Region> ());
404 	void possibly_splice_unlocked (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude, ThawList& thawlist);
405 
406 	void splice_locked (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude);
407 	void splice_unlocked (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude, ThawList& thawlist);
408 
409 	void ripple_locked (samplepos_t at, samplecnt_t distance, RegionList* exclude);
410 	void ripple_unlocked (samplepos_t at, samplecnt_t distance, RegionList* exclude, ThawList& thawlist, bool notify = true);
411 
remove_dependents(boost::shared_ptr<Region>)412 	virtual void remove_dependents (boost::shared_ptr<Region> /*region*/) {}
region_going_away(boost::weak_ptr<Region>)413 	virtual void region_going_away (boost::weak_ptr<Region> /*region*/) {}
414 
415 	virtual XMLNode& state (bool);
416 
417 	bool add_region_internal (boost::shared_ptr<Region>, samplepos_t position, ThawList& thawlist, int32_t sub_num = 0, double quarter_note = 0.0, bool for_music = false);
418 
419 	int  remove_region_internal (boost::shared_ptr<Region>, ThawList& thawlist);
420 	void copy_regions (RegionList&) const;
421 	void partition_internal (samplepos_t start, samplepos_t end, bool cutting, ThawList& thawlist);
422 
423 	std::pair<samplepos_t, samplepos_t> _get_extent () const;
424 
425 	boost::shared_ptr<Playlist> cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf) (samplepos_t, samplecnt_t, bool),
426 	                                      std::list<AudioRange>& ranges, bool result_is_hidden);
427 	boost::shared_ptr<Playlist> cut (samplepos_t start, samplecnt_t cnt, bool result_is_hidden);
428 	boost::shared_ptr<Playlist> copy (samplepos_t start, samplecnt_t cnt, bool result_is_hidden);
429 
430 	void relayer ();
431 
432 	void begin_undo ();
433 	void end_undo ();
434 
435 	virtual void _split_region (boost::shared_ptr<Region>, const MusicSample& position, ThawList& thawlist);
436 
437 	typedef std::pair<boost::shared_ptr<Region>, boost::shared_ptr<Region> > TwoRegions;
438 
439 	/* this is called before we create a new compound region */
pre_combine(std::vector<boost::shared_ptr<Region>> &)440 	virtual void pre_combine (std::vector<boost::shared_ptr<Region> >&) {}
441 	/* this is called before we create a new compound region */
post_combine(std::vector<boost::shared_ptr<Region>> &,boost::shared_ptr<Region>)442 	virtual void post_combine (std::vector<boost::shared_ptr<Region> >&, boost::shared_ptr<Region>) {}
443 	/* this is called before we remove a compound region and replace it
444 	 * with its constituent regions
445 	 */
pre_uncombine(std::vector<boost::shared_ptr<Region>> &,boost::shared_ptr<Region>)446 	virtual void pre_uncombine (std::vector<boost::shared_ptr<Region> >&, boost::shared_ptr<Region>) {}
447 
448 private:
449 	friend class RegionReadLock;
450 	friend class RegionWriteLock;
451 
452 	mutable Glib::Threads::RWLock region_lock;
453 
454 private:
455 	void freeze_locked ();
456 	void setup_layering_indices (RegionList const&);
457 	void coalesce_and_check_crossfades (std::list<Evoral::Range<samplepos_t> >);
458 
459 	boost::shared_ptr<RegionList> find_regions_at (samplepos_t);
460 
461 	mutable boost::optional<std::pair<samplepos_t, samplepos_t> > _cached_extent;
462 
463 	samplepos_t _end_space; // this is used when we are pasting a range with extra space at the end
464 	bool        _playlist_shift_active;
465 
466 	std::string _pgroup_id; // when we make multiple playlists in one action, they will share the same pgroup_id
467 };
468 
469 } /* namespace ARDOUR */
470 
471 #endif /* __ardour_playlist_h__ */
472