X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudio_playlist.cc;h=329a09eba44a55b3655aa107e01164d43f23ea14;hb=baa00942a20856cf332f547086ed5ebd2ff9078e;hp=6653e2f655a58befc923e6cb1f9254618bd8c5b3;hpb=9dc61bff3ae1420e4724b82bcf6da9ead456bf8a;p=ardour.git diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index 6653e2f655..329a09eba4 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -28,7 +28,7 @@ #include "ardour/region_sorters.h" #include "ardour/session.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace ARDOUR; using namespace std; @@ -38,7 +38,7 @@ AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden : Playlist (session, node, DataType::AUDIO, hidden) { #ifndef NDEBUG - const XMLProperty* prop = node.property("type"); + XMLProperty const * prop = node.property("type"); assert(!prop || DataType(prop->value()) == DataType::AUDIO); #endif @@ -63,13 +63,13 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr other, stri { } -AudioPlaylist::AudioPlaylist (boost::shared_ptr other, framepos_t start, framecnt_t cnt, string name, bool hidden) +AudioPlaylist::AudioPlaylist (boost::shared_ptr other, samplepos_t start, samplecnt_t cnt, string name, bool hidden) : Playlist (other, start, cnt, name, hidden) { RegionReadLock rlock2 (const_cast (other.get())); in_set_state++; - framepos_t const end = start + cnt - 1; + samplepos_t const end = start + cnt - 1; /* Audio regions that have been created by the Playlist constructor will currently have the same fade in/out as the regions that they @@ -82,8 +82,8 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr other, fram boost::shared_ptr region = boost::dynamic_pointer_cast (*i); assert (region); - framecnt_t fade_in = 64; - framecnt_t fade_out = 64; + samplecnt_t fade_in = 64; + samplecnt_t fade_out = 64; switch (region->coverage (start, end)) { case Evoral::OverlapNone: @@ -91,8 +91,8 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr other, fram case Evoral::OverlapInternal: { - framecnt_t const offset = start - region->position (); - framecnt_t const trim = region->last_frame() - end; + samplecnt_t const offset = start - region->position (); + samplecnt_t const trim = region->last_sample() - end; if (region->fade_in()->back()->when > offset) { fade_in = region->fade_in()->back()->when - offset; } @@ -105,13 +105,13 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr other, fram case Evoral::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 + if (end > region->last_sample() - region->fade_out()->back()->when) + fade_out = region->fade_out()->back()->when - ( region->last_sample() - end ); //end is inside the fadeout, preserve the fades endpoint break; } case Evoral::OverlapEnd: { - if (start < region->last_frame() - region->fade_out()->back()->when) //start is before fade-out, preserve the fadeout + if (start < region->last_sample() - 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) @@ -151,21 +151,21 @@ struct ReadSorter { /** A segment of region that needs to be read */ struct Segment { - Segment (boost::shared_ptr r, Evoral::Range a) : region (r), range (a) {} - + Segment (boost::shared_ptr r, Evoral::Range a) : region (r), range (a) {} + boost::shared_ptr region; ///< the region - Evoral::Range range; ///< range of the region to read, in session frames + Evoral::Range range; ///< range of the region to read, in session samples }; -/** @param start Start position in session frames. - * @param cnt Number of frames to read. +/** @param start Start position in session samples. + * @param cnt Number of samples to read. */ -ARDOUR::framecnt_t -AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, framepos_t start, - framecnt_t cnt, unsigned chan_n) +ARDOUR::samplecnt_t +AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, samplepos_t start, + samplecnt_t cnt, unsigned chan_n) { - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Playlist %1 read @ %2 for %3, channel %4, regions %5\n", - name(), start, cnt, chan_n, regions.size())); + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Playlist %1 read @ %2 for %3, channel %4, regions %5 mixdown @ %6 gain @ %7\n", + name(), start, cnt, chan_n, regions.size(), mixdown_buffer, gain_buffer)); /* optimizing this memset() away involves a lot of conditionals that may well cause more of a hit due to cache misses @@ -196,9 +196,9 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, fr /* This will be a list of the bits of our read range that we have handled completely (ie for which no more regions need to be read). - It is a list of ranges in session frames. + It is a list of ranges in session samples. */ - Evoral::RangeList done; + Evoral::RangeList done; /* This will be a list of the bits of regions that we need to read */ list to_do; @@ -207,30 +207,39 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, fr for (RegionList::iterator i = all->begin(); i != all->end(); ++i) { boost::shared_ptr ar = boost::dynamic_pointer_cast (*i); + /* muted regions don't figure into it at all */ + if ( ar->muted() ) + continue; + + /* check for the case of solo_selection */ + bool force_transparent = ( _session.solo_selection_active() && SoloSelectedActive() && !SoloSelectedListIncludes( (const Region*) &(**i) ) ); + if ( force_transparent ) + continue; + /* Work out which bits of this region need to be read; first, trim to the range we are reading... */ - Evoral::Range region_range = ar->range (); + Evoral::Range region_range = ar->range (); region_range.from = max (region_range.from, start); region_range.to = min (region_range.to, start + cnt - 1); /* ... and then remove the bits that are already done */ - Evoral::RangeList region_to_do = Evoral::subtract (region_range, done); + Evoral::RangeList region_to_do = Evoral::subtract (region_range, done); /* Make a note to read those bits, adding their bodies (the parts between end-of-fade-in and start-of-fade-out) to the `done' list. */ - Evoral::RangeList::List t = region_to_do.get (); + Evoral::RangeList::List t = region_to_do.get (); - for (Evoral::RangeList::List::iterator j = t.begin(); j != t.end(); ++j) { - Evoral::Range d = *j; + for (Evoral::RangeList::List::iterator j = t.begin(); j != t.end(); ++j) { + Evoral::Range d = *j; to_do.push_back (Segment (ar, d)); if (ar->opaque ()) { /* Cut this range down to just the body and mark it done */ - Evoral::Range body = ar->body_range (); + Evoral::Range body = ar->body_range (); if (body.from < d.to && body.to > d.from) { d.from = max (d.from, body.from); d.to = min (d.to, body.to); @@ -252,198 +261,6 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, fr return cnt; } -void -AudioPlaylist::check_crossfades (Evoral::Range range) -{ - if (in_set_state || in_partition || !_session.config.get_auto_xfade ()) { - return; - } - - boost::shared_ptr starts = regions_with_start_within (range); - boost::shared_ptr ends = regions_with_end_within (range); - - RegionList all = *starts; - std::copy (ends->begin(), ends->end(), back_inserter (all)); - - all.sort (RegionSortByLayer ()); - - set > done_start; - set > done_end; - - for (RegionList::reverse_iterator i = all.rbegin(); i != all.rend(); ++i) { - for (RegionList::reverse_iterator j = all.rbegin(); j != all.rend(); ++j) { - - if (i == j) { - continue; - } - - if ((*i)->muted() || (*j)->muted()) { - continue; - } - - if ((*i)->position() == (*j)->position() && ((*i)->length() == (*j)->length())) { - /* precise overlay: no xfade */ - continue; - } - - if ((*i)->position() == (*j)->position() || ((*i)->last_frame() == (*j)->last_frame())) { - /* starts or ends match: no xfade */ - continue; - } - - boost::shared_ptr top; - boost::shared_ptr bottom; - - if ((*i)->layer() < (*j)->layer()) { - top = boost::dynamic_pointer_cast (*j); - bottom = boost::dynamic_pointer_cast (*i); - } else { - top = boost::dynamic_pointer_cast (*i); - bottom = boost::dynamic_pointer_cast (*j); - } - - if (!top->opaque ()) { - continue; - } - - Evoral::OverlapType const c = top->coverage (bottom->position(), bottom->last_frame()); - - if (c == Evoral::OverlapStart) { - - /* top starts within bottom but covers bottom's end */ - - /* { ==== top ============ } - * [---- bottom -------------------] - */ - - if (done_start.find (top) == done_start.end() && done_end.find (bottom) == done_end.end ()) { - - /* Top's fade-in will cause an implicit fade-out of bottom */ - - if (top->fade_in_is_xfade() && top->fade_in_is_short()) { - - /* its already an xfade. if its - * really short, leave it - * alone. - */ - - } else { - framecnt_t len = 0; - - if (_capture_insertion_underway) { - len = _session.config.get_short_xfade_seconds() * _session.frame_rate(); - } else { - switch (_session.config.get_xfade_model()) { - case FullCrossfade: - len = bottom->last_frame () - top->first_frame (); - top->set_fade_in_is_short (false); - break; - case ShortCrossfade: - len = _session.config.get_short_xfade_seconds() * _session.frame_rate(); - top->set_fade_in_is_short (true); - break; - } - } - - top->set_fade_in_active (true); - top->set_fade_in_is_xfade (true); - - /* XXX may 2012: -3dB and -6dB curves - * are the same right now - */ - - switch (_session.config.get_xfade_choice ()) { - case ConstantPowerMinus3dB: - top->set_fade_in (FadeConstantPower, len); - break; - case ConstantPowerMinus6dB: - top->set_fade_in (FadeConstantPower, len); - break; - case RegionFades: - top->set_fade_in_length (len); - break; - } - } - - done_start.insert (top); - } - - } else if (c == Evoral::OverlapEnd) { - - /* top covers start of bottom but ends within it */ - - /* [---- top ------------------------] - * { ==== bottom ============ } - */ - - if (done_end.find (top) == done_end.end() && done_start.find (bottom) == done_start.end ()) { - /* Top's fade-out will cause an implicit fade-in of bottom */ - - - if (top->fade_out_is_xfade() && top->fade_out_is_short()) { - - /* its already an xfade. if its - * really short, leave it - * alone. - */ - - } else { - framecnt_t len = 0; - - if (_capture_insertion_underway) { - len = _session.config.get_short_xfade_seconds() * _session.frame_rate(); - } else { - switch (_session.config.get_xfade_model()) { - case FullCrossfade: - len = top->last_frame () - bottom->first_frame (); - break; - case ShortCrossfade: - len = _session.config.get_short_xfade_seconds() * _session.frame_rate(); - break; - } - } - - top->set_fade_out_active (true); - top->set_fade_out_is_xfade (true); - - switch (_session.config.get_xfade_choice ()) { - case ConstantPowerMinus3dB: - top->set_fade_out (FadeConstantPower, len); - break; - case ConstantPowerMinus6dB: - top->set_fade_out (FadeConstantPower, len); - break; - case RegionFades: - top->set_fade_out_length (len); - break; - } - } - - done_end.insert (top); - } - } - } - } - - for (RegionList::iterator i = starts->begin(); i != starts->end(); ++i) { - if (done_start.find (*i) == done_start.end()) { - boost::shared_ptr r = boost::dynamic_pointer_cast (*i); - if (r->fade_in_is_xfade()) { - r->set_default_fade_in (); - } - } - } - - for (RegionList::iterator i = ends->begin(); i != ends->end(); ++i) { - if (done_end.find (*i) == done_end.end()) { - boost::shared_ptr r = boost::dynamic_pointer_cast (*i); - if (r->fade_out_is_xfade()) { - r->set_default_fade_out (); - } - } - } -} - void AudioPlaylist::dump () const { @@ -523,6 +340,11 @@ AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared return false; } + PropertyChange bounds; + bounds.add (Properties::start); + bounds.add (Properties::position); + bounds.add (Properties::length); + PropertyChange our_interests; our_interests.add (Properties::fade_in_active); @@ -536,8 +358,8 @@ AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared bool parent_wants_notify; parent_wants_notify = Playlist::region_changed (what_changed, region); - - if (parent_wants_notify || (what_changed.contains (our_interests))) { + /* if bounds changed, we have already done notify_contents_changed ()*/ + if ((parent_wants_notify || what_changed.contains (our_interests)) && !what_changed.contains (bounds)) { notify_contents_changed (); } @@ -675,13 +497,13 @@ AudioPlaylist::load_legacy_crossfades (const XMLNode& node, int version) for (XMLNodeConstIterator i = children.begin(); i != children.end(); ++i) { if ((*i)->name() == X_("Crossfade")) { - XMLProperty* p = (*i)->property (X_("active")); + XMLProperty const * p = (*i)->property (X_("active")); assert (p); - if (!string_is_affirmative (p->value())) { + if (!string_to (p->value())) { continue; } - + if ((p = (*i)->property (X_("in"))) == 0) { continue; } @@ -690,7 +512,7 @@ AudioPlaylist::load_legacy_crossfades (const XMLNode& node, int version) if (!in) { warning << string_compose (_("Legacy crossfade involved an incoming region not present in playlist \"%1\" - crossfade discarded"), - name()) + name()) << endmsg; continue; } @@ -706,7 +528,7 @@ AudioPlaylist::load_legacy_crossfades (const XMLNode& node, int version) if (!out) { warning << string_compose (_("Legacy crossfade involved an outgoing region not present in playlist \"%1\" - crossfade discarded"), - name()) + name()) << endmsg; continue; } @@ -721,11 +543,11 @@ AudioPlaylist::load_legacy_crossfades (const XMLNode& node, int version) if (in->layer() <= out->layer()) { /* incoming region is below the outgoing one, - * so apply a fade out to the outgoing one + * so apply a fade out to the outgoing one */ const XMLNodeList c = (*i)->children (); - + for (XMLNodeConstIterator j = c.begin(); j != c.end(); ++j) { if ((*j)->name() == X_("FadeOut")) { out_a->fade_out()->set_state (**j, version); @@ -733,14 +555,7 @@ AudioPlaylist::load_legacy_crossfades (const XMLNode& node, int version) out_a->inverse_fade_out()->set_state (**j, version); } } - - if ((p = (*i)->property ("follow-overlap")) != 0) { - out_a->set_fade_out_is_short (!string_is_affirmative (p->value())); - } else { - out_a->set_fade_out_is_short (false); - } - - out_a->set_fade_out_is_xfade (true); + out_a->set_fade_out_active (true); } else { @@ -750,7 +565,7 @@ AudioPlaylist::load_legacy_crossfades (const XMLNode& node, int version) */ const XMLNodeList c = (*i)->children (); - + for (XMLNodeConstIterator j = c.begin(); j != c.end(); ++j) { if ((*j)->name() == X_("FadeIn")) { in_a->fade_in()->set_state (**j, version); @@ -758,14 +573,7 @@ AudioPlaylist::load_legacy_crossfades (const XMLNode& node, int version) in_a->inverse_fade_in()->set_state (**j, version); } } - - if ((p = (*i)->property ("follow-overlap")) != 0) { - in_a->set_fade_in_is_short (!string_is_affirmative (p->value())); - } else { - in_a->set_fade_in_is_short (false); - } - - in_a->set_fade_in_is_xfade (true); + in_a->set_fade_in_active (true); } }