X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudio_playlist.cc;h=76d0228547d01f1aae99a151cda1976cc61636c2;hb=204baa31d842d4c2f833d319b6fa55e402a1bfb8;hp=4e15aa70c2d3a89318df3ec9457276f27a155e72;hpb=3ae786bb06c58eee8dcef2b63a1bc871daf6a7ff;p=ardour.git diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index 4e15aa70c2..76d0228547 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -27,6 +27,7 @@ #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" @@ -53,7 +54,7 @@ CrossfadeListProperty::CrossfadeListProperty (AudioPlaylist& pl) : SequenceProperty > > (Properties::crossfades.property_id, boost::bind (&AudioPlaylist::update, &pl, _1)) , _playlist (pl) { - + } CrossfadeListProperty::CrossfadeListProperty (CrossfadeListProperty const & p) @@ -108,8 +109,12 @@ AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden 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) @@ -124,7 +129,7 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr other, stri , _crossfades (*this) { add_property (_crossfades); - + RegionList::const_iterator in_o = other->regions.begin(); RegionList::iterator in_n = regions.begin(); @@ -169,7 +174,7 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr other, fram { RegionLock rlock2 (const_cast (other.get())); in_set_state++; - + add_property (_crossfades); framepos_t const end = start + cnt - 1; @@ -205,28 +210,20 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr other, fram break; } - case OverlapStart: - { - if (region->fade_in()->back()->when > 0) { - fade_in = region->fade_in()->back()->when; - } - if (start > region->last_frame() - region->fade_out()->back()->when) { - fade_out = region->last_frame() - start; - } + case OverlapStart: { + 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: - { - framecnt_t const offset = start - region->position(); - if (region->fade_in()->back()->when > offset) { - fade_in = region->fade_in()->back()->when - offset; - } - if (start > region->last_frame() - region->fade_out()->back()->when) { - fade_out = region->last_frame() - start; - } else { + 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; } @@ -266,6 +263,9 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, fr { 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. @@ -288,16 +288,10 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, fr 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 rlist = regions_to_read (start, start+cnt); if (rlist->empty()) { - delete rlist; return cnt; } @@ -312,9 +306,17 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, fr } } + 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)))); } } @@ -331,6 +333,8 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, fr for (vector::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) { + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read for layer %1\n", *l)); + vector > r (relevant_regions[*l]); vector >& x (relevant_xfades[*l]); @@ -339,20 +343,15 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, fr boost::shared_ptr ar = boost::dynamic_pointer_cast(*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 >::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; } @@ -491,7 +490,7 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) boost::shared_ptr top; boost::shared_ptr bottom; boost::shared_ptr xfade; - RegionList* touched_regions = 0; + boost::shared_ptr touched_regions; if (in_set_state || in_partition) { return; @@ -542,8 +541,7 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) OverlapType c = top->coverage (bottom->position(), bottom->last_frame()); - delete touched_regions; - touched_regions = 0; + touched_regions.reset (); try { framecnt_t xfade_length; @@ -574,7 +572,8 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) if (top_region_at (top->first_frame()) == top) { - xfade = boost::shared_ptr (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn)); + xfade = boost::shared_ptr (new Crossfade (top, bottom, xfade_length, StartOfIn)); + xfade->set_position (top->first_frame()); add_crossfade (xfade); } @@ -585,7 +584,8 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) would cover it). */ - xfade = boost::shared_ptr (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut)); + xfade = boost::shared_ptr (new Crossfade (bottom, top, xfade_length, EndOfOut)); + xfade->set_position (top->last_frame() - xfade_length); add_crossfade (xfade); } break; @@ -654,8 +654,6 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) } } - - delete touched_regions; } void @@ -713,7 +711,9 @@ AudioPlaylist::set_state (const XMLNode& node, int version) in_set_state++; - Playlist::set_state (node, version); + if (Playlist::set_state (node, version)) { + return -1; + } freeze (); @@ -965,3 +965,242 @@ AudioPlaylist::find_crossfade (const PBD::ID& id) const return *i; } + +struct crossfade_triple { + boost::shared_ptr old_in; + boost::shared_ptr new_in; + boost::shared_ptr new_out; +}; + +void +AudioPlaylist::copy_dependents (const vector& old_and_new, Playlist* other) const +{ + AudioPlaylist* other_audio = dynamic_cast(other); + + if (!other_audio) { + return; + } + + /* our argument is a vector of old and new regions. Each old region + might be participant in a crossfade that is already present. Each new + region is a copy of the old region, present in the other playlist. + + our task is to find all the relevant xfades in our playlist (involving + the "old" regions) and place copies of them in the other playlist. + */ + + typedef map,crossfade_triple> CrossfadeInfo; + CrossfadeInfo crossfade_info; + + /* build up a record that links crossfades, old regions and new regions + */ + + for (vector::const_iterator on = old_and_new.begin(); on != old_and_new.end(); ++on) { + + 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, + 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; + + crossfade_info[*i] = ct; + } + + } 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 + */ + + crossfade_triple ct; + + ct.old_in = on->first; + ct.new_out = on->second; + + crossfade_info[*i] = ct; + } + } + } + } + + 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 new_xfade (new Crossfade (ci->first, + boost::dynamic_pointer_cast(ci->second.new_in), + boost::dynamic_pointer_cast(ci->second.new_out))); + + /* 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 >& copies) +{ + RegionSortByPosition cmp; + boost::shared_ptr ar; + + sort (copies.begin(), copies.end(), cmp); + + ar = boost::dynamic_pointer_cast (copies.front()); + + /* disable fade in of the first region */ + + if (ar) { + ar->set_fade_in_active (false); + } + + ar = boost::dynamic_pointer_cast (copies.back()); + + /* disable fade out of the last region */ + + if (ar) { + ar->set_fade_out_active (false); + } +} + +void +AudioPlaylist::post_combine (vector >& originals, boost::shared_ptr compound_region) +{ + RegionSortByPosition cmp; + boost::shared_ptr ar; + boost::shared_ptr cr; + + if ((cr = boost::dynamic_pointer_cast (compound_region)) == 0) { + return; + } + + sort (originals.begin(), originals.end(), cmp); + + ar = boost::dynamic_pointer_cast (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 (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 >& originals, boost::shared_ptr compound_region) +{ + RegionSortByPosition cmp; + boost::shared_ptr ar; + boost::shared_ptr cr = boost::dynamic_pointer_cast(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 >::iterator i = originals.begin(); i != originals.end(); ++i) { + + if ((ar = boost::dynamic_pointer_cast (*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)); + } +} + +void +AudioPlaylist::get_equivalent_crossfades (boost::shared_ptr c, vector > & results) +{ + for (list >::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) { + if ((*i)->equivalent (c)) { + results.push_back (*i); + } + } +}