X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudio_playlist.cc;h=b62aeb3ee7ddadb9bf6a5d0fe70a70303565a45d;hb=cfe9ae636e0ee61cafdff43b3bd6967d835ef629;hp=07a6d099eaa34b43408968d066299e684ba55ac4;hpb=aa6adacc7505005305d922847ef0e33378314ecd;p=ardour.git diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index 07a6d099ea..b62aeb3ee7 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,7 +109,9 @@ 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--; } @@ -124,7 +127,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 +172,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; @@ -206,29 +209,22 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr other, fram } case OverlapStart: { - position = region->position() - start; - len = end - region->position(); - - if (end > region->position() + region->fade_in().back()->when) - fade_in_len = 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_len = region->fade_out().back()->when - ( region->last_frame() - end ); //end is inside the fadeout, preserve the fades endpoint + 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; - - if (start < region->last_frame() - region->fade_out().back()->when) //start is before fade-out, preserve the fadeout - fade_out_len = region->fade_out().back()->when; - - if (start < region->position() + region->fade_in().back()->when) - fade_in_len = region->fade_in().back()->when - (start - region->position()); //end is inside the fade-in, preserve the fade-in endpoint + 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; @@ -265,6 +261,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. @@ -287,11 +286,6 @@ 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); @@ -311,9 +305,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)))); } } @@ -330,6 +332,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]); @@ -338,16 +342,12 @@ 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. - */ } } @@ -573,7 +573,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); } @@ -584,7 +585,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; @@ -712,7 +714,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 (); @@ -964,3 +968,232 @@ 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)); + } +}