- // cerr << _name << " sends RegionAdded\n";
- /* 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_extent().second) {
- pending_length = true;
- // cerr << _name << " length has changed\n";
- }
- }
-
- if (pending_length || (freeze_length != _get_extent().second)) {
- pending_length = false;
- // cerr << _name << " sends LengthChanged\n";
- LengthChanged(); /* EMIT SIGNAL */
- }
-
- if (regions_changed || pending_contents_change) {
- if (!in_set_state) {
- relayer ();
- }
- pending_contents_change = false;
- // cerr << _name << " sends 5 contents change @ " << get_microseconds() << endl;
- ContentsChanged (); /* EMIT SIGNAL */
- // 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 ()) {
- RangesMoved (pending_range_moves, from_undo);
- }
-
- if (!pending_region_extensions.empty ()) {
- RegionsExtended (pending_region_extensions);
- }
-
- clear_pending ();
-
- in_flush = false;
-}
-
-void
-Playlist::clear_pending ()
-{
- pending_adds.clear ();
- pending_removes.clear ();
- pending_bounds.clear ();
- pending_range_moves.clear ();
- pending_region_extensions.clear ();
- pending_contents_change = false;
- pending_length = false;
-}
-
-/*************************************************************
- PLAYLIST OPERATIONS
- *************************************************************/
-
-void
-Playlist::add_region (boost::shared_ptr<Region> region, framepos_t position, float times, bool auto_partition)
-{
- RegionLock rlock (this);
- times = fabs (times);
-
- int itimes = (int) floor (times);
-
- framepos_t pos = position;
-
- if (times == 1 && auto_partition){
- partition(pos - 1, (pos + region->length()), true);
- }
-
- if (itimes >= 1) {
- add_region_internal (region, pos);
- pos += region->length();
- --itimes;
- }
-
-
- /* note that itimes can be zero if we being asked to just
- insert a single fraction of the region.
- */
-
- for (int i = 0; i < itimes; ++i) {
- boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
- add_region_internal (copy, pos);
- pos += region->length();
- }
-
- framecnt_t length = 0;
-
- if (floor (times) != times) {
- length = (framecnt_t) floor (region->length() * (times - floor (times)));
- string name;
- RegionFactory::region_name (name, region->name(), false);
-
- {
- PropertyList plist;
-
- plist.add (Properties::start, region->start());
- plist.add (Properties::length, length);
- plist.add (Properties::name, name);
- plist.add (Properties::layer, region->layer());
-
- boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
- add_region_internal (sub, pos);
- }
- }
-
- possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr<Region>());
-}
-
-void
-Playlist::set_region_ownership ()
-{
- RegionLock rl (this);
- RegionList::iterator i;
- boost::weak_ptr<Playlist> pl (shared_from_this());
-
- for (i = regions.begin(); i != regions.end(); ++i) {
- (*i)->set_playlist (pl);
- }
-}
-
-bool
-Playlist::add_region_internal (boost::shared_ptr<Region> region, framepos_t position)
-{
- if (region->data_type() != _type){
- return false;
- }
-
- RegionSortByPosition cmp;
-
- framecnt_t old_length = 0;
-
- if (!holding_state()) {
- old_length = _get_extent().second;
- }
-
- if (!first_set_state) {
- boost::shared_ptr<Playlist> foo (shared_from_this());
- region->set_playlist (boost::weak_ptr<Playlist>(foo));
- }
-
- region->set_position (position);
-
- timestamp_layer_op (region);
-
- regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region);
- all_regions.insert (region);
-
- possibly_splice_unlocked (position, region->length(), region);
-
- if (!holding_state ()) {
- /* layers get assigned from XML state, and are not reset during undo/redo */
- relayer ();
- }
-
- /* we need to notify the existence of new region before checking dependents. Ick. */
-
- notify_region_added (region);
-
-
- if (!holding_state ()) {
-
- check_dependents (region, false);
-
- if (old_length != _get_extent().second) {
- notify_length_changed ();
- }
- }
-
- region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
-
- return true;
-}
-
-void
-Playlist::replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, framepos_t pos)
-{
- RegionLock rlock (this);
-
- bool old_sp = _splicing;
- _splicing = true;
-
- remove_region_internal (old);
- add_region_internal (newr, pos);
-
- _splicing = old_sp;
-
- possibly_splice_unlocked (pos, old->length() - newr->length());
-}
-
-void
-Playlist::remove_region (boost::shared_ptr<Region> region)
-{
- RegionLock rlock (this);
- remove_region_internal (region);
-}
-
-int
-Playlist::remove_region_internal (boost::shared_ptr<Region> region)
-{
- RegionList::iterator i;
- framecnt_t old_length = 0;
- int ret = -1;
-
- if (!holding_state()) {
- old_length = _get_extent().second;
- }
-
- if (!in_set_state) {
- /* unset playlist */
- region->set_playlist (boost::weak_ptr<Playlist>());
- }
-
- /* XXX should probably freeze here .... */
-
- for (i = regions.begin(); i != regions.end(); ++i) {
- if (*i == region) {
-
- framepos_t pos = (*i)->position();
- framecnt_t distance = (*i)->length();
-
- regions.erase (i);
-
- possibly_splice_unlocked (pos, -distance);
-
- if (!holding_state ()) {
- relayer ();
- remove_dependents (region);
-
- if (old_length != _get_extent().second) {
- notify_length_changed ();
- }
- }
-
- notify_region_removed (region);
- ret = 0;
- break;
- }
- }
-
- return -1;
-}
-
-void
-Playlist::get_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
-{
- if (Config->get_use_overlap_equivalency()) {
- for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
- if ((*i)->overlap_equivalent (other)) {
- results.push_back ((*i));
- }
- }
- } else {
- for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
- if ((*i)->equivalent (other)) {
- results.push_back ((*i));
- }
- }
- }
-}
-
-void
-Playlist::get_region_list_equivalent_regions (boost::shared_ptr<Region> other, vector<boost::shared_ptr<Region> >& results)
-{
- for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
-
- if ((*i) && (*i)->region_list_equivalent (other)) {
- results.push_back (*i);
- }
- }
-}
-
-void
-Playlist::partition (framepos_t start, framepos_t end, bool cut)
-{
- RegionList thawlist;
-
- partition_internal (start, end, cut, thawlist);
-
- for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
- (*i)->resume_property_changes ();
- }
-}
-
-void
-Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist)
-{
- RegionList new_regions;
-
- {
- RegionLock rlock (this);
-
- boost::shared_ptr<Region> region;
- boost::shared_ptr<Region> current;
- string new_name;
- RegionList::iterator tmp;
- OverlapType overlap;
- framepos_t pos1, pos2, pos3, pos4;
-
- in_partition = true;
-
- /* need to work from a copy, because otherwise the regions we add during the process
- get operated on as well.
- */
-
- RegionList copy = regions.rlist();
-
- for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
-
- tmp = i;
- ++tmp;
-
- current = *i;
-
- if (current->first_frame() >= start && current->last_frame() < end) {
-
- if (cutting) {
- remove_region_internal (current);
- }
-
- continue;
- }
-
- /* coverage will return OverlapStart if the start coincides
- with the end point. we do not partition such a region,
- so catch this special case.
- */
-
- if (current->first_frame() >= end) {
- continue;
- }
-
- if ((overlap = current->coverage (start, end)) == OverlapNone) {
- continue;
- }
-
- pos1 = current->position();
- pos2 = start;
- pos3 = end;
- pos4 = current->last_frame();
-
- if (overlap == OverlapInternal) {
- /* split: we need 3 new regions, the front, middle and end.
- cut: we need 2 regions, the front and end.
- */
-
- /*
- start end
- ---------------*************************------------
- P1 P2 P3 P4
- SPLIT:
- ---------------*****++++++++++++++++====------------
- CUT
- ---------------*****----------------====------------
-
- */
-
- if (!cutting) {
- /* "middle" ++++++ */
-
- RegionFactory::region_name (new_name, current->name(), false);
-
- PropertyList plist;
-
- plist.add (Properties::start, current->start() + (pos2 - pos1));
- plist.add (Properties::length, pos3 - pos2);
- plist.add (Properties::name, new_name);
- plist.add (Properties::layer, regions.size());
- plist.add (Properties::automatic, true);
- plist.add (Properties::left_of_split, true);
- plist.add (Properties::right_of_split, true);
-
- region = RegionFactory::create (current, plist);
- add_region_internal (region, start);
- new_regions.push_back (region);
- }
-
- /* "end" ====== */
-
- RegionFactory::region_name (new_name, current->name(), false);
-
- PropertyList plist;
-
- plist.add (Properties::start, current->start() + (pos3 - pos1));
- plist.add (Properties::length, pos4 - pos3);
- plist.add (Properties::name, new_name);
- plist.add (Properties::layer, regions.size());
- plist.add (Properties::automatic, true);
- plist.add (Properties::right_of_split, true);
-
- region = RegionFactory::create (current, plist);
-
- add_region_internal (region, end);
- new_regions.push_back (region);
-
- /* "front" ***** */
-
- current->suspend_property_changes ();
- thawlist.push_back (current);
- current->cut_end (pos2 - 1);
-
- } else if (overlap == OverlapEnd) {
-
- /*
- start end
- ---------------*************************------------
- P1 P2 P4 P3
- SPLIT:
- ---------------**************+++++++++++------------
- CUT:
- ---------------**************-----------------------
- */
-
- if (!cutting) {
-
- /* end +++++ */
-
- RegionFactory::region_name (new_name, current->name(), false);
-
- PropertyList plist;
-
- plist.add (Properties::start, current->start() + (pos2 - pos1));
- plist.add (Properties::length, pos4 - pos2);
- plist.add (Properties::name, new_name);
- plist.add (Properties::layer, regions.size());
- plist.add (Properties::automatic, true);
- plist.add (Properties::left_of_split, true);
-
- region = RegionFactory::create (current, plist);
-
- add_region_internal (region, start);
- new_regions.push_back (region);
- }
-
- /* front ****** */
-
- current->suspend_property_changes ();
- thawlist.push_back (current);
- current->cut_end (pos2 - 1);
-
- } else if (overlap == OverlapStart) {
-
- /* split: we need 2 regions: the front and the end.
- cut: just trim current to skip the cut area
- */
-
- /*
- start end
- ---------------*************************------------
- P2 P1 P3 P4
-
- SPLIT:
- ---------------****+++++++++++++++++++++------------
- CUT:
- -------------------*********************------------
-
- */
-
- if (!cutting) {
- /* front **** */
- RegionFactory::region_name (new_name, current->name(), false);
-
- PropertyList plist;
-
- plist.add (Properties::start, current->start());
- plist.add (Properties::length, pos3 - pos1);
- plist.add (Properties::name, new_name);
- plist.add (Properties::layer, regions.size());
- plist.add (Properties::automatic, true);
- plist.add (Properties::right_of_split, true);
-
- region = RegionFactory::create (current, plist);
-
- add_region_internal (region, pos1);
- new_regions.push_back (region);
- }
-
- /* end */
-
- current->suspend_property_changes ();
- thawlist.push_back (current);
- current->trim_front (pos3);
- } else if (overlap == OverlapExternal) {
-
- /* split: no split required.
- cut: remove the region.
- */
-
- /*
- start end
- ---------------*************************------------
- P2 P1 P3 P4
-
- SPLIT:
- ---------------*************************------------
- CUT:
- ----------------------------------------------------
-
- */
-
- if (cutting) {
- remove_region_internal (current);
- }
-
- new_regions.push_back (current);
- }
- }
-
- in_partition = false;
- }
-
- for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
- check_dependents (*i, false);
- }
-}
-
-boost::shared_ptr<Playlist>
-Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t, framecnt_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
-{
- boost::shared_ptr<Playlist> ret;
- boost::shared_ptr<Playlist> pl;
- framepos_t start;
-
- if (ranges.empty()) {
- return boost::shared_ptr<Playlist>();
- }
-
- start = ranges.front().start;
-
- for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
-
- pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
-
- if (i == ranges.begin()) {
- ret = pl;
- } else {
-
- /* paste the next section into the nascent playlist,
- offset to reflect the start of the first range we
- chopped.
- */
-
- ret->paste (pl, (*i).start - start, 1.0f);
- }
- }
-
- return ret;
-}
-
-boost::shared_ptr<Playlist>
-Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
-{
- boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::cut;
- return cut_copy (pmf, ranges, result_is_hidden);
-}
-
-boost::shared_ptr<Playlist>
-Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
-{
- boost::shared_ptr<Playlist> (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::copy;
- return cut_copy (pmf, ranges, result_is_hidden);
-}
-
-boost::shared_ptr<Playlist>
-Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden)
-{
- boost::shared_ptr<Playlist> the_copy;
- RegionList thawlist;
- char buf[32];
-
- snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
- string new_name = _name;
- new_name += '.';
- new_name += buf;
-
- if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
- return boost::shared_ptr<Playlist>();
- }
-
- partition_internal (start, start+cnt-1, true, thawlist);
-
- for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) {
- (*i)->resume_property_changes();
- }
-
- return the_copy;
-}
-
-boost::shared_ptr<Playlist>
-Playlist::copy (framepos_t start, framecnt_t cnt, bool result_is_hidden)
-{
- char buf[32];
-
- snprintf (buf, sizeof (buf), "%" PRIu32, ++subcnt);
- string new_name = _name;
- new_name += '.';
- new_name += buf;
-
- cnt = min (_get_extent().second - start, cnt);
- return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
-}
-
-int
-Playlist::paste (boost::shared_ptr<Playlist> other, framepos_t position, float times)
-{
- times = fabs (times);
-
- {
- RegionLock rl1 (this);
- RegionLock rl2 (other.get());
-
- framecnt_t const old_length = _get_extent().second;
-
- int itimes = (int) floor (times);
- framepos_t pos = position;
- framecnt_t const shift = other->_get_extent().second;
- layer_t top_layer = regions.size();
-
- while (itimes--) {
- for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++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, (*i)->position() + pos);
- }
- pos += shift;
- }
-
-
- /* XXX shall we handle fractional cases at some point? */
-
- if (old_length != _get_extent().second) {
- notify_length_changed ();
- }
-
-
- }
-
- return 0;
-}
-
-
-void
-Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, float times)
-{
- times = fabs (times);
-
- RegionLock rl (this);
- int itimes = (int) floor (times);
- framepos_t pos = position + 1;
-
- while (itimes--) {
- boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
- add_region_internal (copy, pos);
- pos += region->length();
- }
-
- if (floor (times) != times) {
- framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
- string name;
- RegionFactory::region_name (name, region->name(), false);
-
- {
- PropertyList plist;
-
- plist.add (Properties::start, region->start());
- plist.add (Properties::length, length);
- plist.add (Properties::name, name);
-
- boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
- add_region_internal (sub, pos);
- }
- }
-}
-
-void
-Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue)
-{
- RegionLock rlock (this);
- RegionList copy (regions.rlist());
- RegionList fixup;
-
- for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
-
- if ((*r)->last_frame() < at) {
- /* too early */
- continue;
- }
-
- if (at > (*r)->first_frame() && at < (*r)->last_frame()) {
- /* intersected region */
- if (!move_intersected) {
- continue;
- }
- }
-
- /* do not move regions glued to music time - that
- has to be done separately.
- */