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