#include "ardour/audioplaylist.h"
#include "ardour/audioregion.h"
#include "ardour/crossfade.h"
+#include "ardour/region_sorters.h"
#include "ardour/session.h"
#include "pbd/enumwriter.h"
: SequenceProperty<std::list<boost::shared_ptr<Crossfade> > > (Properties::crossfades.property_id, boost::bind (&AudioPlaylist::update, &pl, _1))
, _playlist (pl)
{
-
+
}
CrossfadeListProperty::CrossfadeListProperty (CrossfadeListProperty const & p)
add_property (_crossfades);
in_set_state++;
- set_state (node, Stateful::loading_state_version);
+ if (set_state (node, Stateful::loading_state_version)) {
+ throw failed_constructor();
+ }
in_set_state--;
+
+ relayer ();
}
AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
, _crossfades (*this)
{
add_property (_crossfades);
-
+
RegionList::const_iterator in_o = other->regions.begin();
RegionList::iterator in_n = regions.begin();
{
RegionLock rlock2 (const_cast<AudioPlaylist*> (other.get()));
in_set_state++;
-
+
add_property (_crossfades);
framepos_t const end = start + cnt - 1;
framecnt_t fade_in = 64;
framecnt_t fade_out = 64;
- framepos_t position;
- framecnt_t len;
- frameoffset_t offset;
switch (region->coverage (start, end)) {
case OverlapNone:
}
case OverlapStart: {
- position = region->position() - start;
- len = end - region->position();
-
if (end > region->position() + region->fade_in()->back()->when)
fade_in = region->fade_in()->back()->when; //end is after fade-in, preserve the fade-in
if (end > region->last_frame() - region->fade_out()->back()->when)
fade_out = region->fade_out()->back()->when - ( region->last_frame() - end ); //end is inside the fadeout, preserve the fades endpoint
break;
}
-
- case OverlapEnd: {
- position = 0;
- offset = start - region->position();
- len = region->length() - offset;
+ case OverlapEnd: {
if (start < region->last_frame() - region->fade_out()->back()->when) //start is before fade-out, preserve the fadeout
fade_out = region->fade_out()->back()->when;
-
+
if (start < region->position() + region->fade_in()->back()->when)
fade_in = region->fade_in()->back()->when - (start - region->position()); //end is inside the fade-in, preserve the fade-in endpoint
break;
}
-
+
case OverlapExternal:
fade_in = region->fade_in()->back()->when;
fade_out = region->fade_out()->back()->when;
{
framecnt_t ret = cnt;
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Playlist %1 read @ %2 for %3, channel %4, regions %5 xfades %6\n",
+ name(), start, cnt, chan_n, regions.size(), _crossfades.size()));
+
/* optimizing this memset() away involves a lot of conditionals
that may well cause more of a hit due to cache misses
and related stuff than just doing this here.
Glib::RecMutex::Lock rm (region_lock);
framepos_t const end = start + cnt - 1;
- framecnt_t read_frames = 0;
- framecnt_t skip_frames = 0;
- _read_data_count = 0;
-
- _read_data_count = 0;
- RegionList* rlist = regions_to_read (start, start+cnt);
+ boost::shared_ptr<RegionList> rlist = regions_to_read (start, start+cnt);
if (rlist->empty()) {
- delete rlist;
return cnt;
}
}
}
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Checking %1 xfades\n", _crossfades.size()));
+
for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 check xfade between %2 and %3 ... [ %4 ... %5 | %6 ... %7]\n",
+ name(), (*i)->out()->name(), (*i)->in()->name(),
+ (*i)->first_frame(), (*i)->last_frame(),
+ start, end));
if ((*i)->coverage (start, end) != OverlapNone) {
relevant_xfades[(*i)->upper_layer()].push_back (*i);
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\t\txfade is relevant (coverage = %2), place on layer %1\n",
+ (*i)->upper_layer(), enum_2_string ((*i)->coverage (start, end))));
}
}
for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read for layer %1\n", *l));
+
vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
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();
+ ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
}
for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
+ DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from xfade between %1 & %2\n", (*i)->out()->name(), (*i)->in()->name()));
(*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
-
- /* don't JACK up _read_data_count, since its the same data as we just
- read from the regions, and the OS should handle that for us.
- */
}
}
- delete rlist;
return ret;
}
boost::shared_ptr<AudioRegion> top;
boost::shared_ptr<AudioRegion> bottom;
boost::shared_ptr<Crossfade> xfade;
- RegionList* touched_regions = 0;
+ boost::shared_ptr<RegionList> touched_regions;
if (in_set_state || in_partition) {
return;
OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
- delete touched_regions;
- touched_regions = 0;
+ touched_regions.reset ();
try {
framecnt_t xfade_length;
if (top_region_at (top->first_frame()) == top) {
- xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
+ xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, StartOfIn));
+ xfade->set_position (top->first_frame());
add_crossfade (xfade);
}
would cover it).
*/
- xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
+ xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, EndOfOut));
+ xfade->set_position (top->last_frame() - xfade_length);
add_crossfade (xfade);
}
break;
}
}
-
- delete touched_regions;
}
void
in_set_state++;
- Playlist::set_state (node, version);
+ if (Playlist::set_state (node, version)) {
+ return -1;
+ }
freeze ();
};
void
-AudioPlaylist::copy_dependents (const vector<TwoRegions>& old_and_new, boost::shared_ptr<Playlist> other)
+AudioPlaylist::copy_dependents (const vector<TwoRegions>& old_and_new, Playlist* other) const
{
- boost::shared_ptr<AudioPlaylist> other_audio = boost::dynamic_pointer_cast<AudioPlaylist>(other);
+ AudioPlaylist* other_audio = dynamic_cast<AudioPlaylist*>(other);
if (!other_audio) {
return;
for (vector<TwoRegions>::const_iterator on = old_and_new.begin(); on != old_and_new.end(); ++on) {
- for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
+ for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
if ((*i)->in() == on->first) {
-
+
CrossfadeInfo::iterator cf;
if ((cf = crossfade_info.find (*i)) != crossfade_info.end()) {
- /* already have a record for the old fade-in region,
+ /* already have a record for the old fade-in region,
so note the new fade-in region
*/
-
+
cf->second.new_in = on->second;
-
+
} else {
-
+
/* add a record of this crossfade, keeping an association
with the new fade-in region
*/
-
+
crossfade_triple ct;
-
+
ct.old_in = on->first;
ct.new_in = on->second;
}
} else if ((*i)->out() == on->first) {
-
+
/* this old region is the fade-out region of this crossfade */
-
+
CrossfadeInfo::iterator cf;
-
+
if ((cf = crossfade_info.find (*i)) != crossfade_info.end()) {
-
+
/* already have a record for this crossfade, so just keep
an association for the new fade out region
*/
-
+
cf->second.new_out = on->second;
-
+
} else {
-
+
/* add a record of this crossfade, keeping an association
with the new fade-in region
*/
}
for (CrossfadeInfo::iterator ci = crossfade_info.begin(); ci != crossfade_info.end(); ++ci) {
-
+
/* for each crossfade that involves at least two of the old regions,
create a new identical crossfade with the new regions
*/
-
+
if (!ci->second.new_in || !ci->second.new_out) {
continue;
}
- boost::shared_ptr<Crossfade> new_xfade (new Crossfade (ci->first,
+ boost::shared_ptr<Crossfade> new_xfade (new Crossfade (ci->first,
boost::dynamic_pointer_cast<AudioRegion>(ci->second.new_in),
boost::dynamic_pointer_cast<AudioRegion>(ci->second.new_out)));
-
- /* add it at the right position */
- new_xfade->set_position (new_xfade->position() + (ci->second.new_in->position() - ci->second.old_in->position()), this);
- cerr << "Add new xfade to new playlist @ " << new_xfade->position() << " len " << new_xfade->length()
- << " in = " << new_xfade->in()->name() << " out = " << new_xfade->out()->name() << endl;
+ /* add it at the right position - which must be at the start
+ * of the fade-in region
+ */
+
+ new_xfade->set_position (ci->second.new_in->position());
other_audio->add_crossfade (new_xfade);
}
}
+
+void
+AudioPlaylist::pre_combine (vector<boost::shared_ptr<Region> >& copies)
+{
+ RegionSortByPosition cmp;
+ boost::shared_ptr<AudioRegion> ar;
+
+ sort (copies.begin(), copies.end(), cmp);
+
+ ar = boost::dynamic_pointer_cast<AudioRegion> (copies.front());
+
+ /* disable fade in of the first region */
+
+ if (ar) {
+ ar->set_fade_in_active (false);
+ }
+
+ ar = boost::dynamic_pointer_cast<AudioRegion> (copies.back());
+
+ /* disable fade out of the last region */
+
+ if (ar) {
+ ar->set_fade_out_active (false);
+ }
+}
+
+void
+AudioPlaylist::post_combine (vector<boost::shared_ptr<Region> >& originals, boost::shared_ptr<Region> compound_region)
+{
+ RegionSortByPosition cmp;
+ boost::shared_ptr<AudioRegion> ar;
+ boost::shared_ptr<AudioRegion> cr;
+
+ if ((cr = boost::dynamic_pointer_cast<AudioRegion> (compound_region)) == 0) {
+ return;
+ }
+
+ sort (originals.begin(), originals.end(), cmp);
+
+ ar = boost::dynamic_pointer_cast<AudioRegion> (originals.front());
+
+ /* copy the fade in of the first into the compound region */
+
+ if (ar) {
+ cr->set_fade_in (ar->fade_in());
+ }
+
+ ar = boost::dynamic_pointer_cast<AudioRegion> (originals.back());
+
+ if (ar) {
+ /* copy the fade out of the last into the compound region */
+ cr->set_fade_out (ar->fade_out());
+ }
+}
+
+void
+AudioPlaylist::pre_uncombine (vector<boost::shared_ptr<Region> >& originals, boost::shared_ptr<Region> compound_region)
+{
+ RegionSortByPosition cmp;
+ boost::shared_ptr<AudioRegion> ar;
+ boost::shared_ptr<AudioRegion> cr = boost::dynamic_pointer_cast<AudioRegion>(compound_region);
+
+ if (!cr) {
+ return;
+ }
+
+ sort (originals.begin(), originals.end(), cmp);
+
+ /* no need to call clear_changes() on the originals because that is
+ * done within Playlist::uncombine ()
+ */
+
+ for (vector<boost::shared_ptr<Region> >::iterator i = originals.begin(); i != originals.end(); ++i) {
+
+ if ((ar = boost::dynamic_pointer_cast<AudioRegion> (*i)) == 0) {
+ continue;
+ }
+
+ /* scale the uncombined regions by any gain setting for the
+ * compound one.
+ */
+
+ ar->set_scale_amplitude (ar->scale_amplitude() * cr->scale_amplitude());
+
+ if (i == originals.begin()) {
+
+ /* copy the compound region's fade in back into the first
+ original region.
+ */
+
+ if (cr->fade_in()->back()->when <= ar->length()) {
+ /* don't do this if the fade is longer than the
+ * region
+ */
+ ar->set_fade_in (cr->fade_in());
+ }
+
+
+ } else if (*i == originals.back()) {
+
+ /* copy the compound region's fade out back into the last
+ original region.
+ */
+
+ if (cr->fade_out()->back()->when <= ar->length()) {
+ /* don't do this if the fade is longer than the
+ * region
+ */
+ ar->set_fade_out (cr->fade_out());
+ }
+
+ }
+
+ _session.add_command (new StatefulDiffCommand (*i));
+ }
+}