summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour/playlist.h
blob: aa661b8588401a43604d5c236fd1a03458b3b7bb (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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
/*
    Copyright (C) 2000 Paul Davis

    This program 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.

    This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifndef __ardour_playlist_h__
#define __ardour_playlist_h__

#include <string>
#include <set>
#include <map>
#include <list>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/utility.hpp>

#include <sys/stat.h>

#include <glib.h>

#include <sigc++/signal.h>

#include "pbd/undo.h"
#include "pbd/stateful.h"
#include "pbd/statefuldestructible.h"

#include "evoral/types.hpp"

#include "ardour/ardour.h"
#include "ardour/session_object.h"
#include "ardour/crossfade_compare.h"
#include "ardour/location.h"
#include "ardour/data_type.h"

namespace ARDOUR  {

class Session;
class Region;

class Playlist : public SessionObject,
                 public boost::noncopyable,
                 public boost::enable_shared_from_this<Playlist> {
  public:
	typedef std::list<boost::shared_ptr<Region> >    RegionList;

	Playlist (Session&, const XMLNode&, DataType type, bool hidden = false);
	Playlist (Session&, std::string name, DataType type, bool hidden = false);
	Playlist (boost::shared_ptr<const Playlist>, std::string name, bool hidden = false);
	Playlist (boost::shared_ptr<const Playlist>, nframes_t start, nframes_t cnt, std::string name, bool hidden = false);

	virtual ~Playlist ();

	void set_region_ownership ();

	virtual void clear (bool with_signals=true);
	virtual void dump () const;

	void use();
	void release();
	bool used () const { return _refcnt != 0; }

	bool set_name (const std::string& str);

	const DataType& data_type() const { return _type; }

	bool frozen() const { return _frozen; }
	void set_frozen (bool yn);

	bool hidden() const { return _hidden; }
	bool empty() const;
	uint32_t n_regions() const;
	nframes_t get_maximum_extent () const;
	layer_t top_layer() const;

	EditMode get_edit_mode() const { return _edit_mode; }
	void set_edit_mode (EditMode);

	/* Editing operations */

	void add_region (boost::shared_ptr<Region>, nframes_t position, float times = 1, bool auto_partition = false);
	void remove_region (boost::shared_ptr<Region>);
	void get_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
	void get_region_list_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
	void replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, nframes_t pos);
	void split_region (boost::shared_ptr<Region>, nframes_t position);
	void split (nframes64_t at);
	void shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue);
	void partition (nframes_t start, nframes_t end, bool cut = false);
	void duplicate (boost::shared_ptr<Region>, nframes_t position, float times);
	void nudge_after (nframes_t start, nframes_t distance, bool forwards);
	void shuffle (boost::shared_ptr<Region>, int dir);
	void update_after_tempo_map_change ();

	boost::shared_ptr<Playlist> cut  (std::list<AudioRange>&, bool result_is_hidden = true);
	boost::shared_ptr<Playlist> copy (std::list<AudioRange>&, bool result_is_hidden = true);
	int                         paste (boost::shared_ptr<Playlist>, nframes_t position, float times);

	RegionList*                regions_at (nframes_t frame);
	RegionList*                regions_touched (nframes_t start, nframes_t end);
	RegionList*                regions_to_read (nframes_t start, nframes_t end);
	boost::shared_ptr<Region>  find_region (const PBD::ID&) const;
	boost::shared_ptr<Region>  top_region_at (nframes_t frame);
	boost::shared_ptr<Region>  top_unmuted_region_at (nframes_t frame);
	boost::shared_ptr<Region>  find_next_region (nframes_t frame, RegionPoint point, int dir);
	nframes64_t                find_next_region_boundary (nframes64_t frame, int dir);
	bool                       region_is_shuffle_constrained (boost::shared_ptr<Region>);

	nframes64_t find_next_transient (nframes64_t position, int dir);

	void foreach_region (sigc::slot<void, boost::shared_ptr<Region> >);

	XMLNode& get_state ();
	int set_state (const XMLNode&, int version);
	XMLNode& get_template ();

	sigc::signal<void,bool> InUse;
	sigc::signal<void>      Modified;
	sigc::signal<void, boost::weak_ptr<Region> > RegionAdded;
	sigc::signal<void, boost::weak_ptr<Region> > RegionRemoved;
	sigc::signal<void>      NameChanged;
	sigc::signal<void>      LengthChanged;
	sigc::signal<void, std::list< Evoral::RangeMove<nframes_t> > const &> RangesMoved;

	static std::string bump_name (std::string old_name, Session&);

	void freeze ();
	void thaw ();

	void raise_region (boost::shared_ptr<Region>);
	void lower_region (boost::shared_ptr<Region>);
	void raise_region_to_top (boost::shared_ptr<Region>);
	void lower_region_to_bottom (boost::shared_ptr<Region>);

	uint32_t read_data_count() const { return _read_data_count; }

	const PBD::ID& get_orig_diskstream_id () const { return _orig_diskstream_id; }
	void set_orig_diskstream_id (const PBD::ID& did) { _orig_diskstream_id = did; }

	/* destructive editing */

	virtual bool destroy_region (boost::shared_ptr<Region>) = 0;

	/* special case function used by UI selection objects, which have playlists that actually own the regions
	   within them.
	*/

	void drop_regions ();

	bool explicit_relayering () const {
		return _explicit_relayering;
	}

	void set_explicit_relayering (bool e);

  protected:
	friend class Session;

  protected:
	struct RegionLock {
		RegionLock (Playlist *pl, bool do_block_notify = true) : playlist (pl), block_notify (do_block_notify) {
			playlist->region_lock.lock();
			if (block_notify) {
				playlist->delay_notifications();
			}
		}
		~RegionLock() {
			playlist->region_lock.unlock();
			if (block_notify) {
				playlist->release_notifications ();
			}
		}
		Playlist *playlist;
		bool block_notify;
	};

	friend class RegionLock;

	RegionList       regions;  /* the current list of regions in the playlist */
	std::set<boost::shared_ptr<Region> > all_regions; /* all regions ever added to this playlist */
	std::list<sigc::connection> region_state_changed_connections;
	DataType        _type;
	mutable gint    block_notifications;
	mutable gint    ignore_state_changes;
	mutable Glib::RecMutex region_lock;
	std::set<boost::shared_ptr<Region> > pending_adds;
	std::set<boost::shared_ptr<Region> > pending_removes;
	RegionList       pending_bounds;
	bool             pending_modified;
	bool             pending_length;
	std::list< Evoral::RangeMove<nframes_t> > pending_range_moves;
	bool             save_on_thaw;
	std::string      last_save_reason;
	uint32_t         in_set_state;
	bool             first_set_state;
	bool            _hidden;
	bool            _splicing;
	bool            _shuffling;
	bool            _nudging;
	uint32_t        _refcnt;
	EditMode        _edit_mode;
	bool             in_flush;
	bool             in_partition;
	bool            _frozen;
	uint32_t         subcnt;
	uint32_t        _read_data_count;
	PBD::ID         _orig_diskstream_id;
	uint64_t         layer_op_counter;
	nframes_t        freeze_length;
	bool             auto_partition;

	/** true if relayering should be done using region's current layers and their `pending explicit relayer'
	 *  flags; otherwise false if relayering should be done using the layer-model (most recently moved etc.)
	 *  Explicit relayering is used by tracks in stacked regionview mode.
	 */
	bool            _explicit_relayering;

	void init (bool hide);

	bool holding_state () const {
		return g_atomic_int_get (&block_notifications) != 0 ||
			g_atomic_int_get (&ignore_state_changes) != 0;
	}

	void delay_notifications ();
	void release_notifications ();
	virtual void flush_notifications ();

	void notify_region_removed (boost::shared_ptr<Region>);
	void notify_region_added (boost::shared_ptr<Region>);
	void notify_length_changed ();
	void notify_layering_changed ();
	void notify_modified ();
	void notify_state_changed (Change);
	void notify_region_moved (boost::shared_ptr<Region>);

	void mark_session_dirty();

	void region_changed_proxy (Change, boost::weak_ptr<Region>);
	virtual bool region_changed (Change, boost::shared_ptr<Region>);

	void region_bounds_changed (Change, boost::shared_ptr<Region>);
	void region_deleted (boost::shared_ptr<Region>);

	void sort_regions ();

	void possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude = boost::shared_ptr<Region>());
	void possibly_splice_unlocked(nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude = boost::shared_ptr<Region>());

	void core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude);
	void splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude);
	void splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr<Region> exclude);

	virtual void finalize_split_region (boost::shared_ptr<Region> /*original*/, boost::shared_ptr<Region> /*left*/, boost::shared_ptr<Region> /*right*/) {}

	virtual void check_dependents (boost::shared_ptr<Region> /*region*/, bool /*norefresh*/) {}
	virtual void refresh_dependents (boost::shared_ptr<Region> /*region*/) {}
	virtual void remove_dependents (boost::shared_ptr<Region> /*region*/) {}

	virtual XMLNode& state (bool);

	boost::shared_ptr<Region> region_by_id (PBD::ID);

	bool add_region_internal (boost::shared_ptr<Region>, nframes_t position);

	int remove_region_internal (boost::shared_ptr<Region>);
	RegionList *find_regions_at (nframes_t frame);
	void copy_regions (RegionList&) const;
	void partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist);

	nframes_t _get_maximum_extent() const;

	boost::shared_ptr<Playlist> cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t, bool),
			std::list<AudioRange>& ranges, bool result_is_hidden);
	boost::shared_ptr<Playlist> cut (nframes_t start, nframes_t cnt, bool result_is_hidden);
	boost::shared_ptr<Playlist> copy (nframes_t start, nframes_t cnt, bool result_is_hidden);

	int move_region_to_layer (layer_t, boost::shared_ptr<Region> r, int dir);
	void relayer ();

	void unset_freeze_parent (Playlist*);
	void unset_freeze_child (Playlist*);

	void timestamp_layer_op (boost::shared_ptr<Region>);

	void _split_region (boost::shared_ptr<Region>, nframes_t position);
};

} /* namespace ARDOUR */

#endif	/* __ardour_playlist_h__ */