*/
-#define __STDC_LIMIT_MACROS
#include <stdint.h>
-
#include <set>
#include <fstream>
#include <algorithm>
#include "pbd/failed_constructor.h"
#include "pbd/stateful_diff_command.h"
#include "pbd/xml++.h"
+#include "pbd/stacktrace.h"
#include "ardour/debug.h"
#include "ardour/playlist.h"
: SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
, _playlist (pl)
{
+
}
-boost::shared_ptr<Region>
-RegionListProperty::lookup_id (const ID& id)
+RegionListProperty::RegionListProperty (RegionListProperty const & p)
+ : PBD::SequenceProperty<std::list<boost::shared_ptr<Region> > > (p)
+ , _playlist (p._playlist)
{
- boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
-
- if (!ret) {
- ret = RegionFactory::region_by_id (id);
- }
- return ret;
}
-RegionListProperty*
-RegionListProperty::copy_for_history () const
+RegionListProperty *
+RegionListProperty::clone () const
+{
+ return new RegionListProperty (*this);
+}
+
+RegionListProperty *
+RegionListProperty::create () const
+{
+ return new RegionListProperty (_playlist);
+}
+
+void
+RegionListProperty::get_content_as_xml (boost::shared_ptr<Region> region, XMLNode & node) const
{
- RegionListProperty* copy = new RegionListProperty (_playlist);
- /* this is all we need */
- copy->_change = _change;
- return copy;
+ /* All regions (even those which are deleted) have their state saved by other
+ code, so we can just store ID here.
+ */
+
+ node.add_property ("id", region->id().to_s ());
}
-void
-RegionListProperty::diff (PropertyList& undo, PropertyList& redo) const
+boost::shared_ptr<Region>
+RegionListProperty::get_content_from_xml (XMLNode const & node) const
{
- if (changed()) {
- /* list of the removed/added regions since clear_history() was last called */
- RegionListProperty* a = copy_for_history ();
+ XMLProperty const * prop = node.property ("id");
+ assert (prop);
- /* the same list, but with removed/added lists swapped (for undo purposes) */
- RegionListProperty* b = copy_for_history ();
- b->invert_changes ();
+ PBD::ID id (prop->value ());
- undo.add (b);
- redo.add (a);
+ boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
+
+ if (!ret) {
+ ret = RegionFactory::region_by_id (id);
}
+
+ return ret;
}
Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
RegionLock rlock (const_cast<Playlist *> (this));
for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
- newlist.push_back (RegionFactory::RegionFactory::create (*i));
+ newlist.push_back (RegionFactory::RegionFactory::create (*i, true));
}
}
void
Playlist::end_undo ()
{
- thaw ();
+ thaw (true);
in_update = false;
}
g_atomic_int_inc (&ignore_state_changes);
}
+/** @param from_undo true if this thaw is triggered by the end of an undo on this playlist */
void
-Playlist::thaw ()
+Playlist::thaw (bool from_undo)
{
g_atomic_int_dec_and_test (&ignore_state_changes);
- release_notifications ();
+ release_notifications (from_undo);
}
freeze_length = _get_extent().second;
}
+/** @param from_undo true if this release is triggered by the end of an undo on this playlist */
void
-Playlist::release_notifications ()
+Playlist::release_notifications (bool from_undo)
{
if (g_atomic_int_dec_and_test (&block_notifications)) {
- flush_notifications ();
+ flush_notifications (from_undo);
}
}
list< Evoral::RangeMove<framepos_t> > m;
m.push_back (move);
- RangesMoved (m);
+ RangesMoved (m, false);
}
}
/* the length change might not be true, but we have to act
as though it could be.
*/
-
+
if (holding_state()) {
pending_adds.insert (r);
pending_contents_change = true;
pending_length = true;
} else {
+ r->clear_changes ();
pending_length = false;
LengthChanged (); /* EMIT SIGNAL */
pending_contents_change = false;
}
}
+/** @param from_undo true if this flush is triggered by the end of an undo on this playlist */
void
-Playlist::flush_notifications ()
+Playlist::flush_notifications (bool from_undo)
{
set<boost::shared_ptr<Region> > dependent_checks_needed;
set<boost::shared_ptr<Region> >::iterator s;
for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
// cerr << _name << " sends RegionAdded\n";
- RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
+ /* don't emit RegionAdded signal until relayering is done,
+ so that the region is fully setup by the time
+ anyone hear's that its been added
+ */
dependent_checks_needed.insert (*s);
}
// cerr << _name << "done contents change @ " << get_microseconds() << endl;
}
+ for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
+ (*s)->clear_changes ();
+ RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
+ }
+
for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
check_dependents (*s, false);
}
if (!pending_range_moves.empty ()) {
- // cerr << _name << " sends RangesMoved\n";
- RangesMoved (pending_range_moves);
+ RangesMoved (pending_range_moves, from_undo);
}
clear_pending ();
framepos_t pos = position;
if (times == 1 && auto_partition){
- partition(pos, (pos + region->length()), true);
+ partition(pos - 1, (pos + region->length()), true);
}
if (itimes >= 1) {
*/
for (int i = 0; i < itimes; ++i) {
- boost::shared_ptr<Region> copy = RegionFactory::create (region);
+ boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
add_region_internal (copy, pos);
pos += region->length();
}
}
}
- /* XXX and thaw ... */
-
- return ret;
+ return -1;
}
void
while (itimes--) {
for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
- boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
+ boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i, true);
/* put these new regions on top of all existing ones, but preserve
the ordering they had in the original playlist.
*/
copy_of_region->set_layer (copy_of_region->layer() + top_layer);
- add_region_internal (copy_of_region, copy_of_region->position() + pos);
+ add_region_internal (copy_of_region, (*i)->position() + pos);
}
pos += shift;
}
RegionLock rl (this);
int itimes = (int) floor (times);
- framepos_t pos = position;
+ framepos_t pos = position + 1;
while (itimes--) {
- boost::shared_ptr<Region> copy = RegionFactory::create (region);
+ boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
add_region_internal (copy, pos);
pos += region->length();
}
has to be done separately.
*/
- if (!ignore_music_glue && (*r)->positional_lock_style() != Region::AudioTime) {
+ if (!ignore_music_glue && (*r)->position_lock_style() != AudioTime) {
fixup.push_back (*r);
continue;
}
{
PropertyList plist;
- plist.add (Properties::start, region->start());
plist.add (Properties::length, before);
plist.add (Properties::name, before_name);
plist.add (Properties::left_of_split, true);
-
- left = RegionFactory::create (region, plist);
+
+ /* note: we must use the version of ::create with an offset here,
+ since it supplies that offset to the Region constructor, which
+ is necessary to get audio region gain envelopes right.
+ */
+ left = RegionFactory::create (region, 0, plist);
}
RegionFactory::region_name (after_name, region->name(), false);
{
PropertyList plist;
- plist.add (Properties::start, region->start() + before);
plist.add (Properties::length, after);
plist.add (Properties::name, after_name);
plist.add (Properties::right_of_split, true);
- right = RegionFactory::create (region, plist);
+ /* same note as above */
+ right = RegionFactory::create (region, before, plist);
}
add_region_internal (left, region->position());
framepos_t new_pos = (*i)->position() + distance;
if (new_pos < 0) {
new_pos = 0;
- } else if (new_pos >= max_frames - (*i)->length()) {
- new_pos = max_frames - (*i)->length();
+ } else if (new_pos >= max_framepos - (*i)->length()) {
+ new_pos = max_framepos - (*i)->length();
}
(*i)->set_position (new_pos, this);
check_dependents (region, false);
}
- if (what_changed.contains (Properties::position)) {
+ if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
notify_region_moved (region);
}
return find_regions_at (frame);
}
+uint32_t
+Playlist::count_regions_at (framepos_t frame)
+{
+ RegionLock rlock (this);
+ uint32_t cnt = 0;
+
+ for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+ if ((*i)->covers (frame)) {
+ cnt++;
+ }
+ }
+
+ return cnt;
+}
+
boost::shared_ptr<Region>
Playlist::top_region_at (framepos_t frame)
{
RegionLock rlock (this);
boost::shared_ptr<Region> ret;
- framepos_t closest = max_frames;
+ framepos_t closest = max_framepos;
bool end_iter = false;
break;
case SyncPoint:
pos = r->sync_position ();
- // r->adjust_to_sync (r->first_frame());
break;
}
{
RegionLock rlock (this);
- framepos_t closest = max_frames;
+ framepos_t closest = max_framepos;
framepos_t ret = -1;
if (dir > 0) {
return ret;
}
+
/***********************************************************************/
}
}
-bool
-Playlist::set_property (const PropertyBase& prop)
-{
- if (prop == Properties::regions.property_id) {
- const RegionListProperty::ChangeRecord& change (dynamic_cast<const RegionListProperty*>(&prop)->change());
- regions.update (change);
- return (!change.added.empty() && !change.removed.empty());
- }
- return false;
-}
-
void
-Playlist::rdiff (vector<StatefulDiffCommand*>& cmds) const
+Playlist::rdiff (vector<Command*>& cmds) const
{
RegionLock rlock (const_cast<Playlist *> (this));
-
- for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
- if ((*i)->changed ()) {
- StatefulDiffCommand* sdc = new StatefulDiffCommand (*i);
- cmds.push_back (sdc);
- }
- }
+ Stateful::rdiff (cmds);
}
void
-Playlist::clear_owned_history ()
+Playlist::clear_owned_changes ()
{
RegionLock rlock (this);
-
- for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
- (*i)->clear_history ();
- }
+ Stateful::clear_owned_changes ();
}
void
thaw ();
}
-PropertyList*
-Playlist::property_factory (const XMLNode& history_node) const
-{
- const XMLNodeList& children (history_node.children());
- PropertyList* prop_list = 0;
-
- for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
-
- if ((*i)->name() == capitalize (regions.property_name())) {
-
- RegionListProperty* rlp = new RegionListProperty (*const_cast<Playlist*> (this));
-
- if (rlp->load_history_state (**i)) {
- if (!prop_list) {
- prop_list = new PropertyList();
- }
- prop_list->add (rlp);
- } else {
- delete rlp;
- }
- }
- }
-
- return prop_list;
-}
-
int
Playlist::set_state (const XMLNode& node, int version)
{
error << _("Playlist: cannot create region from XML") << endmsg;
continue;
}
-
+
+
add_region (region, region->position(), 1.0);
// So that layer_op ordering doesn't get screwed up
Playlist::state (bool full_state)
{
XMLNode *node = new XMLNode (X_("Playlist"));
- char buf[64];
+ char buf[64] = "";
node->add_property (X_("id"), id().to_s());
node->add_property (X_("name"), _name);
if (full_state) {
RegionLock rlock (this, false);
+
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
node->add_child_nocopy ((*i)->get_state());
}
return regions.size();
}
-pair<framecnt_t, framecnt_t>
+pair<framepos_t, framepos_t>
Playlist::get_extent () const
{
RegionLock rlock (const_cast<Playlist *>(this), false);
return _get_extent ();
}
-pair<framecnt_t, framecnt_t>
+pair<framepos_t, framepos_t>
Playlist::_get_extent () const
{
- pair<framecnt_t, framecnt_t> ext (max_frames, 0);
+ pair<framepos_t, framepos_t> ext (max_framepos, 0);
for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
- pair<framecnt_t, framecnt_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
+ pair<framepos_t, framepos_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
if (e.first < ext.first) {
ext.first = e.first;
}
void
Playlist::raise_region (boost::shared_ptr<Region> region)
{
- uint32_t rsz = regions.size();
+ uint32_t top = regions.size() - 1;
layer_t target = region->layer() + 1U;
- if (target >= rsz) {
+ if (target >= top) {
/* its already at the effective top */
return;
}
}
}
+ freeze ();
+
/* now reset the layers without holding the region lock */
for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
region->set_layer (target_layer);
-#if 0
- /* now check all dependents */
+ /* now check all dependents, since we changed the layering */
for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
check_dependents (x->first, false);
}
check_dependents (region, false);
-#endif
+ notify_layering_changed ();
+
+ thaw ();
return 0;
}
if (forwards) {
- if ((*i)->last_frame() > max_frames - distance) {
- new_pos = max_frames - (*i)->length();
+ if ((*i)->last_frame() > max_framepos - distance) {
+ new_pos = max_framepos - (*i)->length();
} else {
new_pos = (*i)->position() + distance;
}
return boost::shared_ptr<Region> ();
}
+uint32_t
+Playlist::region_use_count (boost::shared_ptr<Region> r) const
+{
+ RegionLock rlock (const_cast<Playlist*> (this));
+ uint32_t cnt = 0;
+
+ for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
+ if ((*i) == r) {
+ cnt++;
+ }
+ }
+
+ return cnt;
+}
+
boost::shared_ptr<Region>
-Playlist::region_by_id (const ID& id)
+Playlist::region_by_id (const ID& id) const
{
/* searches all regions ever added to this playlist */
i = j;
}
}
+
+/** Look from a session frame time and find the start time of the next region
+ * which is on the top layer of this playlist.
+ * @param t Time to look from.
+ * @return Position of next top-layered region, or max_framepos if there isn't one.
+ */
+framepos_t
+Playlist::find_next_top_layer_position (framepos_t t) const
+{
+ RegionLock rlock (const_cast<Playlist *> (this));
+
+ layer_t const top = top_layer ();
+
+ RegionList copy = regions.rlist ();
+ copy.sort (RegionSortByPosition ());
+
+ for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
+ if ((*i)->position() >= t && (*i)->layer() == top) {
+ return (*i)->position();
+ }
+ }
+
+ return max_framepos;
+}