*/
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
#include <set>
#include <fstream>
#include <algorithm>
}
void
-RegionListProperty::diff (PropertyList& undo, PropertyList& redo) const
+RegionListProperty::diff (PropertyList& undo, PropertyList& redo, Command* cmd) const
{
if (changed()) {
/* list of the removed/added regions since clear_history() was last called */
RegionListProperty* b = copy_for_history ();
b->invert_changes ();
+ if (cmd) {
+ /* whenever one of the regions emits DropReferences, make sure
+ that the Destructible we've been told to notify hears about
+ it. the Destructible is likely to be the Command being built
+ with this diff().
+ */
+
+ for (set<boost::shared_ptr<Region> >::iterator i = a->change().added.begin(); i != a->change().added.end(); ++i) {
+ (*i)->DropReferences.connect_same_thread (*cmd, boost::bind (&Destructible::drop_references, cmd));
+ }
+ }
+
undo.add (b);
redo.add (a);
}
, _type(type)
{
+#ifndef NDEBUG
const XMLProperty* prop = node.property("type");
assert(!prop || DataType(prop->value()) == _type);
+#endif
init (hide);
_name = "unnamed"; /* reset by set_state */
: SessionObject(other->_session, namestr)
, regions (*this)
, _type(other->_type)
- , _orig_diskstream_id(other->_orig_diskstream_id)
+ , _orig_diskstream_id (other->_orig_diskstream_id)
{
init (hide);
: SessionObject(other->_session, str)
, regions (*this)
, _type(other->_type)
- , _orig_diskstream_id(other->_orig_diskstream_id)
+ , _orig_diskstream_id (other->_orig_diskstream_id)
{
RegionLock rlock2 (const_cast<Playlist*> (other.get()));
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);
}
Playlist::delay_notifications ()
{
g_atomic_int_inc (&block_notifications);
- freeze_length = _get_maximum_extent();
+ 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);
}
}
pending_contents_change = true;
pending_length = true;
} else {
+ r->clear_history ();
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;
if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) {
regions_changed = true;
if (!pending_length) {
- old_length = _get_maximum_extent ();
+ old_length = _get_extent ().second;
check_length = true;
}
}
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);
}
if (check_length) {
- if (old_length != _get_maximum_extent()) {
+ if (old_length != _get_extent().second) {
pending_length = true;
// cerr << _name << " length has changed\n";
}
}
- if (pending_length || (freeze_length != _get_maximum_extent())) {
+ if (pending_length || (freeze_length != _get_extent().second)) {
pending_length = false;
// cerr << _name << " sends LengthChanged\n";
LengthChanged(); /* EMIT SIGNAL */
// cerr << _name << "done contents change @ " << get_microseconds() << endl;
}
+ for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
+ (*s)->clear_history ();
+ 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) {
framecnt_t old_length = 0;
if (!holding_state()) {
- old_length = _get_maximum_extent();
+ old_length = _get_extent().second;
}
if (!first_set_state) {
check_dependents (region, false);
- if (old_length != _get_maximum_extent()) {
+ if (old_length != _get_extent().second) {
notify_length_changed ();
}
}
int ret = -1;
if (!holding_state()) {
- old_length = _get_maximum_extent();
+ old_length = _get_extent().second;
}
if (!in_set_state) {
relayer ();
remove_dependents (region);
- if (old_length != _get_maximum_extent()) {
+ if (old_length != _get_extent().second) {
notify_length_changed ();
}
}
}
}
- /* XXX and thaw ... */
-
- return ret;
+ return -1;
}
void
current->suspend_property_changes ();
thawlist.push_back (current);
- current->trim_end (pos2, this);
+ current->cut_end (pos2 - 1, this);
} else if (overlap == OverlapEnd) {
current->suspend_property_changes ();
thawlist.push_back (current);
- current->trim_end (pos2, this);
+ current->cut_end (pos2 - 1, this);
} else if (overlap == OverlapStart) {
new_name += '.';
new_name += buf;
- cnt = min (_get_maximum_extent() - start, cnt);
+ cnt = min (_get_extent().second - start, cnt);
return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
}
RegionLock rl1 (this);
RegionLock rl2 (other.get());
- framecnt_t old_length = _get_maximum_extent();
+ framecnt_t const old_length = _get_extent().second;
int itimes = (int) floor (times);
framepos_t pos = position;
- framecnt_t shift = other->_get_maximum_extent();
+ framecnt_t const shift = other->_get_extent().second;
layer_t top_layer = regions.size();
while (itimes--) {
/* XXX shall we handle fractional cases at some point? */
- if (old_length != _get_maximum_extent()) {
+ if (old_length != _get_extent().second) {
notify_length_changed ();
}
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);
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;
}
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);
}
to_check.insert (start);
to_check.insert (end);
+ DEBUG_TRACE (DEBUG::AudioPlayback, ">>>>> REGIONS TO READ\n");
+
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
/* find all/any regions that span start+end */
case OverlapInternal:
covering.push_back (*i);
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OInternal)\n", (*i)->name()));
break;
case OverlapStart:
to_check.insert ((*i)->position());
+ if ((*i)->position() != 0) {
+ to_check.insert ((*i)->position()-1);
+ }
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
covering.push_back (*i);
break;
case OverlapEnd:
to_check.insert ((*i)->last_frame());
+ to_check.insert ((*i)->last_frame()+1);
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OEnd)\n", (*i)->name()));
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
covering.push_back (*i);
break;
case OverlapExternal:
covering.push_back (*i);
to_check.insert ((*i)->position());
+ if ((*i)->position() != 0) {
+ to_check.insert ((*i)->position()-1);
+ }
to_check.insert ((*i)->last_frame());
+ to_check.insert ((*i)->last_frame()+1);
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OExt)\n", (*i)->name()));
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
break;
}
if (covering.size() == 1) {
rlist->push_back (covering.front());
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Just one covering region (%1)\n", covering.front()->name()));
} else {
here.clear ();
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t));
+
for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
if ((*x)->covers (*t)) {
here.push_back (*x);
- }
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n",
+ (*x)->name(),
+ (*t)));
+ } else {
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n",
+ (*x)->name(),
+ (*t)));
+ }
+
}
RegionSortByLayer cmp;
if ((*c)->opaque()) {
/* the other regions at this position are hidden by this one */
-
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n",
+ (*c)->name()));
break;
}
}
}
}
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size()));
+
return rlist;
}
return ret;
}
+
/***********************************************************************/
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();
}
-framecnt_t
-Playlist::get_maximum_extent () const
+pair<framecnt_t, framecnt_t>
+Playlist::get_extent () const
{
RegionLock rlock (const_cast<Playlist *>(this), false);
- return _get_maximum_extent ();
+ return _get_extent ();
}
-framecnt_t
-Playlist::_get_maximum_extent () const
+pair<framecnt_t, framecnt_t>
+Playlist::_get_extent () const
{
- RegionList::const_iterator i;
- framecnt_t max_extent = 0;
- framepos_t end = 0;
+ pair<framecnt_t, framecnt_t> ext (max_frames, 0);
- for (i = regions.begin(); i != regions.end(); ++i) {
- if ((end = (*i)->position() + (*i)->length()) > max_extent) {
- max_extent = end;
+ for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
+ pair<framecnt_t, framecnt_t> const e ((*i)->position(), (*i)->position() + (*i)->length());
+ if (e.first < ext.first) {
+ ext.first = e.first;
+ }
+ if (e.second > ext.second) {
+ ext.second = e.second;
}
}
- return max_extent;
+ return ext;
}
string
string newname = name;
do {
- newname = bump_name_once (newname);
+ newname = bump_name_once (newname, '.');
} while (session.playlists->by_name (newname)!=NULL);
return newname;
int const divisions = 512;
/* find the start and end positions of the regions on this playlist */
- framepos_t start = UINT_MAX;
+ framepos_t start = INT64_MAX;
framepos_t end = 0;
for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
start = min (start, (*i)->position());
/* reset the pending explicit relayer flag for every region, now that we're relayering */
(*i)->set_pending_explicit_relayer (false);
- /* find the time divisions that this region covers */
- int const start_division = floor ( ((*i)->position() - start) / division_size);
- int end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
- if (end_division == divisions) {
- end_division--;
+ /* find the time divisions that this region covers; if there are no regions on the list,
+ division_size will equal 0 and in this case we'll just say that
+ start_division = end_division = 0.
+ */
+ int start_division = 0;
+ int end_division = 0;
+
+ if (division_size > 0) {
+ start_division = floor ( ((*i)->position() - start) / division_size);
+ end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
+ if (end_division == divisions) {
+ end_division--;
+ }
}
- assert (end_division < divisions);
+ assert (divisions == 0 || end_division < divisions);
/* find the lowest layer that this region can go on */
size_t j = layers.size();
Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
{
/* does nothing useful if layering mode is later=higher */
- if ((_session.config.get_layer_model() == MoveAddHigher) ||
- (_session.config.get_layer_model() == AddHigher)) {
- timestamp_layer_op (region);
- relayer ();
+ switch (_session.config.get_layer_model()) {
+ case LaterHigher:
+ return;
+ default:
+ break;
+ }
+
+ layer_t top = regions.size() - 1;
+
+ if (region->layer() >= top) {
+ /* already on the top */
+ return;
}
+
+ move_region_to_layer (top, region, 1);
+ /* mark the region's last_layer_op as now, so that it remains on top when
+ doing future relayers (until something else takes over)
+ */
+ timestamp_layer_op (region);
}
void
Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
{
/* does nothing useful if layering mode is later=higher */
- if ((_session.config.get_layer_model() == MoveAddHigher) ||
- (_session.config.get_layer_model() == AddHigher)) {
- region->set_last_layer_op (0);
- relayer ();
+ switch (_session.config.get_layer_model()) {
+ case LaterHigher:
+ return;
+ default:
+ break;
}
+
+ if (region->layer() == 0) {
+ /* already on the bottom */
+ return;
+ }
+
+ move_region_to_layer (0, region, -1);
+ /* force region's last layer op to zero so that it stays at the bottom
+ when doing future relayers
+ */
+ region->set_last_layer_op (0);
}
int
void
Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
{
-// struct timeval tv;
-// gettimeofday (&tv, 0);
region->set_last_layer_op (++layer_op_counter);
}
return (i != regions.end());
}
+
+/** Remove any region that uses a given source */
+void
+Playlist::remove_region_by_source (boost::shared_ptr<Source> s)
+{
+ RegionLock rl (this);
+
+ RegionList::iterator i = regions.begin();
+ while (i != regions.end()) {
+ RegionList::iterator j = i;
+ ++j;
+
+ if ((*i)->uses_source (s)) {
+ remove_region_internal (*i);
+ }
+
+ i = j;
+ }
+}