From a98fa4bc61e26cd94aeb6720325633c4e6618155 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 11 May 2012 21:30:36 +0000 Subject: switch to 5 new fade curves, taken from mixbus2 branch. make xfade context menus functional even though the images are not accurate git-svn-id: svn://localhost/ardour2/branches/3.0@12253 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/audio_region_view.cc | 2 + gtk2_ardour/editor.cc | 218 +++++++++++++---------- gtk2_ardour/editor.h | 10 +- gtk2_ardour/editor_mouse.cc | 11 +- libs/ardour/ardour/audioregion.h | 1 - libs/ardour/ardour/types.h | 6 +- libs/ardour/audio_playlist.cc | 12 +- libs/ardour/audioregion.cc | 356 ++++++++++++++++++------------------- libs/ardour/enums.cc | 6 +- libs/evoral/evoral/ControlList.hpp | 1 + libs/evoral/src/ControlList.cpp | 33 ++-- 11 files changed, 348 insertions(+), 308 deletions(-) diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index 165af74037..d9ad504aee 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -560,6 +560,7 @@ AudioRegionView::reset_fade_in_shape_width (framecnt_t width) } if (audio_region()->fade_in_is_xfade()) { + cerr << "Fade in changed, reset xfade\n"; if (fade_in_handle) { fade_in_handle->hide (); fade_in_shape->hide (); @@ -668,6 +669,7 @@ AudioRegionView::reset_fade_out_shape_width (framecnt_t width) } if (audio_region()->fade_out_is_xfade()) { + cerr << "Fade out changed, reset xfade\n"; if (fade_out_handle) { fade_out_handle->hide (); fade_out_shape->hide (); diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 6dfe47230f..5e3810977c 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -1341,64 +1341,98 @@ Editor::action_pre_activated (Glib::RefPtr const & a) } } -/** Pop up a context menu for when the user clicks on a crossfade */ void -Editor::popup_xfade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type) +Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start) { using namespace Menu_Helpers; - MenuList& items (xfade_context_menu.items()); + void (Editor::*emf)(FadeShape); + std::map* images; + + if (start) { + images = &_xfade_in_images; + emf = &Editor::set_fade_in_shape; + } else { + images = &_xfade_out_images; + emf = &Editor::set_fade_out_shape; + } + + items.push_back ( + ImageMenuElem ( + _("Linear (for highly correlated material)"), + *(*images)[FadeLinear], + sigc::bind (sigc::mem_fun (*this, emf), FadeLinear) + ) + ); + + dynamic_cast(&items.back())->set_always_show_image (); + + items.push_back ( + ImageMenuElem ( + _("ConstantPower"), + *(*images)[FadeConstantPower], + sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower) + )); + + dynamic_cast(&items.back())->set_always_show_image (); + items.push_back ( + ImageMenuElem ( + _("Symmetric"), + *(*images)[FadeSymmetric], + sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric) + ) + ); + + dynamic_cast(&items.back())->set_always_show_image (); + + items.push_back ( + ImageMenuElem ( + _("Slow"), + *(*images)[FadeSlow], + sigc::bind (sigc::mem_fun (*this, emf), FadeSlow) + )); + + dynamic_cast(&items.back())->set_always_show_image (); + + items.push_back ( + ImageMenuElem ( + _("Fast"), + *(*images)[FadeFast], + sigc::bind (sigc::mem_fun (*this, emf), FadeFast) + )); + + dynamic_cast(&items.back())->set_always_show_image (); +} + +/** Pop up a context menu for when the user clicks on a start crossfade */ +void +Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type) +{ + using namespace Menu_Helpers; + + MenuList& items (xfade_in_context_menu.items()); + if (items.empty()) { - items.push_back ( - ImageMenuElem ( - _("Linear (for highly correlated material)"), - *_xfade_images[FadeLinear], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear) - ) - ); - - dynamic_cast(&items.back())->set_always_show_image (); - - items.push_back ( - ImageMenuElem ( - _("ConstantPower (-6dB)"), - *_xfade_images[FadeFast], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast) - )); - - dynamic_cast(&items.back())->set_always_show_image (); - - items.push_back ( - ImageMenuElem ( - _("Linear-dB"), - *_xfade_images[FadeSlow], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow) - ) - ); - - dynamic_cast(&items.back())->set_always_show_image (); - - items.push_back ( - ImageMenuElem ( - _("Smooth"), - *_xfade_images[FadeLogB], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB) - )); - - dynamic_cast(&items.back())->set_always_show_image (); - - items.push_back ( - ImageMenuElem ( - _("Fast"), - *_xfade_images[FadeLogA], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA) - )); - - dynamic_cast(&items.back())->set_always_show_image (); + fill_xfade_menu (items, true); + } + + xfade_in_context_menu.popup (button, time); +} + +/** Pop up a context menu for when the user clicks on an end crossfade */ +void +Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type) +{ + using namespace Menu_Helpers; + + MenuList& items (xfade_out_context_menu.items()); + + if (items.empty()) { + fill_xfade_menu (items, false); } - xfade_context_menu.popup (button, time); + xfade_out_context_menu.popup (button, time); } @@ -1448,36 +1482,34 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i items.push_back ( ImageMenuElem ( - _("Slowest"), - *_fade_in_images[FadeFast], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast) + _("Slow"), + *_fade_in_images[FadeSlow], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow) )); dynamic_cast(&items.back())->set_always_show_image (); items.push_back ( ImageMenuElem ( - _("Slow"), - *_fade_in_images[FadeLogB], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB) + _("Fast"), + *_fade_in_images[FadeFast], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast) )); dynamic_cast(&items.back())->set_always_show_image (); items.push_back ( ImageMenuElem ( - _("Fast"), - *_fade_in_images[FadeLogA], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA) + _("Symmetric"), + *_fade_in_images[FadeSlow], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric) )); - dynamic_cast(&items.back())->set_always_show_image (); - items.push_back ( ImageMenuElem ( - _("Fastest"), - *_fade_in_images[FadeSlow], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow) + _("Constant Power"), + *_fade_in_images[FadeConstantPower], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower) )); dynamic_cast(&items.back())->set_always_show_image (); @@ -1512,8 +1544,8 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i items.push_back ( ImageMenuElem ( - _("Slowest"), - *_fade_out_images[FadeFast], + _("Slow"), + *_fade_out_images[FadeSlow], sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow) )); @@ -1521,27 +1553,25 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i items.push_back ( ImageMenuElem ( - _("Slow"), - *_fade_out_images[FadeLogB], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA) + _("Fast"), + *_fade_out_images[FadeFast], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast) )); dynamic_cast(&items.back())->set_always_show_image (); items.push_back ( ImageMenuElem ( - _("Fast"), - *_fade_out_images[FadeLogA], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB) + _("Symmetric"), + *_fade_out_images[FadeSlow], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric) )); - dynamic_cast(&items.back())->set_always_show_image (); - items.push_back ( ImageMenuElem ( - _("Fastest"), - *_fade_out_images[FadeSlow], - sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast) + _("Constant Power"), + *_fade_out_images[FadeConstantPower], + sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower) )); dynamic_cast(&items.back())->set_always_show_image (); @@ -5345,22 +5375,28 @@ void Editor::setup_fade_images () { _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear"))); - _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-short-cut"))); - _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut"))); - _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut"))); - _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-long-cut"))); + _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut"))); + _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut"))); + _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut"))); + _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut"))); _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear"))); - _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut"))); - _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut"))); - _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut"))); - _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut"))); - - _xfade_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear"))); - _xfade_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut"))); - _xfade_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut"))); - _xfade_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut"))); - _xfade_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut"))); + _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut"))); + _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut"))); + _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut"))); + _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut"))); + + _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear"))); + _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut"))); + _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut"))); + _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut"))); + _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut"))); + + _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear"))); + _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut"))); + _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut"))); + _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut"))); + _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut"))); } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 3c1ebdbd49..2e203e9c75 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1337,8 +1337,11 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD Gtk::Menu fade_context_menu; void popup_fade_context_menu (int, int, ArdourCanvas::Item*, ItemType); - Gtk::Menu xfade_context_menu; - void popup_xfade_context_menu (int, int, ArdourCanvas::Item*, ItemType); + Gtk::Menu xfade_in_context_menu; + Gtk::Menu xfade_out_context_menu; + void popup_xfade_in_context_menu (int, int, ArdourCanvas::Item*, ItemType); + void popup_xfade_out_context_menu (int, int, ArdourCanvas::Item*, ItemType); + void fill_xfade_menu (Gtk::Menu_Helpers::MenuList& items, bool start); void set_fade_in_shape (ARDOUR::FadeShape); void set_fade_out_shape (ARDOUR::FadeShape); @@ -2062,7 +2065,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void setup_fade_images (); std::map _fade_in_images; std::map _fade_out_images; - std::map _xfade_images; + std::map _xfade_in_images; + std::map _xfade_out_images; Gtk::MenuItem& action_menu_item (std::string const &); void action_pre_activated (Glib::RefPtr const &); diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 1724666976..d7d1c34280 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -640,15 +640,12 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp } break; - - case StartCrossFadeItem: - case EndCrossFadeItem: - break; - case FadeInHandleItem: case FadeInItem: case FadeOutHandleItem: case FadeOutItem: + case StartCrossFadeItem: + case EndCrossFadeItem: if (doing_object_stuff() || (mouse_mode != MouseRange && mouse_mode != MouseObject)) { set_selected_regionview_from_click (press, op); } else if (event->type == GDK_BUTTON_PRESS) { @@ -1484,11 +1481,11 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; case StartCrossFadeItem: - popup_xfade_context_menu (1, event->button.time, item, item_type); + popup_xfade_in_context_menu (1, event->button.time, item, item_type); break; case EndCrossFadeItem: - popup_xfade_context_menu (1, event->button.time, item, item_type); + popup_xfade_out_context_menu (1, event->button.time, item, item_type); break; case StreamItem: diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index 013629637d..c03f32cb63 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -180,7 +180,6 @@ class AudioRegion : public Region private: friend class RegionFactory; - friend class Crossfade; AudioRegion (boost::shared_ptr); AudioRegion (const SourceList &); diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 127c840840..6ac9ebfe70 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -557,10 +557,8 @@ namespace ARDOUR { FadeLinear, FadeFast, FadeSlow, - FadeLogA, - FadeLogB, - FadeConstantPowerMinus3dB, - FadeConstantPowerMinus6dB, + FadeConstantPower, + FadeSymmetric, }; } // namespace ARDOUR diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index 867f6f0ce4..9b433d160b 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -328,12 +328,16 @@ AudioPlaylist::check_crossfades (Evoral::Range range) 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 (FadeConstantPowerMinus3dB, len); + top->set_fade_in (FadeConstantPower, len); break; case ConstantPowerMinus6dB: - top->set_fade_in (FadeConstantPowerMinus6dB, len); + top->set_fade_in (FadeConstantPower, len); break; case RegionFades: top->set_fade_in_length (len); @@ -369,10 +373,10 @@ AudioPlaylist::check_crossfades (Evoral::Range range) switch (_session.config.get_xfade_choice ()) { case ConstantPowerMinus3dB: - top->set_fade_out (FadeConstantPowerMinus3dB, len); + top->set_fade_out (FadeConstantPower, len); break; case ConstantPowerMinus6dB: - top->set_fade_out (FadeConstantPowerMinus6dB, len); + top->set_fade_out (FadeConstantPower, len); break; case RegionFades: top->set_fade_out_length (len); diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 066cf368f5..1e85b61ce5 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -65,6 +65,90 @@ namespace ARDOUR { } } +static const double VERY_SMALL_SIGNAL = 0.0000001; //-140dB + +/* Curve manipulations */ + +static void +reverse_curve (boost::shared_ptr dst, boost::shared_ptr src) +{ + size_t len = src->back()->when; + + for (Evoral::ControlList::const_iterator it = src->begin(); it!=src->end(); it++) { + dst->add ( len - (*it)->when, (*it)->value ); + } +} + +static void +generate_inverse_power_curve (boost::shared_ptr dst, boost::shared_ptr src) +{ + //calc inverse curve using sum of squares + for (Evoral::ControlList::const_iterator it = src->begin(); it!=src->end(); ++it ) { + float value = (*it)->value; + value = 1 - powf(value,2); + value = sqrtf(value); + dst->fast_simple_add ( (*it)->when, value ); + } +} + +/* +static void +generate_inverse_coefficient_curve (boost::shared_ptr dst, boost::shared_ptr src) +{ + //calc inverse gain coefficient curve + for (Evoral::ControlList::const_iterator it = src->begin(); it!=src->end(); ++it ) { + float value = 1.0 - (*it)->value; + dst->fast_simple_add ( (*it)->when, value ); + } +} +*/ + +static void +generate_db_fade (boost::shared_ptr dst, double len, int num_steps, float dB_drop) +{ + dst->fast_simple_add (0, 1); + + //generate a fade-out curve by successively applying a gain drop + float fade_speed = dB_to_coefficient(dB_drop / (float) num_steps); + for (int i = 1; i < (num_steps-1); i++) { + float coeff = 1.0; + for (int j = 0; j < i; j++) { + coeff *= fade_speed; + } + dst->fast_simple_add (len*(double)i/(double)num_steps, coeff); + } + + dst->fast_simple_add (len, VERY_SMALL_SIGNAL); +} + +static void +merge_curves (boost::shared_ptr dst, + boost::shared_ptr curve1, + boost::shared_ptr curve2) +{ + Evoral::ControlList::EventList::size_type size = curve1->size(); + + //curve lengths must match for now + if (size != curve2->size()) { + return; + } + + Evoral::ControlList::const_iterator c1 = curve1->begin(); + int count = 0; + for (Evoral::ControlList::const_iterator c2 = curve2->begin(); c2!=curve2->end(); c2++ ) { + float v1 = accurate_coefficient_to_dB((*c1)->value); + float v2 = accurate_coefficient_to_dB((*c2)->value); + + double interp = v1 * ( 1.0-( (double)count / (double)size) ); + interp += v2 * ( (double)count / (double)size ); + + interp = dB_to_coefficient(interp); + dst->add ( (*c1)->when, interp ); + c1++; + count++; + } +} + void AudioRegion::make_property_quarks () { @@ -133,7 +217,9 @@ AudioRegion::AudioRegion (Session& s, framepos_t start, framecnt_t len, std::str , AUDIOREGION_STATE_DEFAULT , _automatable (s) , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation))) + , _inverse_fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation))) , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation))) + , _inverse_fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation))) , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation))) , _fade_in_suspended (0) , _fade_out_suspended (0) @@ -150,7 +236,9 @@ AudioRegion::AudioRegion (const SourceList& srcs) , AUDIOREGION_STATE_DEFAULT , _automatable(srcs[0]->session()) , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation))) + , _inverse_fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation))) , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation))) + , _inverse_fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation))) , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation))) , _fade_in_suspended (0) , _fade_out_suspended (0) @@ -166,7 +254,9 @@ AudioRegion::AudioRegion (boost::shared_ptr other) , AUDIOREGION_COPY_STATE (other) , _automatable (other->session()) , _fade_in (new AutomationList (*other->_fade_in)) + , _inverse_fade_in (new AutomationList(*other->_inverse_fade_in)) , _fade_out (new AutomationList (*other->_fade_out)) + , _inverse_fade_out (new AutomationList (*other->_inverse_fade_out)) /* As far as I can see, the _envelope's times are relative to region position, and have nothing to do with sources (and hence _start). So when we copy the envelope, we just use the supplied offset. */ @@ -192,7 +282,9 @@ AudioRegion::AudioRegion (boost::shared_ptr other, framecnt_t , AUDIOREGION_COPY_STATE (other) , _automatable (other->session()) , _fade_in (new AutomationList (*other->_fade_in)) + , _inverse_fade_in (new AutomationList(*other->_inverse_fade_in)) , _fade_out (new AutomationList (*other->_fade_out)) + , _inverse_fade_out (new AutomationList (*other->_inverse_fade_out)) /* As far as I can see, the _envelope's times are relative to region position, and have nothing to do with sources (and hence _start). So when we copy the envelope, we just use the supplied offset. */ @@ -218,7 +310,9 @@ AudioRegion::AudioRegion (boost::shared_ptr other, const Sour , AUDIOREGION_COPY_STATE (other) , _automatable (other->session()) , _fade_in (new AutomationList (*other->_fade_in)) + , _inverse_fade_in (new AutomationList(*other->_inverse_fade_in)) , _fade_out (new AutomationList (*other->_fade_out)) + , _inverse_fade_out (new AutomationList (*other->_inverse_fade_out)) , _envelope (new AutomationList (*other->_envelope)) , _fade_in_suspended (0) , _fade_out_suspended (0) @@ -241,7 +335,9 @@ AudioRegion::AudioRegion (SourceList& srcs) , AUDIOREGION_STATE_DEFAULT , _automatable(srcs[0]->session()) , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation))) + , _inverse_fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation))) , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation))) + , _inverse_fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation))) , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation))) , _fade_in_suspended (0) , _fade_out_suspended (0) @@ -830,17 +926,11 @@ AudioRegion::_set_state (const XMLNode& node, int version, PropertyChange& what_ } else if (child->name() == "InvFadeIn") { XMLNode* grandchild = child->child ("AutomationList"); if (grandchild) { - if (!_inverse_fade_in) { - _inverse_fade_in.reset (new AutomationList (Evoral::Parameter (FadeInAutomation))); - } _inverse_fade_in->set_state (*grandchild, version); } } else if (child->name() == "InvFadeOut") { XMLNode* grandchild = child->child ("AutomationList"); if (grandchild) { - if (!_inverse_fade_out) { - _inverse_fade_out.reset (new AutomationList (Evoral::Parameter (FadeOutAutomation))); - } _inverse_fade_out->set_state (*grandchild, version); } } @@ -893,117 +983,70 @@ AudioRegion::set_fade_in (boost::shared_ptr f) void AudioRegion::set_fade_in (FadeShape shape, framecnt_t len) { + boost::shared_ptr c1 (new Evoral::ControlList (FadeInAutomation)); + boost::shared_ptr c2 (new Evoral::ControlList (FadeInAutomation)); + boost::shared_ptr c3 (new Evoral::ControlList (FadeInAutomation)); + + cerr << "Resetting fade in to " << shape << " len = " << len << endl; + _fade_in->freeze (); _fade_in->clear (); + _inverse_fade_in->clear (); switch (shape) { case FadeLinear: _fade_in->fast_simple_add (0.0, 0.0); _fade_in->fast_simple_add (len, 1.0); - _inverse_fade_in.reset (); + reverse_curve (_inverse_fade_in, _fade_in); break; case FadeFast: - _fade_in->fast_simple_add (0, 0); - _fade_in->fast_simple_add (len * 0.389401, 0.0333333); - _fade_in->fast_simple_add (len * 0.629032, 0.0861111); - _fade_in->fast_simple_add (len * 0.829493, 0.233333); - _fade_in->fast_simple_add (len * 0.9447, 0.483333); - _fade_in->fast_simple_add (len * 0.976959, 0.697222); - _fade_in->fast_simple_add (len, 1); - _inverse_fade_in.reset (); + generate_db_fade (_fade_in, len, 10, -60); + reverse_curve (c1, _fade_in); + _fade_in->copy_events (*c1); + generate_inverse_power_curve (_inverse_fade_in, _fade_in); break; case FadeSlow: - _fade_in->fast_simple_add (0, 0); - _fade_in->fast_simple_add (len * 0.0207373, 0.197222); - _fade_in->fast_simple_add (len * 0.0645161, 0.525); - _fade_in->fast_simple_add (len * 0.152074, 0.802778); - _fade_in->fast_simple_add (len * 0.276498, 0.919444); - _fade_in->fast_simple_add (len * 0.481567, 0.980556); - _fade_in->fast_simple_add (len * 0.767281, 1); - _fade_in->fast_simple_add (len, 1); - _inverse_fade_in.reset (); - break; - - case FadeLogA: - _fade_in->fast_simple_add (0, 0); - _fade_in->fast_simple_add (len * 0.0737327, 0.308333); - _fade_in->fast_simple_add (len * 0.246544, 0.658333); - _fade_in->fast_simple_add (len * 0.470046, 0.886111); - _fade_in->fast_simple_add (len * 0.652074, 0.972222); - _fade_in->fast_simple_add (len * 0.771889, 0.988889); - _fade_in->fast_simple_add (len, 1); - _inverse_fade_in.reset (); - break; - - case FadeLogB: - _fade_in->fast_simple_add (0, 0); - _fade_in->fast_simple_add (len * 0.304147, 0.0694444); - _fade_in->fast_simple_add (len * 0.529954, 0.152778); - _fade_in->fast_simple_add (len * 0.725806, 0.333333); - _fade_in->fast_simple_add (len * 0.847926, 0.558333); - _fade_in->fast_simple_add (len * 0.919355, 0.730556); - _fade_in->fast_simple_add (len, 1); - _inverse_fade_in.reset (); + generate_db_fade (c1, len, 10, -1); // start off with a slow fade + generate_db_fade (c2, len, 10, -80); // end with a fast fade + merge_curves (_fade_in, c1, c2); + generate_inverse_power_curve (_inverse_fade_in, _fade_in); break; - case FadeConstantPowerMinus3dB: - _fade_in->fast_simple_add (0.0, 0.0); - _fade_in->fast_simple_add ((len * 0.166667), 0.282192); - _fade_in->fast_simple_add ((len * 0.333333), 0.518174); - _fade_in->fast_simple_add ((len * 0.500000), 0.707946); - _fade_in->fast_simple_add ((len * 0.666667), 0.851507); - _fade_in->fast_simple_add ((len * 0.833333), 0.948859); - _fade_in->fast_simple_add (len, 1.0); - - /* setup complementary fade out for lower layers */ - - if (!_inverse_fade_in) { - _inverse_fade_in.reset (new AutomationList (Evoral::Parameter (FadeInAutomation))); + case FadeConstantPower: + for (int i = 0; i < 9; ++i) { + float dist = (float) i / 10.0f; + _fade_in->fast_simple_add (len*dist, sin (dist*M_PI/2)); } - - _inverse_fade_in->clear (); - _inverse_fade_in->fast_simple_add (0.0, 1.0); - _inverse_fade_in->fast_simple_add ((len * 0.166667), 0.948859); - _inverse_fade_in->fast_simple_add ((len * 0.333333), 0.851507); - _inverse_fade_in->fast_simple_add ((len * 0.500000), 0.707946); - _inverse_fade_in->fast_simple_add ((len * 0.666667), 0.518174); - _inverse_fade_in->fast_simple_add ((len * 0.833333), 0.282192); - _inverse_fade_in->fast_simple_add (len, 0.0); - + _fade_in->fast_simple_add (len, 1.0); + generate_inverse_power_curve (_inverse_fade_in, _fade_in); break; - case FadeConstantPowerMinus6dB: - _fade_in->fast_simple_add (0.0, 0.0); - _fade_in->fast_simple_add ((len * 0.166667), 0.166366); - _fade_in->fast_simple_add ((len * 0.333333), 0.332853); - _fade_in->fast_simple_add ((len * 0.500000), 0.499459); - _fade_in->fast_simple_add ((len * 0.666667), 0.666186); - _fade_in->fast_simple_add ((len * 0.833333), 0.833033); - _fade_in->fast_simple_add (len, 1.0); - - /* setup complementary fade out for lower layers */ - - if (!_inverse_fade_in) { - _inverse_fade_in.reset (new AutomationList (Evoral::Parameter (FadeInAutomation))); + case FadeSymmetric: + // starts kind of like a constant power but has a slower fadeout + // however it is NOT constant power and there will be a level drop in the middle of the crossfade + c1->fast_simple_add (0.0, 1.0); + for ( int i = 1; i < 9; i++ ) { + float dist = (float)i/10.0; + c1->fast_simple_add ((len * dist), cos(dist*M_PI/10.0)); } + c1->fast_simple_add (len, VERY_SMALL_SIGNAL); - _inverse_fade_in->clear (); - _inverse_fade_in->fast_simple_add (0.0, 1.0); - _inverse_fade_in->fast_simple_add ((len * 0.166667), 0.833033); - _inverse_fade_in->fast_simple_add ((len * 0.333333), 0.666186); - _inverse_fade_in->fast_simple_add ((len * 0.500000), 0.499459); - _inverse_fade_in->fast_simple_add ((len * 0.666667), 0.332853); - _inverse_fade_in->fast_simple_add ((len * 0.833333), 0.166366); - _inverse_fade_in->fast_simple_add (len, 0.0); + //curve 2 is a slow fade at end + generate_db_fade (c2, len, 10, -30 ); + merge_curves (c3, c1, c2); + reverse_curve (_fade_in, c3); + reverse_curve (_inverse_fade_in, _fade_in ); break; } _default_fade_in = false; _fade_in->thaw (); + cerr << "SEND CHANGE SIGNAL\n"; send_change (PropertyChange (Properties::fade_in)); + cerr << "DONE CHANGE SIGNAL\n"; } void @@ -1020,115 +1063,65 @@ AudioRegion::set_fade_out (boost::shared_ptr f) void AudioRegion::set_fade_out (FadeShape shape, framecnt_t len) { + boost::shared_ptr c1 (new Evoral::ControlList (FadeOutAutomation)); + boost::shared_ptr c2 (new Evoral::ControlList (FadeOutAutomation)); + _fade_out->freeze (); _fade_out->clear (); + _inverse_fade_out->clear (); switch (shape) { - case FadeFast: - _fade_out->fast_simple_add (0.0, 1.0); - _fade_out->fast_simple_add (len * 0.023041, 0.697222); - _fade_out->fast_simple_add (len * 0.0553, 0.483333); - _fade_out->fast_simple_add (len * 0.170507, 0.233333); - _fade_out->fast_simple_add (len * 0.370968, 0.0861111); - _fade_out->fast_simple_add (len * 0.610599, 0.0333333); - _fade_out->fast_simple_add (1.0, 0.0); - _inverse_fade_out.reset (); - break; - - case FadeLogA: - _fade_out->fast_simple_add (0, 1.0); - _fade_out->fast_simple_add (len * 0.228111, 0.988889); - _fade_out->fast_simple_add (len * 0.347926, 0.972222); - _fade_out->fast_simple_add (len * 0.529954, 0.886111); - _fade_out->fast_simple_add (len * 0.753456, 0.658333); - _fade_out->fast_simple_add (len * 0.9262673, 0.308333); - _fade_out->fast_simple_add (len, 0.0); - _inverse_fade_out.reset (); - break; - - case FadeSlow: + case FadeLinear: _fade_out->fast_simple_add (0.0, 1.0); - _fade_out->fast_simple_add (len * 0.305556, 1); - _fade_out->fast_simple_add (len * 0.548611, 0.991736); - _fade_out->fast_simple_add (len * 0.759259, 0.931129); - _fade_out->fast_simple_add (len * 0.918981, 0.68595); - _fade_out->fast_simple_add (len * 0.976852, 0.22865); - _fade_out->fast_simple_add (len, 0.0); - _inverse_fade_out.reset (); + _fade_out->fast_simple_add (len, VERY_SMALL_SIGNAL); + reverse_curve (_inverse_fade_out, _fade_out); break; - - case FadeLogB: - _fade_out->fast_simple_add (0.0, 1.0); - _fade_out->fast_simple_add (len * 0.080645, 0.730556); - _fade_out->fast_simple_add (len * 0.277778, 0.289256); - _fade_out->fast_simple_add (len * 0.470046, 0.152778); - _fade_out->fast_simple_add (len * 0.695853, 0.0694444); - _fade_out->fast_simple_add (len, 0.0); - _inverse_fade_out.reset (); + + case FadeFast: + generate_db_fade (_fade_out, len, 10, -60 ); + generate_inverse_power_curve (_inverse_fade_out, _fade_out); break; - - case FadeLinear: - _fade_out->fast_simple_add (0.0, 1.0); - _fade_out->fast_simple_add (len, 0.0); - _inverse_fade_out.reset (); + + case FadeSlow: + generate_db_fade (c1, len, 10, -1 ); //start off with a slow fade + generate_db_fade (c2, len, 10, -80 ); //end with a fast fade + merge_curves (_fade_out, c1, c2); + generate_inverse_power_curve (_inverse_fade_out, _fade_out); break; - case FadeConstantPowerMinus3dB: + case FadeConstantPower: + //constant-power fades use a sin/cos relationship + //the cutoff is abrupt but it has the benefit of being symmetrical _fade_out->fast_simple_add (0.0, 1.0); - _fade_out->fast_simple_add ((len * 0.166667), 0.948859); - _fade_out->fast_simple_add ((len * 0.333333), 0.851507); - _fade_out->fast_simple_add ((len * 0.500000), 0.707946); - _fade_out->fast_simple_add ((len * 0.666667), 0.518174); - _fade_out->fast_simple_add ((len * 0.833333), 0.282192); - _fade_out->fast_simple_add (len, 0.0); - - /* setup complementary fade in for lower layers */ - - if (!_inverse_fade_out) { - _inverse_fade_out.reset (new AutomationList (Evoral::Parameter (FadeOutAutomation))); + for (int i = 1; i < 9; i++ ) { + float dist = (float)i/10.0; + _fade_out->fast_simple_add ((len * dist), cos(dist*M_PI/2)); } - - _inverse_fade_out->clear (); - _inverse_fade_out->fast_simple_add (0.0, 0.0); - _inverse_fade_out->fast_simple_add ((len * 0.166667), 0.282192); - _inverse_fade_out->fast_simple_add ((len * 0.333333), 0.518174); - _inverse_fade_out->fast_simple_add ((len * 0.500000), 0.707946); - _inverse_fade_out->fast_simple_add ((len * 0.666667), 0.851507); - _inverse_fade_out->fast_simple_add ((len * 0.833333), 0.948859); - _inverse_fade_out->fast_simple_add (len, 1.0); - + _fade_out->fast_simple_add (len, VERY_SMALL_SIGNAL); + generate_inverse_power_curve (_inverse_fade_out, _fade_out); break; - - case FadeConstantPowerMinus6dB: - _fade_out->fast_simple_add (0.0, 1.0); - _fade_out->fast_simple_add ((len * 0.166667), 0.833033); - _fade_out->fast_simple_add ((len * 0.333333), 0.666186); - _fade_out->fast_simple_add ((len * 0.500000), 0.499459); - _fade_out->fast_simple_add ((len * 0.666667), 0.332853); - _fade_out->fast_simple_add ((len * 0.833333), 0.166366); - _fade_out->fast_simple_add (len, 0.0); - - /* setup complementary fade in for lower layers */ - - if (!_inverse_fade_out) { - _inverse_fade_out.reset (new AutomationList (Evoral::Parameter (FadeOutAutomation))); + + case FadeSymmetric: + //starts kind of like a constant power but has a slower fadeout + //however it is NOT constant power and there will be a level drop in the middle of the crossfade + c1->fast_simple_add (0.0, 1.0); + for ( int i = 1; i < 9; i++ ) { + float dist = (float)i/10.0; + c1->fast_simple_add ((len * dist), cos(dist*M_PI/10.0)); //cheesy way of making a flat line } + c1->fast_simple_add (len, VERY_SMALL_SIGNAL); - _inverse_fade_out->clear (); - _inverse_fade_out->fast_simple_add (0.0, 0.0); - _inverse_fade_out->fast_simple_add ((len * 0.166667), 0.166366); - _inverse_fade_out->fast_simple_add ((len * 0.333333), 0.332853); - _inverse_fade_out->fast_simple_add ((len * 0.500000), 0.499459); - _inverse_fade_out->fast_simple_add ((len * 0.666667), 0.666186); - _inverse_fade_out->fast_simple_add ((len * 0.833333), 0.833033); - _inverse_fade_out->fast_simple_add (len, 1.0); + //curve 2 is a slow fade at end + generate_db_fade (c2, len, 10, -30); + merge_curves (_fade_out, c1, c2); + reverse_curve (_inverse_fade_out, _fade_out); break; } _default_fade_out = false; _fade_out->thaw (); - send_change (PropertyChange (Properties::fade_in)); + send_change (PropertyChange (Properties::fade_out)); } void @@ -1879,6 +1872,11 @@ AudioRegion::verify_xfade_bounds (framecnt_t len, bool start) boost::shared_ptr other = get_single_other_xfade_region (start); framecnt_t maxlen; + if (!other) { + /* zero or > 2 regions here, don't care about len */ + return len; + } + /* we overlap a single region. clamp the length of an xfade to the maximum possible duration of the overlap (if the other region were trimmed appropriately). diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 54c6214ee5..c0d6107639 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -414,10 +414,8 @@ setup_enum_writer () REGISTER_ENUM (FadeLinear); REGISTER_ENUM (FadeFast); REGISTER_ENUM (FadeSlow); - REGISTER_ENUM (FadeLogA); - REGISTER_ENUM (FadeLogB); - REGISTER_ENUM (FadeConstantPowerMinus3dB); - REGISTER_ENUM (FadeConstantPowerMinus6dB); + REGISTER_ENUM (FadeConstantPower); + REGISTER_ENUM (FadeSymmetric); REGISTER (_FadeShape); REGISTER_CLASS_ENUM (Diskstream, Recordable); diff --git a/libs/evoral/evoral/ControlList.hpp b/libs/evoral/evoral/ControlList.hpp index 30b9fca430..c54c231ca7 100644 --- a/libs/evoral/evoral/ControlList.hpp +++ b/libs/evoral/evoral/ControlList.hpp @@ -95,6 +95,7 @@ public: ControlList& operator= (const ControlList&); bool operator== (const ControlList&); + void copy_events (const ControlList&); virtual void freeze(); virtual void thaw (); diff --git a/libs/evoral/src/ControlList.cpp b/libs/evoral/src/ControlList.cpp index 9c38f67b29..9a820294ef 100644 --- a/libs/evoral/src/ControlList.cpp +++ b/libs/evoral/src/ControlList.cpp @@ -80,9 +80,7 @@ ControlList::ControlList (const ControlList& other) _search_cache.first = _events.end(); _sort_pending = false; - for (const_iterator i = other._events.begin(); i != other._events.end(); ++i) { - _events.push_back (new ControlEvent (**i)); - } + copy_events (other); mark_dirty (); } @@ -106,9 +104,7 @@ ControlList::ControlList (const ControlList& other, double start, double end) boost::shared_ptr section = const_cast(&other)->copy (start, end); if (!section->empty()) { - for (iterator i = section->begin(); i != section->end(); ++i) { - _events.push_back (new ControlEvent ((*i)->when, (*i)->value)); - } + copy_events (*(section.get())); } mark_dirty (); @@ -147,23 +143,30 @@ ControlList::operator= (const ControlList& other) { if (this != &other) { - _events.clear (); - - for (const_iterator i = other._events.begin(); i != other._events.end(); ++i) { - _events.push_back (new ControlEvent (**i)); - } - _min_yval = other._min_yval; _max_yval = other._max_yval; _default_value = other._default_value; - - mark_dirty (); - maybe_signal_changed (); + + copy_events (other); } return *this; } +void +ControlList::copy_events (const ControlList& other) +{ + { + Glib::Mutex::Lock lm (_lock); + _events.clear (); + for (const_iterator i = other.begin(); i != other.end(); ++i) { + _events.push_back (new ControlEvent ((*i)->when, (*i)->value)); + } + mark_dirty (); + } + maybe_signal_changed (); +} + void ControlList::create_curve() { -- cgit v1.2.3