From 58def58bf50f29e42babdb5de7ca34819c00909f Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 15 Jan 2014 09:37:20 +0100 Subject: [PATCH 01/10] VBAP GUI convention: top == front ^= azimuth == .5 This allows to move from stereo,mono panners to VBAP and back and also facilitates sharing pannables of all currently existing panners with semantically similar results. (somewhat dirty solution, this retains PBD::spherical_to_cartesian and maps angles pretty much everywhere else) --- gtk2_ardour/panner2d.cc | 55 ++++++++++++++++++++++++--------------- libs/ardour/speakers.cc | 10 +++---- libs/panners/vbap/vbap.cc | 10 +++---- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/gtk2_ardour/panner2d.cc b/gtk2_ardour/panner2d.cc index 0f8b46aa56..a3befff5cf 100644 --- a/gtk2_ardour/panner2d.cc +++ b/gtk2_ardour/panner2d.cc @@ -166,6 +166,7 @@ Panner2d::on_size_allocate (Gtk::Allocation& alloc) radius = min (width, height); radius -= border; radius /= 2; + radius = rint(radius) + .5; hoffset = max ((double) (width - height), border); voffset = max ((double) (height - width), border); @@ -251,12 +252,8 @@ Panner2d::handle_position_change () uint32_t n; double w = panner_shell->pannable()->pan_width_control->get_value(); - if (have_elevation) { - position.position = AngularVector (panner_shell->pannable()->pan_azimuth_control->get_value() * 360.0, - panner_shell->pannable()->pan_elevation_control->get_value() * 90.0); - } else { - position.position = AngularVector (panner_shell->pannable()->pan_azimuth_control->get_value() * 360.0, 0); - } + position.position = AngularVector (panner_shell->pannable()->pan_azimuth_control->get_value() * 360.0, + panner_shell->pannable()->pan_elevation_control->get_value() * 90.0); for (uint32_t i = 0; i < signals.size(); ++i) { signals[i]->position = panner_shell->panner()->signal_position (i); @@ -300,7 +297,11 @@ Panner2d::find_closest_object (gdouble x, gdouble y, bool& is_signal) /* start with the position itself */ - position.position.cartesian (c); + PBD::AngularVector dp = position.position; + if (!have_elevation) dp.ele = 0; + dp.azi = 270 - dp.azi; + dp.cartesian (c); + cart_to_gtk (c); best_distance = sqrt ((c.x - x) * (c.x - x) + (c.y - y) * (c.y - y)); @@ -342,9 +343,11 @@ Panner2d::find_closest_object (gdouble x, gdouble y, bool& is_signal) if (!closest) { for (Targets::const_iterator i = speakers.begin(); i != speakers.end(); ++i) { candidate = *i; - - candidate->position.cartesian (c); - cart_to_gtk (c); + PBD::AngularVector sp = candidate->position; + sp.azi = 270 -sp.azi; + CartesianVector c; + sp.cartesian (c); + cart_to_gtk (c); distance = sqrt ((c.x - x) * (c.x - x) + (c.y - y) * (c.y - y)); @@ -426,14 +429,14 @@ Panner2d::on_expose_event (GdkEventExpose *event) /* horizontal line of "crosshairs" */ cairo_set_source_rgba (cr, 0.282, 0.517, 0.662, 1.0); - cairo_move_to (cr, 0.0, rint(radius) + .5); - cairo_line_to (cr, diameter, rint(radius) + .5); + cairo_move_to (cr, 0.0, radius); + cairo_line_to (cr, diameter, radius); cairo_stroke (cr); /* vertical line of "crosshairs" */ - cairo_move_to (cr, rint(radius) + .5, 0); - cairo_line_to (cr, rint(radius) + .5, diameter); + cairo_move_to (cr, radius, 0); + cairo_line_to (cr, radius, diameter); cairo_stroke (cr); /* the circle on which signals live */ @@ -456,15 +459,17 @@ Panner2d::on_expose_event (GdkEventExpose *event) } if (!panner_shell->bypassed()) { + /* convention top == front ^= azimuth == .5 (same as stereo/mono panners) */ if (signals.size() > 1) { /* arc to show "diffusion" */ double width_angle = fabs (panner_shell->pannable()->pan_width_control->get_value()) * 2 * M_PI; - double position_angle = (2 * M_PI) - panner_shell->pannable()->pan_azimuth_control->get_value() * 2 * M_PI; + double position_angle = panner_shell->pannable()->pan_azimuth_control->get_value() * 2 * M_PI; cairo_save (cr); cairo_translate (cr, radius, radius); + cairo_rotate (cr, M_PI / 2.0); cairo_rotate (cr, position_angle - (width_angle/2.0)); cairo_move_to (cr, 0, 0); cairo_arc_negative (cr, 0, 0, radius, width_angle, 0.0); @@ -493,7 +498,10 @@ Panner2d::on_expose_event (GdkEventExpose *event) /* draw position */ - position.position.cartesian (c); + PBD::AngularVector dp = position.position; + if (!have_elevation) dp.ele = 0; + dp.azi = 270 - dp.azi; + dp.cartesian (c); cart_to_gtk (c); cairo_new_path (cr); @@ -505,7 +513,7 @@ Panner2d::on_expose_event (GdkEventExpose *event) /* signals */ - if (signals.size() > 1) { + if (signals.size() > 0) { for (Targets::iterator i = signals.begin(); i != signals.end(); ++i) { Target* signal = *i; @@ -516,6 +524,7 @@ Panner2d::on_expose_event (GdkEventExpose *event) */ PBD::AngularVector sp = signal->position; if (!have_elevation) sp.ele = 0; + sp.azi += 270.0; sp.cartesian (c); cart_to_gtk (c); @@ -553,9 +562,10 @@ Panner2d::on_expose_event (GdkEventExpose *event) if (speaker->visible) { + PBD::AngularVector sp = speaker->position; + sp.azi += 270.0; CartesianVector c; - - speaker->position.cartesian (c); + sp.cartesian (c); cart_to_gtk (c); snprintf (buf, sizeof (buf), "%d", n); @@ -564,7 +574,7 @@ Panner2d::on_expose_event (GdkEventExpose *event) cairo_move_to (cr, c.x, c.y); cairo_save (cr); - cairo_rotate (cr, -(speaker->position.azi/360.0) * (2.0 * M_PI)); + cairo_rotate (cr, -(sp.azi/360.0) * (2.0 * M_PI)); if (small) { cairo_scale (cr, 0.8, 0.8); } else { @@ -588,7 +598,8 @@ Panner2d::on_expose_event (GdkEventExpose *event) /* move the text in just a bit */ - AngularVector textpos (speaker->position.azi, speaker->position.ele, 0.85); + AngularVector textpos (speaker->position.azi + 270.0, speaker->position.ele, 0.85); + textpos.cartesian (c); cart_to_gtk (c); cairo_move_to (cr, c.x, c.y); @@ -716,6 +727,7 @@ Panner2d::handle_motion (gint evx, gint evy, GdkModifierType state) if (!have_elevation) { clamp_to_circle (cp.x, cp.y); cp.angular (av); + av.azi = fmod(270 - av.azi, 360); if (drag_target == &position) { double degree_fract = av.azi / 360.0; panner_shell->panner()->set_position (degree_fract); @@ -727,6 +739,7 @@ Panner2d::handle_motion (gint evx, gint evy, GdkModifierType state) double r2d = 180.0 / M_PI; av.azi = r2d * atan2(cp.y, cp.x); av.ele = r2d * asin(cp.z); + av.azi = fmod(270 - av.azi, 360); if (drag_target == &position) { double azi_fract = av.azi / 360.0; diff --git a/libs/ardour/speakers.cc b/libs/ardour/speakers.cc index 2acc9659ef..bbad254f6e 100644 --- a/libs/ardour/speakers.cc +++ b/libs/ardour/speakers.cc @@ -149,7 +149,7 @@ Speakers::move_speaker (int id, const AngularVector& new_position) void Speakers::setup_default_speakers (uint32_t n) { - double o = 90.0; + double o = 180.0; /* default assignment of speaker position for n speakers */ @@ -229,12 +229,12 @@ Speakers::setup_default_speakers (uint32_t n) */ if (n % 2) { - deg = 90.0 - degree_step; + deg = 360 + o + degree_step; } else { - deg = 90.0; + deg = 360 + o; } - for (i = 0; i < n; ++i, deg += degree_step) { - add_speaker (AngularVector (deg, 0.0)); + for (i = 0; i < n; ++i, deg -= degree_step) { + add_speaker (AngularVector (fmod(deg, 360), 0.0)); } } } diff --git a/libs/panners/vbap/vbap.cc b/libs/panners/vbap/vbap.cc index e15e2abb4c..2ab91cf3c4 100644 --- a/libs/panners/vbap/vbap.cc +++ b/libs/panners/vbap/vbap.cc @@ -122,7 +122,7 @@ VBAPanner::update () if (_signals.size() > 1) { double w = - (_pannable->pan_width_control->get_value()); - double signal_direction = _pannable->pan_azimuth_control->get_value() - (w/2); + double signal_direction = 1.0 - (_pannable->pan_azimuth_control->get_value() + (w/2)); double grd_step_per_signal = w / (_signals.size() - 1); for (vector::iterator s = _signals.begin(); s != _signals.end(); ++s) { @@ -137,7 +137,7 @@ VBAPanner::update () signal_direction += grd_step_per_signal; } } else if (_signals.size() == 1) { - double center = _pannable->pan_azimuth_control->get_value() * 360.0; + double center = (1.0 - _pannable->pan_azimuth_control->get_value()) * 360.0; /* width has no role to play if there is only 1 signal: VBAP does not do "diffusion" of a single channel */ @@ -421,7 +421,7 @@ VBAPanner::value_as_string (boost::shared_ptr ac) const switch (ac->parameter().type()) { case PanAzimuthAutomation: /* direction */ - return string_compose (_("%1\u00B0"), int (rint (val * 360.0))); + return string_compose (_("%1\u00B0"), (int (rint (val * 360.0))+180)%360); case PanWidthAutomation: /* diffusion */ return string_compose (_("%1%%"), (int) floor (100.0 * fabs(val))); @@ -475,11 +475,11 @@ VBAPanner::set_elevation (double e) void VBAPanner::reset () { - set_position (0); + set_position (.5); if (_signals.size() > 1) { set_width (1.0 - (1.0 / (double)_signals.size())); } else { - set_width (0); + set_width (1.0); } set_elevation (0); From a4dc05f603c5de1748752eb6e078a2415f17532f Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 15 Jan 2014 09:45:02 +0100 Subject: [PATCH 02/10] fix invalid width when swiching to 2in2out --- libs/panners/2in2out/panner_2in2out.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libs/panners/2in2out/panner_2in2out.cc b/libs/panners/2in2out/panner_2in2out.cc index f801a36ff4..463b2671bb 100644 --- a/libs/panners/2in2out/panner_2in2out.cc +++ b/libs/panners/2in2out/panner_2in2out.cc @@ -78,7 +78,14 @@ Panner2in2out::Panner2in2out (boost::shared_ptr p) if (!_pannable->has_state()) { _pannable->pan_azimuth_control->set_value (0.5); _pannable->pan_width_control->set_value (1.0); - } + } + + double const w = width(); + double const wrange = min (position(), (1 - position())) * 2; + if (fabs(w) > wrange) { + set_width(w > 0 ? wrange : -wrange); + } + update (); From d27d6e673f6381947789e5934b42381f5b52847f Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 15 Jan 2014 10:37:25 +0100 Subject: [PATCH 03/10] re-allow panners for monitoring-section (for now) --- libs/ardour/delivery.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/ardour/delivery.cc b/libs/ardour/delivery.cc index 045417b0cc..82e025845e 100644 --- a/libs/ardour/delivery.cc +++ b/libs/ardour/delivery.cc @@ -398,7 +398,7 @@ Delivery::reset_panner () if (!_no_panner_reset) { if (_panshell) { - assert (_role == Main || _role == Aux || _role == Send); + assert (_role == Main || _role == Aux || _role == Send || _role == Listen); _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, pan_outs())); } } @@ -413,7 +413,7 @@ void Delivery::panners_became_legal () { if (_panshell) { - assert (_role == Main || _role == Aux || _role == Send); + assert (_role == Main || _role == Aux || _role == Send || _role == Listen); _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, pan_outs())); } From abb75d4a2eeafc9894011998cb263449c55bc4e0 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 15 Jan 2014 10:38:32 +0100 Subject: [PATCH 04/10] prevent stackoverflow when pannable changes to fewer params endless loop: e.g. 2in2out -> balance (or 1in1out) #23 0xb7ab5c17 in ARDOUR::Pannable::value_as_string #24 0xb2ebb206 in ARDOUR::Pannerbalance::value_as_string #25 0xb7ab5c17 in ARDOUR::Pannable::value_as_string #26 0xb2ebb206 in ARDOUR::Pannerbalance::value_as_string ad infinitum --- libs/panners/1in2out/panner_1in2out.cc | 2 +- libs/panners/2in2out/panner_2in2out.cc | 2 +- libs/panners/stereobalance/panner_balance.cc | 2 +- libs/panners/vbap/vbap.cc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/panners/1in2out/panner_1in2out.cc b/libs/panners/1in2out/panner_1in2out.cc index 12e7896cfb..4dd21493e6 100644 --- a/libs/panners/1in2out/panner_1in2out.cc +++ b/libs/panners/1in2out/panner_1in2out.cc @@ -385,7 +385,7 @@ Panner1in2out::value_as_string (boost::shared_ptr ac) const (int) rint (100.0 * val)); default: - return _pannable->value_as_string (ac); + return _("unused"); } } diff --git a/libs/panners/2in2out/panner_2in2out.cc b/libs/panners/2in2out/panner_2in2out.cc index 463b2671bb..860610ecfc 100644 --- a/libs/panners/2in2out/panner_2in2out.cc +++ b/libs/panners/2in2out/panner_2in2out.cc @@ -529,7 +529,7 @@ Panner2in2out::value_as_string (boost::shared_ptr ac) const return string_compose (_("Width: %1%%"), (int) floor (100.0 * val)); default: - return _pannable->value_as_string (ac); + return _("unused"); } } diff --git a/libs/panners/stereobalance/panner_balance.cc b/libs/panners/stereobalance/panner_balance.cc index d5ab96b73c..b7d8a2a031 100644 --- a/libs/panners/stereobalance/panner_balance.cc +++ b/libs/panners/stereobalance/panner_balance.cc @@ -321,7 +321,7 @@ Pannerbalance::value_as_string (boost::shared_ptr ac) const (int) rint (100.0 * val)); default: - return _pannable->value_as_string (ac); + return _("unused"); } } diff --git a/libs/panners/vbap/vbap.cc b/libs/panners/vbap/vbap.cc index 2ab91cf3c4..b092be29d0 100644 --- a/libs/panners/vbap/vbap.cc +++ b/libs/panners/vbap/vbap.cc @@ -430,7 +430,7 @@ VBAPanner::value_as_string (boost::shared_ptr ac) const return string_compose (_("%1\u00B0"), (int) floor (90.0 * fabs(val))); default: - return _pannable->value_as_string (ac); + return _("unused"); } } From b73b2ceecd21cfc64ee7aa21fc731e41264217dd Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 15 Jan 2014 11:23:38 +0100 Subject: [PATCH 05/10] update pan automation-track display --- gtk2_ardour/audio_time_axis.cc | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc index bf980690aa..675136b860 100644 --- a/gtk2_ardour/audio_time_axis.cc +++ b/gtk2_ardour/audio_time_axis.cc @@ -216,6 +216,16 @@ AudioTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool void AudioTimeAxisView::ensure_pan_views (bool show) { + bool changed = false; + for (list >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) { + changed = true; + (*i)->set_marked_for_display (false); + } + if (changed) { + _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */ + } + pan_tracks.clear(); + if (!_route->panner()) { return; } @@ -252,6 +262,8 @@ AudioTimeAxisView::ensure_pan_views (bool show) pan_tracks.push_back (t); add_automation_child (*p, t, show); + } else { + pan_tracks.push_back (automation_child (pan_control->parameter ())); } } } @@ -393,14 +405,16 @@ AudioTimeAxisView::build_automation_action_menu (bool for_selection) _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item; - automation_items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &AudioTimeAxisView::update_pan_track_visibility))); - pan_automation_item = dynamic_cast (&automation_items.back ()); - pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) && - (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible")))); + if (!pan_tracks.empty()) { + automation_items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &AudioTimeAxisView::update_pan_track_visibility))); + pan_automation_item = dynamic_cast (&automation_items.back ()); + pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) && + (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible")))); - set const & params = _route->pannable()->what_can_be_automated (); - for (set::iterator p = params.begin(); p != params.end(); ++p) { - _main_automation_menu_map[*p] = pan_automation_item; + set const & params = _route->pannable()->what_can_be_automated (); + for (set::iterator p = params.begin(); p != params.end(); ++p) { + _main_automation_menu_map[*p] = pan_automation_item; + } } } From ab838a126046c09017ec09a1971472f6be81bd51 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 15 Jan 2014 11:30:54 +0100 Subject: [PATCH 06/10] Midi-track fader & pan automation NB. Fader automation lane always shows 'dB' value and is logarithmic. OK for pre-fader synths, but not for raw-midi data. --- gtk2_ardour/midi_time_axis.cc | 128 ++++++++++++++++++++++++++++++++++ gtk2_ardour/midi_time_axis.h | 9 +++ 2 files changed, 137 insertions(+) diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc index a4ffc442a3..54793d9904 100644 --- a/gtk2_ardour/midi_time_axis.cc +++ b/gtk2_ardour/midi_time_axis.cc @@ -47,6 +47,9 @@ #include "ardour/midi_source.h" #include "ardour/midi_track.h" #include "ardour/operations.h" +#include "ardour/pannable.h" +#include "ardour/panner.h" +#include "ardour/panner_shell.h" #include "ardour/playlist.h" #include "ardour/region.h" #include "ardour/region_factory.h" @@ -165,7 +168,17 @@ MidiTimeAxisView::set_route (boost::shared_ptr rt) controls_ebox.set_name ("MidiBusControlsBaseUnselected"); } + /* if set_state above didn't create a gain automation child, we need to make one */ + if (automation_child (GainAutomation) == 0) { + create_automation_child (GainAutomation, false); + } + + if (_route->panner_shell()) { + _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context()); + } + /* map current state of the route */ + ensure_pan_views (false); processors_changed (RouteProcessorChange ()); @@ -583,6 +596,27 @@ MidiTimeAxisView::build_automation_action_menu (bool for_selection) MenuElem (string_compose ("%1", _("No MIDI Channels selected")))); dynamic_cast (automation_items.back().get_child())->set_use_markup (true); } + + automation_items.push_back (SeparatorElem()); + automation_items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &MidiTimeAxisView::update_gain_track_visibility))); + gain_automation_item = dynamic_cast (&automation_items.back ()); + gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) && + (gain_track && string_is_affirmative (gain_track->gui_property ("visible")))); + + _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item; + + if (!pan_tracks.empty()) { + automation_items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &MidiTimeAxisView::update_pan_track_visibility))); + pan_automation_item = dynamic_cast (&automation_items.back ()); + pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) && + (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible")))); + + set const & params = _route->pannable()->what_can_be_automated (); + for (set::iterator p = params.begin(); p != params.end(); ++p) { + _main_automation_menu_map[*p] = pan_automation_item; + } + } + } void @@ -1074,6 +1108,94 @@ MidiTimeAxisView::update_range() } } +void +MidiTimeAxisView::ensure_pan_views (bool show) +{ + bool changed = false; + for (list >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) { + changed = true; + (*i)->set_marked_for_display (false); + } + if (changed) { + _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */ + } + pan_tracks.clear(); + + if (!_route->panner()) { + return; + } + + set params = _route->panner()->what_can_be_automated(); + set::iterator p; + + for (p = params.begin(); p != params.end(); ++p) { + boost::shared_ptr pan_control = _route->pannable()->automation_control(*p); + + if (pan_control->parameter().type() == NullAutomation) { + error << "Pan control has NULL automation type!" << endmsg; + continue; + } + + if (automation_child (pan_control->parameter ()).get () == 0) { + + /* we don't already have an AutomationTimeAxisView for this parameter */ + + std::string const name = _route->panner()->describe_parameter (pan_control->parameter ()); + + boost::shared_ptr t ( + new AutomationTimeAxisView (_session, + _route, + _route->pannable(), + pan_control, + pan_control->parameter (), + _editor, + *this, + false, + parent_canvas, + name) + ); + + pan_tracks.push_back (t); + add_automation_child (*p, t, show); + } else { + pan_tracks.push_back (automation_child (pan_control->parameter ())); + } + } +} + +void +MidiTimeAxisView::update_gain_track_visibility () +{ + bool const showit = gain_automation_item->get_active(); + + if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) { + gain_track->set_marked_for_display (showit); + + /* now trigger a redisplay */ + + if (!no_redraw) { + _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */ + } + } +} + +void +MidiTimeAxisView::update_pan_track_visibility () +{ + bool const showit = pan_automation_item->get_active(); + bool changed = false; + + for (list >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) { + if ((*i)->set_marked_for_display (showit)) { + changed = true; + } + } + + if (changed) { + _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */ + } +} + void MidiTimeAxisView::show_all_automation (bool apply_to_selection) { @@ -1180,6 +1302,12 @@ MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool add_automation_child (param, track, show); break; + case PanWidthAutomation: + case PanElevationAutomation: + case PanAzimuthAutomation: + ensure_pan_views (show); + break; + default: error << "MidiTimeAxisView: unknown automation child " << EventTypeMap::instance().to_symbol(param) << endmsg; diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h index 25e89fc2e0..12d62459b8 100644 --- a/gtk2_ardour/midi_time_axis.h +++ b/gtk2_ardour/midi_time_axis.h @@ -179,6 +179,15 @@ class MidiTimeAxisView : public RouteTimeAxisView void capture_channel_mode_changed(); void playback_channel_mode_changed(); + + void ensure_pan_views (bool show = true); + + void update_gain_track_visibility (); + void update_pan_track_visibility (); + + Gtk::CheckMenuItem* gain_automation_item; + std::list > pan_tracks; + Gtk::CheckMenuItem* pan_automation_item; }; #endif /* __ardour_midi_time_axis_h__ */ From c8f94053866c3c0f1e796ca2e7fad36266534640 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 15 Jan 2014 14:07:02 +0100 Subject: [PATCH 07/10] stereo-panner: clamp width during processing to valid range --- libs/panners/2in2out/panner_2in2out.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libs/panners/2in2out/panner_2in2out.cc b/libs/panners/2in2out/panner_2in2out.cc index 860610ecfc..25ea1c401a 100644 --- a/libs/panners/2in2out/panner_2in2out.cc +++ b/libs/panners/2in2out/panner_2in2out.cc @@ -165,6 +165,11 @@ Panner2in2out::update () double width = this->width (); const double direction_as_lr_fract = position (); + double const wrange = min (position(), (1 - position())) * 2; + if (fabs(width) > wrange) { + width = (width > 0 ? wrange : -wrange); + } + if (width < 0.0) { width = -width; pos[0] = direction_as_lr_fract + (width/2.0); // left signal lr_fract @@ -428,6 +433,8 @@ Panner2in2out::distribute_one_automated (AudioBuffer& srcbuf, BufferSet& obufs, panR = position[n] + (width[n]/2.0f); // center - width/2 } + panR = max(0.f, min(1.f, panR)); + const float panL = 1 - panR; /* note that are overwriting buffers, but its OK From b06fa27ccb06f4c5430acab3feaea656891beaae Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 15 Jan 2014 14:55:26 +0100 Subject: [PATCH 08/10] rework LXVST port assignments - fixes #5827 --- libs/ardour/vst_plugin.cc | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc index cb40d6eac8..729ee5c129 100644 --- a/libs/ardour/vst_plugin.cc +++ b/libs/ardour/vst_plugin.cc @@ -528,22 +528,35 @@ VSTPlugin::connect_and_run (BufferSet& bufs, { Plugin::connect_and_run (bufs, in_map, out_map, nframes, offset); + ChanCount bufs_count; + bufs_count.set(DataType::AUDIO, 1); + bufs_count.set(DataType::MIDI, 1); + + BufferSet& silent_bufs = _session.get_silent_buffers(bufs_count); + BufferSet& scratch_bufs = _session.get_scratch_buffers(bufs_count); + float *ins[_plugin->numInputs]; float *outs[_plugin->numOutputs]; int32_t i; - const uint32_t nbufs = bufs.count().n_audio(); - - int in_index = 0; + uint32_t in_index = 0; for (i = 0; i < (int32_t) _plugin->numInputs; ++i) { - ins[i] = bufs.get_audio(min((uint32_t) in_index, nbufs - 1)).data() + offset; - in_index++; + uint32_t index; + bool valid = false; + index = in_map.get(DataType::AUDIO, in_index++, &valid); + ins[i] = (valid) + ? bufs.get_audio(index).data(offset) + : silent_bufs.get_audio(0).data(offset); } - int out_index = 0; + uint32_t out_index = 0; for (i = 0; i < (int32_t) _plugin->numOutputs; ++i) { - outs[i] = bufs.get_audio(min((uint32_t) out_index, nbufs - 1)).data() + offset; - out_index++; + uint32_t index; + bool valid = false; + index = out_map.get(DataType::AUDIO, out_index++, &valid); + outs[i] = (valid) + ? bufs.get_audio(index).data(offset) + : scratch_bufs.get_audio(0).data(offset); } if (bufs.count().n_midi() > 0) { From f9a5f8700332e71e9647a83626e5a37409d6e2a8 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 15 Jan 2014 17:59:16 +0100 Subject: [PATCH 09/10] don't pan send/return inserts --- libs/ardour/delivery.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libs/ardour/delivery.cc b/libs/ardour/delivery.cc index 82e025845e..4a392a8145 100644 --- a/libs/ardour/delivery.cc +++ b/libs/ardour/delivery.cc @@ -397,8 +397,7 @@ Delivery::reset_panner () if (panners_legal) { if (!_no_panner_reset) { - if (_panshell) { - assert (_role == Main || _role == Aux || _role == Send || _role == Listen); + if (_panshell && _role != Insert) { _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, pan_outs())); } } @@ -412,8 +411,7 @@ Delivery::reset_panner () void Delivery::panners_became_legal () { - if (_panshell) { - assert (_role == Main || _role == Aux || _role == Send || _role == Listen); + if (_panshell && _role != Insert) { _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, pan_outs())); } From 79b56b1d3319d03d14b2d3e2f8d6cd7b3e797deb Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 15 Jan 2014 20:03:20 +0100 Subject: [PATCH 10/10] fix pan-width automation --- gtk2_ardour/automation_line.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index 993b4779dd..c83a8a0f0c 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -1122,9 +1122,10 @@ AutomationLine::view_to_model_coord_y (double& y) const y = max (0.0, y); y = min (2.0, y); } else if (alist->parameter().type() == PanAzimuthAutomation || - alist->parameter().type() == PanElevationAutomation || - alist->parameter().type() == PanWidthAutomation) { + alist->parameter().type() == PanElevationAutomation) { y = 1.0 - y; + } else if (alist->parameter().type() == PanWidthAutomation) { + y = 2.0 * y - 1.0; } else if (alist->parameter().type() == PluginAutomation) { y = y * (double)(alist->get_max_y()- alist->get_min_y()) + alist->get_min_y(); } else { @@ -1140,10 +1141,10 @@ AutomationLine::model_to_view_coord (double& x, double& y) const alist->parameter().type() == EnvelopeAutomation) { y = gain_to_slider_position_with_max (y, Config->get_max_gain()); } else if (alist->parameter().type() == PanAzimuthAutomation || - alist->parameter().type() == PanElevationAutomation || - alist->parameter().type() == PanWidthAutomation) { - // vertical coordinate axis reversal + alist->parameter().type() == PanElevationAutomation) { y = 1.0 - y; + } else if (alist->parameter().type() == PanWidthAutomation) { + y = .5 + y * .5; } else if (alist->parameter().type() == PluginAutomation) { y = (y - alist->get_min_y()) / (double)(alist->get_max_y()- alist->get_min_y()); } else {