*/
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
#include <set>
#include <fstream>
#include <algorithm>
}
void
-RegionListProperty::diff (PropertyList& before, PropertyList& after) const
+RegionListProperty::diff (PropertyList& undo, PropertyList& redo, Command* cmd) const
{
- if (_have_old) {
+ if (changed()) {
+ /* list of the removed/added regions since clear_history() was last called */
RegionListProperty* a = copy_for_history ();
- RegionListProperty* b = copy_for_history ();
+ /* the same list, but with removed/added lists swapped (for undo purposes) */
+ RegionListProperty* b = copy_for_history ();
b->invert_changes ();
- before.add (b);
- after.add (a);
+ 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()));
break;
}
- _session.region_name (new_name, region->name(), false);
+ RegionFactory::region_name (new_name, region->name(), false);
PropertyList plist;
Playlist::delay_notifications ()
{
g_atomic_int_inc (&block_notifications);
- freeze_length = _get_maximum_extent();
+ freeze_length = _get_extent().second;
}
void
pending_contents_change = true;
pending_length = true;
} else {
+ r->clear_history ();
pending_length = false;
LengthChanged (); /* EMIT SIGNAL */
pending_contents_change = false;
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 (floor (times) != times) {
length = (framecnt_t) floor (region->length() * (times - floor (times)));
string name;
- _session.region_name (name, region->name(), false);
+ RegionFactory::region_name (name, region->name(), false);
{
PropertyList plist;
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 ();
}
}
if (!cutting) {
/* "middle" ++++++ */
- _session.region_name (new_name, current->name(), false);
+ RegionFactory::region_name (new_name, current->name(), false);
PropertyList plist;
/* "end" ====== */
- _session.region_name (new_name, current->name(), false);
+ RegionFactory::region_name (new_name, current->name(), false);
PropertyList plist;
current->suspend_property_changes ();
thawlist.push_back (current);
- current->trim_end (pos2, this);
+ current->cut_end (pos2 - 1, this);
} else if (overlap == OverlapEnd) {
/* end +++++ */
- _session.region_name (new_name, current->name(), false);
+ RegionFactory::region_name (new_name, current->name(), false);
PropertyList plist;
current->suspend_property_changes ();
thawlist.push_back (current);
- current->trim_end (pos2, this);
+ current->cut_end (pos2 - 1, this);
} else if (overlap == OverlapStart) {
if (!cutting) {
/* front **** */
- _session.region_name (new_name, current->name(), false);
+ RegionFactory::region_name (new_name, current->name(), false);
PropertyList plist;
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 ();
}
if (floor (times) != times) {
framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
string name;
- _session.region_name (name, region->name(), false);
+ RegionFactory::region_name (name, region->name(), false);
{
PropertyList plist;
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;
}
before = playlist_position - region->position();
after = region->length() - before;
- _session.region_name (before_name, region->name(), false);
+ RegionFactory::region_name (before_name, region->name(), false);
{
PropertyList plist;
left = RegionFactory::create (region, plist);
}
- _session.region_name (after_name, region->name(), false);
+ RegionFactory::region_name (after_name, region->name(), false);
{
PropertyList plist;
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 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;
void
Playlist::relayer ()
{
- /* never compute layers when changing state for undo/redo or setting from XML*/
+ /* never compute layers when changing state for undo/redo or setting from XML */
if (in_update || in_set_state) {
return;
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;
+ }
+}