(Hopefully) clarify operator= and copy construction behaviour of the Property hierarc...
[ardour.git] / libs / ardour / audio_playlist.cc
index 7f75d448526d4ffa433d9d3e90cdb128d8096d16..5019935d5d0802587dae7b4e91c077f2b06855d9 100644 (file)
@@ -21,8 +21,8 @@
 
 #include <cstdlib>
 
-
 #include "ardour/types.h"
+#include "ardour/debug.h"
 #include "ardour/configuration.h"
 #include "ardour/audioplaylist.h"
 #include "ardour/audioregion.h"
@@ -37,11 +37,76 @@ using namespace ARDOUR;
 using namespace std;
 using namespace PBD;
 
+namespace ARDOUR {
+       namespace Properties {
+               PBD::PropertyDescriptor<bool> crossfades;
+       }
+}
+
+void
+AudioPlaylist::make_property_quarks ()
+{
+        Properties::crossfades.property_id = g_quark_from_static_string (X_("crossfades"));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for crossfades = %1\n", Properties::crossfades.property_id));
+}
+
+CrossfadeListProperty::CrossfadeListProperty (AudioPlaylist& pl)
+        : SequenceProperty<std::list<boost::shared_ptr<Crossfade> > > (Properties::crossfades.property_id, boost::bind (&AudioPlaylist::update, &pl, _1))
+        , _playlist (pl)
+{
+       
+}
+
+CrossfadeListProperty::CrossfadeListProperty (CrossfadeListProperty const & p)
+       : PBD::SequenceProperty<std::list<boost::shared_ptr<Crossfade> > > (p)
+       , _playlist (p._playlist)
+{
+
+}
+
+
+CrossfadeListProperty *
+CrossfadeListProperty::create () const
+{
+       return new CrossfadeListProperty (_playlist);
+}
+
+CrossfadeListProperty *
+CrossfadeListProperty::clone () const
+{
+       return new CrossfadeListProperty (*this);
+}
+
+void
+CrossfadeListProperty::get_content_as_xml (boost::shared_ptr<Crossfade> xfade, XMLNode & node) const
+{
+       /* Crossfades are not written to any state when they are no
+          longer in use, so we must write their state here.
+       */
+
+       XMLNode& c = xfade->get_state ();
+       node.add_child_nocopy (c);
+}
+
+boost::shared_ptr<Crossfade>
+CrossfadeListProperty::get_content_from_xml (XMLNode const & node) const
+{
+       XMLNodeList const c = node.children ();
+       assert (c.size() == 1);
+       return boost::shared_ptr<Crossfade> (new Crossfade (_playlist, *c.front()));
+}
+
+
 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
        : Playlist (session, node, DataType::AUDIO, hidden)
+       , _crossfades (*this)
 {
+#ifndef NDEBUG
        const XMLProperty* prop = node.property("type");
        assert(!prop || DataType(prop->value()) == DataType::AUDIO);
+#endif
+
+       add_property (_crossfades);
 
        in_set_state++;
        set_state (node, Stateful::loading_state_version);
@@ -50,12 +115,17 @@ AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden
 
 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
        : Playlist (session, name, DataType::AUDIO, hidden)
+       , _crossfades (*this)
 {
+       add_property (_crossfades);
 }
 
 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
        : Playlist (other, name, hidden)
+       , _crossfades (*this)
 {
+       add_property (_crossfades);
+       
        RegionList::const_iterator in_o  = other->regions.begin();
        RegionList::iterator in_n = regions.begin();
 
@@ -96,7 +166,10 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, stri
 
 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
        : Playlist (other, start, cnt, name, hidden)
+       , _crossfades (*this)
 {
+       add_property (_crossfades);
+       
        /* this constructor does NOT notify others (session) */
 }
 
@@ -163,7 +236,7 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf
                if ((*i)->coverage (start, end) != OverlapNone) {
                        relevant_regions[(*i)->layer()].push_back (*i);
                        relevant_layers.push_back ((*i)->layer());
-               }
+                }
        }
 
        for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
@@ -188,8 +261,10 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf
                vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
                vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
 
+
                for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
                        boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
+                        DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from region %1\n", ar->name()));
                        assert(ar);
                        ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
                        _read_data_count += ar->read_data_count();
@@ -236,9 +311,9 @@ AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
 
 
 void
-AudioPlaylist::flush_notifications ()
+AudioPlaylist::flush_notifications (bool from_undo)
 {
-       Playlist::flush_notifications();
+       Playlist::flush_notifications (from_undo);
 
        if (in_flush) {
                return;
@@ -365,9 +440,6 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
        }
 
        for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
-
-               nframes_t xfade_length;
-
                other = boost::dynamic_pointer_cast<AudioRegion> (*i);
 
                if (other == region) {
@@ -397,6 +469,7 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
                touched_regions = 0;
 
                try {
+                       framecnt_t xfade_length;
                        switch (c) {
                        case OverlapNone:
                                break;
@@ -420,7 +493,7 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
                                   audio engineering.
                                */
 
-                               xfade_length = min ((nframes_t) 720, top->length());
+                               xfade_length = min ((framecnt_t) 720, top->length());
 
                                if (top_region_at (top->first_frame()) == top) {
 
@@ -454,7 +527,7 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
                                } else {
 
                                        touched_regions = regions_touched (top->first_frame(),
-                                                                          top->first_frame() + min ((nframes_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
+                                                                          top->first_frame() + min ((framecnt_t) _session.config.get_short_xfade_seconds() * _session.frame_rate(),
                                                                                                     top->length()));
                                        if (touched_regions->size() <= 2) {
                                                xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
@@ -480,7 +553,7 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
 
                                } else {
                                        touched_regions = regions_touched (bottom->first_frame(),
-                                                                          bottom->first_frame() + min ((nframes_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
+                                                                          bottom->first_frame() + min ((framecnt_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
                                                                                                        bottom->length()));
                                        if (touched_regions->size() <= 2) {
                                                xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
@@ -525,7 +598,7 @@ AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
                _crossfades.push_back (xfade);
 
                xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
-               xfade->StateChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
+               xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
 
                notify_crossfade_added (xfade);
        }
@@ -581,7 +654,7 @@ AudioPlaylist::set_state (const XMLNode& node, int version)
                        boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
                        _crossfades.push_back (xfade);
                        xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
-                       xfade->StateChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
+                       xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
                        NewCrossfade(xfade);
                }
 
@@ -662,17 +735,15 @@ bool
 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
 {
        boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
+
+        if (!r) {
+                return false;
+        }
+
        bool changed = false;
        Crossfades::iterator c, ctmp;
        set<boost::shared_ptr<Crossfade> > unique_xfades;
 
-       if (r == 0) {
-               fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
-                     << endmsg;
-               /*NOTREACHED*/
-               return false;
-       }
-
        {
                RegionLock rlock (this);
 
@@ -726,7 +797,7 @@ AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
 }
 
 void
-AudioPlaylist::crossfade_changed (Change)
+AudioPlaylist::crossfade_changed (const PropertyChange&)
 {
        if (in_flush || in_set_state) {
                return;
@@ -742,24 +813,27 @@ AudioPlaylist::crossfade_changed (Change)
 }
 
 bool
-AudioPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
+AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
 {
        if (in_flush || in_set_state) {
                return false;
        }
 
-       Change our_interests = Change (AudioRegion::FadeInChanged|
-                                      AudioRegion::FadeOutChanged|
-                                      AudioRegion::FadeInActiveChanged|
-                                      AudioRegion::FadeOutActiveChanged|
-                                      AudioRegion::EnvelopeActiveChanged|
-                                      AudioRegion::ScaleAmplitudeChanged|
-                                      AudioRegion::EnvelopeChanged);
+       PropertyChange our_interests;
+
+       our_interests.add (Properties::fade_in_active);
+       our_interests.add (Properties::fade_out_active);
+       our_interests.add (Properties::scale_amplitude);
+       our_interests.add (Properties::envelope_active);
+       our_interests.add (Properties::envelope);
+       our_interests.add (Properties::fade_in);
+       our_interests.add (Properties::fade_out);
+
        bool parent_wants_notify;
 
        parent_wants_notify = Playlist::region_changed (what_changed, region);
 
-       if ((parent_wants_notify || (what_changed & our_interests))) {
+       if (parent_wants_notify || (what_changed.contains (our_interests))) {
                notify_contents_changed ();
        }
 
@@ -791,3 +865,13 @@ AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossf
                s (*i);
        }
 }
+
+void
+AudioPlaylist::update (const CrossfadeListProperty::ChangeRecord& change)
+{
+       for (CrossfadeListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
+               add_crossfade (*i);
+       }
+
+       /* don't remove crossfades here; they will be dealt with by the dependency code */
+}