X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fardour%2Fplaylist.h;h=a64ebdd727c5602420a6c828811fe6fe0b10e89c;hb=97d920593ffc796986107e16d7bbf88cc3184043;hp=1018419c262a8a501a7dd23c79df1acdc511b451;hpb=b1e69d4b7bfba085f5206fe64c4695ab10506c26;p=ardour.git diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index 1018419c26..a64ebdd727 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + 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 @@ -32,37 +32,71 @@ #include -#include - #include "pbd/undo.h" -#include "pbd/stateful.h" +#include "pbd/stateful.h" #include "pbd/statefuldestructible.h" +#include "pbd/sequence_property.h" +#include "pbd/stacktrace.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; +class Crossfade; + +namespace Properties { + /* fake the type, since regions are handled by SequenceProperty which doesn't + care about such things. + */ + extern PBD::PropertyDescriptor regions; +} -class Playlist : public SessionObject, - public boost::noncopyable, - public boost::enable_shared_from_this { +class RegionListProperty : public PBD::SequenceProperty > > +{ public: - typedef std::list > RegionList; + RegionListProperty (Playlist&); + + RegionListProperty* clone () const; + void get_content_as_xml (boost::shared_ptr, XMLNode &) const; + boost::shared_ptr get_content_from_xml (XMLNode const &) const; + + private: + RegionListProperty* create () const; + + /* copy construction only by ourselves */ + RegionListProperty (RegionListProperty const & p); + + friend class Playlist; + /* we live and die with our playlist, no lifetime management needed */ + Playlist& _playlist; +}; + +class Playlist : public SessionObject , public boost::enable_shared_from_this +{ +public: + static void make_property_quarks (); Playlist (Session&, const XMLNode&, DataType type, bool hidden = false); Playlist (Session&, std::string name, DataType type, bool hidden = false); Playlist (boost::shared_ptr, std::string name, bool hidden = false); - Playlist (boost::shared_ptr, nframes_t start, nframes_t cnt, std::string name, bool hidden = false); + Playlist (boost::shared_ptr, framepos_t start, framecnt_t cnt, std::string name, bool hidden = false); + + virtual ~Playlist (); - virtual ~Playlist (); + void update (const RegionListProperty::ChangeRecord&); + void clear_owned_changes (); + void rdiff (std::vector&) const; + + boost::shared_ptr region_by_id (const PBD::ID&) const; + + uint32_t max_source_level () const; void set_region_ownership (); @@ -74,6 +108,7 @@ class Playlist : public SessionObject, bool used () const { return _refcnt != 0; } bool set_name (const std::string& str); + int sort_id() { return _sort_id; } const DataType& data_type() const { return _type; } @@ -83,7 +118,8 @@ class Playlist : public SessionObject, bool hidden() const { return _hidden; } bool empty() const; uint32_t n_regions() const; - nframes_t get_maximum_extent () const; + bool all_regions_empty() const; + std::pair get_extent () const; layer_t top_layer() const; EditMode get_edit_mode() const { return _edit_mode; } @@ -91,119 +127,158 @@ class Playlist : public SessionObject, /* Editing operations */ - void add_region (boost::shared_ptr, nframes_t position, float times = 1, bool auto_partition = false); + void add_region (boost::shared_ptr, framepos_t position, float times = 1, bool auto_partition = false); void remove_region (boost::shared_ptr); + void remove_region_by_source (boost::shared_ptr); void get_equivalent_regions (boost::shared_ptr, std::vector >&); void get_region_list_equivalent_regions (boost::shared_ptr, std::vector >&); - void replace_region (boost::shared_ptr old, boost::shared_ptr newr, nframes_t pos); - void split_region (boost::shared_ptr, 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, nframes_t position, float times); - void nudge_after (nframes_t start, nframes_t distance, bool forwards); + void replace_region (boost::shared_ptr old, boost::shared_ptr newr, framepos_t pos); + void split_region (boost::shared_ptr, framepos_t position); + void split (framepos_t at); + void shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue); + void partition (framepos_t start, framepos_t end, bool cut = false); + void duplicate (boost::shared_ptr, framepos_t position, float times); + void nudge_after (framepos_t start, framecnt_t distance, bool forwards); + boost::shared_ptr combine (const RegionList&); + void uncombine (boost::shared_ptr); + void shuffle (boost::shared_ptr, int dir); void update_after_tempo_map_change (); boost::shared_ptr cut (std::list&, bool result_is_hidden = true); boost::shared_ptr copy (std::list&, bool result_is_hidden = true); - int paste (boost::shared_ptr, nframes_t position, float times); + int paste (boost::shared_ptr, framepos_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); + const RegionListProperty& region_list () const { return regions; } + + boost::shared_ptr regions_at (framepos_t frame); + uint32_t count_regions_at (framepos_t) const; + boost::shared_ptr regions_touched (framepos_t start, framepos_t end); + boost::shared_ptr regions_with_start_within (Evoral::Range); + boost::shared_ptr regions_with_end_within (Evoral::Range); + uint32_t region_use_count (boost::shared_ptr) const; boost::shared_ptr find_region (const PBD::ID&) const; - boost::shared_ptr top_region_at (nframes_t frame); - boost::shared_ptr find_next_region (nframes_t frame, RegionPoint point, int dir); - nframes64_t find_next_region_boundary (nframes64_t frame, int dir); + boost::shared_ptr top_region_at (framepos_t frame); + boost::shared_ptr top_unmuted_region_at (framepos_t frame); + boost::shared_ptr find_next_region (framepos_t frame, RegionPoint point, int dir); + framepos_t find_next_region_boundary (framepos_t frame, int dir); bool region_is_shuffle_constrained (boost::shared_ptr); + bool has_region_at (framepos_t const) const; + + bool uses_source (boost::shared_ptr src) const; - nframes64_t find_next_transient (nframes64_t position, int dir); + framepos_t find_next_transient (framepos_t position, int dir); - void foreach_region (sigc::slot >); + void foreach_region (boost::function)>); XMLNode& get_state (); - int set_state (const XMLNode&); + virtual int set_state (const XMLNode&, int version); XMLNode& get_template (); - sigc::signal InUse; - sigc::signal Modified; - sigc::signal > RegionAdded; - sigc::signal > RegionRemoved; - sigc::signal NameChanged; - sigc::signal LengthChanged; - sigc::signal > const &> RangesMoved; + PBD::Signal1 InUse; + PBD::Signal0 ContentsChanged; + PBD::Signal1 > RegionAdded; + PBD::Signal1 > RegionRemoved; + PBD::Signal0 NameChanged; + PBD::Signal0 LayeringChanged; + + /** Emitted when regions have moved (not when regions have only been trimmed) */ + PBD::Signal2 > const &, bool> RangesMoved; + + /** Emitted when regions are extended; the ranges passed are the new extra time ranges + that these regions now occupy. + */ + PBD::Signal1 > const &> RegionsExtended; static std::string bump_name (std::string old_name, Session&); void freeze (); - void thaw (); + void thaw (bool from_undo = false); void raise_region (boost::shared_ptr); void lower_region (boost::shared_ptr); void raise_region_to_top (boost::shared_ptr); void lower_region_to_bottom (boost::shared_ptr); - 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; } + const PBD::ID& get_orig_track_id () const { return _orig_track_id; } + void set_orig_track_id (const PBD::ID& did); /* destructive editing */ - + virtual bool destroy_region (boost::shared_ptr) = 0; + void sync_all_regions_with_regions (); + /* 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; + virtual boost::shared_ptr find_crossfade (const PBD::ID &) const { + return boost::shared_ptr (); } - - void set_explicit_relayering (bool e); + framepos_t find_next_top_layer_position (framepos_t) const; + uint32_t combine_ops() const { return _combine_ops; } + + void set_layer (boost::shared_ptr, double); + + void set_capture_insertion_in_progress (bool yn); + 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 */ + class RegionReadLock : public Glib::RWLock::ReaderLock { + public: + RegionReadLock (Playlist *pl) : Glib::RWLock::ReaderLock (pl->region_lock) {} + ~RegionReadLock() {} + }; + + class RegionWriteLock : public Glib::RWLock::WriterLock { + public: + RegionWriteLock (Playlist *pl, bool do_block_notify = true) + : Glib::RWLock::WriterLock (pl->region_lock) + , playlist (pl) + , block_notify (do_block_notify) { + if (block_notify) { + playlist->delay_notifications(); + } + } + + ~RegionWriteLock() { + Glib::RWLock::WriterLock::release (); + if (block_notify) { + playlist->release_notifications (); + } + } + Playlist *playlist; + bool block_notify; + }; + + RegionListProperty regions; /* the current list of regions in the playlist */ std::set > all_regions; /* all regions ever added to this playlist */ - std::list region_state_changed_connections; + PBD::ScopedConnectionList region_state_changed_connections; DataType _type; + int _sort_id; mutable gint block_notifications; mutable gint ignore_state_changes; - mutable Glib::RecMutex region_lock; std::set > pending_adds; std::set > pending_removes; RegionList pending_bounds; - bool pending_modified; - bool pending_length; - std::list< Evoral::RangeMove > pending_range_moves; - bool save_on_thaw; - std::string last_save_reason; + bool pending_contents_change; + bool pending_layering; + + /** Movements of time ranges caused by region moves; note that + * region trims are not included in this list; it is used to + * do automation-follows-regions. + */ + std::list< Evoral::RangeMove > pending_range_moves; + /** Extra sections added to regions during trims */ + std::list< Evoral::Range > pending_region_extensions; uint32_t in_set_state; + bool in_undo; bool first_set_state; bool _hidden; bool _splicing; @@ -214,88 +289,98 @@ class Playlist : public SessionObject, bool in_flush; bool in_partition; bool _frozen; + bool _capture_insertion_underway; 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; + PBD::ID _orig_track_id; + uint32_t _combine_ops; void init (bool hide); - bool holding_state () const { + 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 release_notifications (bool from_undo = false); + virtual void flush_notifications (bool from_undo = false); + void clear_pending (); + + void _set_sort_id (); + + boost::shared_ptr regions_touched_locked (framepos_t start, framepos_t end); void notify_region_removed (boost::shared_ptr); void notify_region_added (boost::shared_ptr); - void notify_length_changed (); void notify_layering_changed (); - void notify_modified (); - void notify_state_changed (Change); + void notify_contents_changed (); + void notify_state_changed (const PBD::PropertyChange&); void notify_region_moved (boost::shared_ptr); + void notify_region_start_trimmed (boost::shared_ptr); + void notify_region_end_trimmed (boost::shared_ptr); void mark_session_dirty(); - void region_changed_proxy (Change, boost::weak_ptr); - virtual bool region_changed (Change, boost::shared_ptr); + void region_changed_proxy (const PBD::PropertyChange&, boost::weak_ptr); + virtual bool region_changed (const PBD::PropertyChange&, boost::shared_ptr); - void region_bounds_changed (Change, boost::shared_ptr); + void region_bounds_changed (const PBD::PropertyChange&, boost::shared_ptr); void region_deleted (boost::shared_ptr); void sort_regions (); - void possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr exclude = boost::shared_ptr()); - void possibly_splice_unlocked(nframes_t at, nframes64_t distance, boost::shared_ptr exclude = boost::shared_ptr()); + void possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr exclude = boost::shared_ptr()); + void possibly_splice_unlocked(framepos_t at, framecnt_t distance, boost::shared_ptr exclude = boost::shared_ptr()); - void core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr exclude); - void splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr exclude); - void splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr exclude); + void core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr exclude); + void splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr exclude); + void splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr exclude); - virtual void finalize_split_region (boost::shared_ptr /*original*/, boost::shared_ptr /*left*/, boost::shared_ptr /*right*/) {} - - virtual void check_dependents (boost::shared_ptr /*region*/, bool /*norefresh*/) {} - virtual void refresh_dependents (boost::shared_ptr /*region*/) {} + virtual void check_crossfades (Evoral::Range) {} virtual void remove_dependents (boost::shared_ptr /*region*/) {} virtual XMLNode& state (bool); - boost::shared_ptr region_by_id (PBD::ID); + bool add_region_internal (boost::shared_ptr, framepos_t position); - bool add_region_internal (boost::shared_ptr, nframes_t position); - int remove_region_internal (boost::shared_ptr); - 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); + void partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist); - nframes_t _get_maximum_extent() const; + std::pair _get_extent() const; - boost::shared_ptr cut_copy (boost::shared_ptr (Playlist::*pmf)(nframes_t, nframes_t, bool), + boost::shared_ptr cut_copy (boost::shared_ptr (Playlist::*pmf)(framepos_t, framecnt_t, bool), std::list& ranges, bool result_is_hidden); - boost::shared_ptr cut (nframes_t start, nframes_t cnt, bool result_is_hidden); - boost::shared_ptr copy (nframes_t start, nframes_t cnt, bool result_is_hidden); + boost::shared_ptr cut (framepos_t start, framecnt_t cnt, bool result_is_hidden); + boost::shared_ptr copy (framepos_t start, framecnt_t cnt, bool result_is_hidden); - int move_region_to_layer (layer_t, boost::shared_ptr r, int dir); void relayer (); - - void unset_freeze_parent (Playlist*); - void unset_freeze_child (Playlist*); - void timestamp_layer_op (boost::shared_ptr); + void begin_undo (); + void end_undo (); + + void _split_region (boost::shared_ptr, framepos_t position); + + typedef std::pair, boost::shared_ptr > TwoRegions; + + /* this is called before we create a new compound region */ + virtual void pre_combine (std::vector >&) {} + /* this is called before we create a new compound region */ + virtual void post_combine (std::vector >&, boost::shared_ptr) {} + /* this is called before we remove a compound region and replace it + with its constituent regions + */ + virtual void pre_uncombine (std::vector >&, boost::shared_ptr) {} + + private: + friend class RegionReadLock; + friend class RegionWriteLock; + mutable Glib::RWLock region_lock; - void _split_region (boost::shared_ptr, nframes_t position); + private: + void setup_layering_indices (RegionList const &); + void coalesce_and_check_crossfades (std::list >); + boost::shared_ptr find_regions_at (framepos_t); }; } /* namespace ARDOUR */