No-op: rename a few variables and add/fix some comments.
[ardour.git] / libs / ardour / ardour / playlist.h
index d322f564eed7be4245a1678ebe45935882767879..d9a14c01fd750c9bbe4a1e523b51bf33030a4d4a 100644 (file)
@@ -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
@@ -15,7 +15,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id$
 */
 
 #ifndef __ardour_playlist_h__
 #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 <ardour/ardour.h>
-#include <ardour/crossfade_compare.h>
-#include <ardour/location.h>
-#include <ardour/stateful.h>
-#include <ardour/source.h>
-#include <ardour/state_manager.h>
+#include "pbd/undo.h"
+#include "pbd/stateful.h"
+#include "pbd/stateful_owner.h"
+#include "pbd/statefuldestructible.h"
+#include "pbd/sequence_property.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;
+
+namespace Properties {
+        /* fake the type, since regions are handled by SequenceProperty which doesn't
+           care about such things.
+        */
+        extern PBD::PropertyDescriptor<bool> regions;
+}
+
+class RegionListProperty : public PBD::SequenceProperty<std::list<boost::shared_ptr<Region > > >
+{
+  public:
+        RegionListProperty (Playlist&);
+
+        boost::shared_ptr<Region> lookup_id (const PBD::ID& id);
+        void diff (PBD::PropertyList& undo, PBD::PropertyList& redo) const;
+
+  private:
+        friend class Playlist;
+        std::list<boost::shared_ptr<Region> > rlist() { return _val; }
+
+        /* we live and die with our playlist, no lifetime management needed */
+        Playlist& _playlist;
+
+        /* create a copy of this RegionListProperty that only
+           has what is needed for use in a history list command. This
+           means that it won't contain the actual region list but
+           will have the added/removed list.
+        */
+        RegionListProperty* copy_for_history () const;
+};
 
-class Playlist : public Stateful, public StateManager {
+class Playlist : public SessionObject
+               , public PBD::StatefulOwner
+              , public boost::enable_shared_from_this<Playlist> {
   public:
-       typedef list<Region*>    RegionList;
+       typedef std::list<boost::shared_ptr<Region> >    RegionList;
+        static void make_property_quarks ();
 
-       Playlist (Session&, const XMLNode&, bool hidden = false);
-       Playlist (Session&, string name, bool hidden = false);
-       Playlist (const Playlist&, string name, bool hidden = false);
-       Playlist (const Playlist&, jack_nframes_t start, jack_nframes_t cnt, string name, bool hidden = false);
+       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>, framepos_t start, framecnt_t cnt, std::string name, bool hidden = false);
 
-       virtual jack_nframes_t read (Sample *dst, Sample *mixdown, float *gain_buffer, char * workbuf, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0) = 0;
-       virtual void clear (bool with_delete = false, bool with_save = true);
+       virtual ~Playlist ();
+
+        bool set_property (const PBD::PropertyBase&);
+        void update (const RegionListProperty::ChangeRecord&);
+        void clear_owned_history ();
+        void rdiff (std::vector<PBD::StatefulDiffCommand*>&) const;
+
+        PBD::PropertyList* property_factory (const XMLNode&) const;
+
+       boost::shared_ptr<Region> region_by_id (const PBD::ID&);
+
+       void set_region_ownership ();
+
+       virtual void clear (bool with_signals=true);
        virtual void dump () const;
-       virtual UndoAction get_memento() const = 0;
 
-       void ref();
-       void unref();
-       uint32_t refcnt() const { return _refcnt; }
+       void use();
+       void release();
+       bool used () const { return _refcnt != 0; }
 
-       const string& name() const { return _name; }
-       void set_name (const string& str);
+       bool set_name (const std::string& str);
+        int sort_id() { return _sort_id; }
+
+       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;
-       jack_nframes_t get_maximum_extent () const;
+       uint32_t n_regions() const;
+       framecnt_t get_maximum_extent () const;
        layer_t top_layer() const;
 
        EditMode get_edit_mode() const { return _edit_mode; }
@@ -79,110 +134,132 @@ class Playlist : public Stateful, public StateManager {
 
        /* Editing operations */
 
-       void add_region (const Region&, jack_nframes_t position, float times = 1, bool with_save = true);
-       void remove_region (Region *);
-       void replace_region (Region& old, Region& newr, jack_nframes_t pos);
-       void split_region (Region&, jack_nframes_t position);
-       void partition (jack_nframes_t start, jack_nframes_t end, bool just_top_level);
-       void duplicate (Region&, jack_nframes_t position, float times);
-       void nudge_after (jack_nframes_t start, jack_nframes_t distance, bool forwards);
-
-       Region* find_region (id_t) const;
-
-       Playlist* cut  (list<AudioRange>&, bool result_is_hidden = true);
-       Playlist* copy (list<AudioRange>&, bool result_is_hidden = true);
-       int       paste (Playlist&, jack_nframes_t position, float times);
-
-       uint32_t read_data_count() { return _read_data_count; }
-
-       RegionList* regions_at (jack_nframes_t frame);
-       RegionList* regions_touched (jack_nframes_t start, jack_nframes_t end);
-       Region*     top_region_at (jack_nframes_t frame);
-
-       Region*     find_next_region (jack_nframes_t frame, RegionPoint point, int dir);
-
-       template<class T> void foreach_region (T *t, void (T::*func)(Region *, void *), void *arg);
-       template<class T> void foreach_region (T *t, void (T::*func)(Region *));
+       void add_region (boost::shared_ptr<Region>, framepos_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, framepos_t pos);
+       void split_region (boost::shared_ptr<Region>, 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<Region>, framepos_t position, float times);
+       void nudge_after (framepos_t start, framecnt_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>, framepos_t position, float times);
+
+       const RegionListProperty& region_list () const { return regions; }
+
+       RegionList*                regions_at (framepos_t frame);
+       RegionList*                regions_touched (framepos_t start, framepos_t end);
+       RegionList*                regions_to_read (framepos_t start, framepos_t end);
+       boost::shared_ptr<Region>  find_region (const PBD::ID&) const;
+       boost::shared_ptr<Region>  top_region_at (framepos_t frame);
+       boost::shared_ptr<Region>  top_unmuted_region_at (framepos_t frame);
+       boost::shared_ptr<Region>  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<Region>);
+       bool                       has_region_at (framepos_t const) const;
+
+
+       framepos_t find_next_transient (framepos_t position, int dir);
+
+       void foreach_region (boost::function<void (boost::shared_ptr<Region>)>);
 
        XMLNode& get_state ();
-       int set_state (const XMLNode&);
+       int set_state (const XMLNode&, int version);
        XMLNode& get_template ();
 
-       sigc::signal<void,Region *> RegionAdded;
-       sigc::signal<void,Region *> RegionRemoved;
-
-       sigc::signal<void,Playlist*,bool> InUse;
-       sigc::signal<void>            Modified;
-       sigc::signal<void>            NameChanged;
-       sigc::signal<void>            LengthChanged;
-       sigc::signal<void>            LayeringChanged;
-       sigc::signal<void,Playlist *> GoingAway;
-       sigc::signal<void>            StatePushed;
+       PBD::Signal1<void,bool> InUse;
+       PBD::Signal0<void>      ContentsChanged;
+       PBD::Signal1<void,boost::weak_ptr<Region> > RegionAdded;
+       PBD::Signal1<void,boost::weak_ptr<Region> > RegionRemoved;
+       PBD::Signal0<void>      NameChanged;
+       PBD::Signal0<void>      LengthChanged;
+       PBD::Signal0<void>      LayeringChanged;
+       PBD::Signal1<void,std::list< Evoral::RangeMove<framepos_t> > const &> RangesMoved;
 
-       static sigc::signal<void,Playlist*> PlaylistCreated;
-
-       static string bump_name (string old_name, Session&);
-       static string bump_name_once (string old_name);
+       static std::string bump_name (std::string old_name, Session&);
 
        void freeze ();
        void thaw ();
 
-       void raise_region (Region&);
-       void lower_region (Region&);
-       void raise_region_to_top (Region&);
-       void lower_region_to_bottom (Region&);
+       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; }
 
-       Session& session() { return _session; }
-
-       id_t get_orig_diskstream_id () const { return _orig_diskstream_id; }
-       void set_orig_diskstream_id (id_t did) { _orig_diskstream_id = did; }  
+       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 (Region *) = 0;
+
+       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;
-       virtual ~Playlist ();  /* members of the public use unref() */
 
   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;
+               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;
-       string          _name;
-       Session&        _session;
+        RegionListProperty   regions;  /* the current list of regions in the playlist */
+       std::set<boost::shared_ptr<Region> > all_regions; /* all regions ever added to this playlist */
+       PBD::ScopedConnectionList region_state_changed_connections;
+       DataType        _type;
+        int             _sort_id;
        mutable gint    block_notifications;
        mutable gint    ignore_state_changes;
-       mutable Glib::Mutex region_lock;
-       RegionList       pending_removals;
-       RegionList       pending_adds;
+       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_contents_change;
+       bool             pending_layering;
        bool             pending_length;
+       std::list< Evoral::RangeMove<framepos_t> > pending_range_moves;
        bool             save_on_thaw;
-       string           last_save_reason;
-       bool             in_set_state;
+       std::string      last_save_reason;
+       uint32_t         in_set_state;
+       bool             in_update;
+       bool             first_set_state;
        bool            _hidden;
        bool            _splicing;
+       bool            _shuffling;
        bool            _nudging;
        uint32_t        _refcnt;
        EditMode        _edit_mode;
@@ -191,88 +268,89 @@ class Playlist : public Stateful, public StateManager {
        bool            _frozen;
        uint32_t         subcnt;
        uint32_t        _read_data_count;
-       id_t            _orig_diskstream_id;
+       PBD::ID         _orig_diskstream_id;
        uint64_t         layer_op_counter;
-       jack_nframes_t   freeze_length;
+       framecnt_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 { 
+       bool holding_state () const {
                return g_atomic_int_get (&block_notifications) != 0 ||
                        g_atomic_int_get (&ignore_state_changes) != 0;
        }
 
-       /* prevent the compiler from ever generating these */
-
-       Playlist (const Playlist&);
-       Playlist (Playlist&);
-
        void delay_notifications ();
        void release_notifications ();
        virtual void flush_notifications ();
+       void clear_pending ();
+
+        void _set_sort_id ();
 
-       void notify_region_removed (Region *);
-       void notify_region_added (Region *);
+       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_contents_changed ();
+       void notify_state_changed (const PBD::PropertyChange&);
+       void notify_region_moved (boost::shared_ptr<Region>);
 
        void mark_session_dirty();
 
-       void region_changed_proxy (Change, Region*);
-       virtual bool region_changed (Change, Region*);
+       void region_changed_proxy (const PBD::PropertyChange&, boost::weak_ptr<Region>);
+       virtual bool region_changed (const PBD::PropertyChange&, boost::shared_ptr<Region>);
 
-       void region_bounds_changed (Change, Region *);
-       void region_deleted (Region *);
+       void region_bounds_changed (const PBD::PropertyChange&, boost::shared_ptr<Region>);
+       void region_deleted (boost::shared_ptr<Region>);
 
        void sort_regions ();
 
-       void possibly_splice ();
-       void possibly_splice_unlocked();
-       void core_splice ();
-       void splice_locked ();
-       void splice_unlocked ();
+       void possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude = boost::shared_ptr<Region>());
+       void possibly_splice_unlocked(framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude = boost::shared_ptr<Region>());
 
+       void core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude);
+       void splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude);
+       void splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude);
 
-       virtual void finalize_split_region (Region *original, Region *left, Region *right) {}
-       
-       virtual void check_dependents (Region& region, bool norefresh) {}
-       virtual void refresh_dependents (Region& region) {}
-       virtual void remove_dependents (Region& region) {}
+       virtual void finalize_split_region (boost::shared_ptr<Region> /*original*/, boost::shared_ptr<Region> /*left*/, boost::shared_ptr<Region> /*right*/) {}
 
-       virtual XMLNode& state (bool);
-
-       /* override state_manager::save_state so we can check in_set_state() */
+       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*/) {}
 
-       void save_state (std::string why);
-       void maybe_save_state (std::string why);
+       virtual XMLNode& state (bool);
 
-       void add_region_internal (Region *, jack_nframes_t position, bool delay_sort = false);
+       bool add_region_internal (boost::shared_ptr<Region>, framepos_t position);
 
-       int remove_region_internal (Region *, bool delay_sort = false);
-       RegionList *find_regions_at (jack_nframes_t frame);
+       int remove_region_internal (boost::shared_ptr<Region>);
+       RegionList *find_regions_at (framepos_t frame);
        void copy_regions (RegionList&) const;
-       void partition_internal (jack_nframes_t start, jack_nframes_t end, bool cutting, RegionList& thawlist);
+       void partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist);
 
-       jack_nframes_t _get_maximum_extent() const;
+       framecnt_t _get_maximum_extent() const;
 
-       Playlist* cut_copy (Playlist* (Playlist::*pmf)(jack_nframes_t, jack_nframes_t, bool), 
-                           list<AudioRange>& ranges, bool result_is_hidden);
-       Playlist *cut (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden);
-       Playlist *copy (jack_nframes_t start, jack_nframes_t cnt, bool result_is_hidden);
+       boost::shared_ptr<Playlist> cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t, framecnt_t, bool),
+                                             std::list<AudioRange>& ranges, bool result_is_hidden);
+       boost::shared_ptr<Playlist> cut (framepos_t start, framecnt_t cnt, bool result_is_hidden);
+       boost::shared_ptr<Playlist> copy (framepos_t start, framecnt_t cnt, bool result_is_hidden);
 
-
-       int move_region_to_layer (layer_t, Region& r, int dir);
+       int move_region_to_layer (layer_t, boost::shared_ptr<Region> r, int dir);
        void relayer ();
 
-       static Playlist* copyPlaylist (const Playlist&, jack_nframes_t start, jack_nframes_t length,
-                                      string name, bool result_is_hidden);
-       
+       void begin_undo ();
+       void end_undo ();
        void unset_freeze_parent (Playlist*);
        void unset_freeze_child (Playlist*);
 
-       void timestamp_layer_op (Region&);
+       void timestamp_layer_op (boost::shared_ptr<Region>);
+
+       void _split_region (boost::shared_ptr<Region>, framepos_t position);
 };
 
 } /* namespace ARDOUR */