13
0

in case sidechain is fed by a Send, show the send's gain control

this is mainly about investigating what's involved with automatically
adding sends rather than connect track outputs...
This commit is contained in:
Robin Gareus 2016-04-17 01:39:59 +02:00
parent 30633cd2e7
commit 514765631b
2 changed files with 236 additions and 14 deletions

View File

@ -37,6 +37,7 @@
#include "plugin_pin_dialog.h"
#include "gui_thread.h"
#include "timers.h"
#include "tooltips.h"
#include "ui_config.h"
@ -79,15 +80,15 @@ PluginPinDialog::PluginPinDialog (boost::shared_ptr<ARDOUR::PluginInsert> pi)
assert (pi->owner ()); // Route
_pi->PluginIoReConfigure.connect (
_plugin_connections, invalidator (*this), boost::bind (&PluginPinDialog::plugin_reconfigured, this), gui_context ()
_plugin_connections, invalidator (*this), boost::bind (&PluginPinDialog::queue_idle_update, this), gui_context ()
);
_pi->PluginMapChanged.connect (
_plugin_connections, invalidator (*this), boost::bind (&PluginPinDialog::plugin_reconfigured, this), gui_context ()
_plugin_connections, invalidator (*this), boost::bind (&PluginPinDialog::queue_idle_update, this), gui_context ()
);
_pi->PluginConfigChanged.connect (
_plugin_connections, invalidator (*this), boost::bind (&PluginPinDialog::plugin_reconfigured, this), gui_context ()
_plugin_connections, invalidator (*this), boost::bind (&PluginPinDialog::queue_idle_update, this), gui_context ()
);
_pin_box_size = 2 * ceil (max (8., 10. * UIConfiguration::instance ().get_ui_scale ()) * .5);
@ -223,6 +224,45 @@ PluginPinDialog::~PluginPinDialog ()
delete _sidechain_selector;
}
void
PluginPinDialog::set_session (ARDOUR::Session *s)
{
SessionHandlePtr::set_session (s);
plugin_reconfigured ();
}
void
PluginPinDialog::queue_idle_update ()
{
/* various actions here are directly executed, in the GUI thread,
* with the GUI-thread eventually taking the process and processor lock.
* "connect gui_context()" will call back immediately and this
* signal-handler will run with the locks held.
*
* This will lead to a crash with calling nth_send() which takes
* a processor read-lock while holding a write lock in the same thread.
*
* decouple update to GUI idle.
*
* BUT, do delete existing controls here (in case they're affected by
* the change and hit by the Timer before idle comes around)
*/
for (list<Control*>::iterator i = _controls.begin (); i != _controls.end (); ++i) {
_sidechain_tbl->remove ((*i)->box);
delete *i;
}
_controls.clear ();
Glib::signal_idle().connect (sigc::mem_fun(*this, &PluginPinDialog::idle_update));
}
bool
PluginPinDialog::idle_update ()
{
plugin_reconfigured ();
return false;
}
void
PluginPinDialog::plugin_reconfigured ()
{
@ -348,6 +388,10 @@ PluginPinDialog::refill_sidechain_table ()
i = kids.erase (i);
}
_sidechain_tbl->resize (1, 1);
for (list<Control*>::iterator i = _controls.begin (); i != _controls.end (); ++i) {
delete *i;
}
_controls.clear ();
if (!_pi->has_sidechain () && _sidechain_selector) {
return;
}
@ -359,11 +403,11 @@ PluginPinDialog::refill_sidechain_table ()
uint32_t r = 0;
PortSet& p (io->ports ());
bool can_remove = p.num_ports () > 1;
for (PortSet::iterator i = p.begin (DataType::MIDI); i != p.end (DataType::MIDI); ++i, ++r) {
add_port_to_table (*i, r, can_remove);
for (PortSet::iterator i = p.begin (DataType::MIDI); i != p.end (DataType::MIDI); ++i) {
r += add_port_to_table (*i, r, can_remove);
}
for (PortSet::iterator i = p.begin (DataType::AUDIO); i != p.end (DataType::AUDIO); ++i, ++r) {
add_port_to_table (*i, r, can_remove);
for (PortSet::iterator i = p.begin (DataType::AUDIO); i != p.end (DataType::AUDIO); ++i) {
r += add_port_to_table (*i, r, can_remove);
}
_sidechain_tbl->show_all ();
}
@ -386,7 +430,7 @@ PluginPinDialog::refill_output_presets ()
}
if (_pi->strict_io () && ppc.size () == 1) {
// XXX "stereo" is currently preferred default for instruments, see PluginInsert
// "stereo" is currently preferred default for instruments, see PluginInsert
if (ppc.find (2) != ppc.end ()) {
need_dropdown = false;
}
@ -449,7 +493,7 @@ PluginPinDialog::refill_output_presets ()
}
}
void
uint32_t
PluginPinDialog::add_port_to_table (boost::shared_ptr<Port> p, uint32_t r, bool can_remove)
{
std::string lbl;
@ -507,6 +551,41 @@ PluginPinDialog::add_port_to_table (boost::shared_ptr<Port> p, uint32_t r, bool
} else {
pb->set_sensitive (false);
}
uint32_t rv = 1;
if (cns.size () == 1 && _session) {
/* check if it's an Ardour Send feeding.. */
boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
for (ARDOUR::RouteList::const_iterator i = routes->begin (); i != routes->end (); ++i) {
uint32_t nth = 0;
boost::shared_ptr<Processor> proc;
/* nth_send () takes a processor read-lock */
while ((proc = (*i)->nth_send (nth))) {
boost::shared_ptr<IOProcessor> send = boost::dynamic_pointer_cast<IOProcessor> (proc);
if (!send || !send->output ()) {
++nth;
continue;
}
if (!send->output ()->connected_to (p->name ())) {
++nth;
continue;
}
/* if processor goes away, we're notified by the port disconnect,
* there should be no need to explicily connect to proc->DropReferences
*/
set<Evoral::Parameter> p = proc->what_can_be_automated ();
for (set<Evoral::Parameter>::iterator i = p.begin (); i != p.end (); ++i) {
Control* c = new Control (proc->automation_control (*i), _("Send"));
_controls.push_back (c);
++r; ++rv;
_sidechain_tbl->attach (c->box, 0, 2, r, r + 1, EXPAND|FILL, SHRINK);
}
break;
}
}
}
return rv;
}
void
@ -1473,13 +1552,16 @@ PluginPinDialog::add_sidechain_port (DataType dt)
if (!io) {
return;
}
// this triggers a PluginIoReConfigure with process and processor write lock held
// from /this/ thread.
io->add_port ("", this, dt);
}
void
PluginPinDialog::remove_port (boost::weak_ptr<ARDOUR::Port> wp)
{
if (_session && _session->actively_recording()) { return; }
if (_session && _session->actively_recording ()) { return; }
boost::shared_ptr<ARDOUR::Port> p = wp.lock ();
boost::shared_ptr<IO> io = _pi->sidechain_input ();
if (!io || !p) {
@ -1619,9 +1701,122 @@ PluginPinDialog::port_connected_or_disconnected (boost::weak_ptr<ARDOUR::Port> w
if (!io) { return; }
if (p0 && io->has_port (p0)) {
plugin_reconfigured ();
queue_idle_update ();
}
else if (p1 && io->has_port (p1)) {
plugin_reconfigured ();
queue_idle_update ();
}
}
/* lifted from ProcessorEntry::Control */
PluginPinDialog::Control::Control (boost::shared_ptr<AutomationControl> c, string const & n)
: _control (c)
, _adjustment (gain_to_slider_position_with_max (1.0, Config->get_max_gain ()), 0, 1, 0.01, 0.1)
, _slider (&_adjustment, boost::shared_ptr<PBD::Controllable> (), 0, max (13.f, rintf (13.f * UIConfiguration::instance ().get_ui_scale ())))
, _slider_persistant_tooltip (&_slider)
, _ignore_ui_adjustment (false)
, _name (n)
{
_slider.set_controllable (c);
box.set_padding (0, 0, 4, 4);
_slider.set_name ("ProcessorControlSlider");
_slider.set_text (_name);
box.add (_slider);
_slider.show ();
const ARDOUR::ParameterDescriptor& desc = c->desc ();
double const lo = c->internal_to_interface (desc.lower);
double const up = c->internal_to_interface (desc.upper);
double const normal = c->internal_to_interface (desc.normal);
double smallstep = desc.smallstep;
double largestep = desc.largestep;
if (smallstep == 0.0) {
smallstep = up / 1000.;
} else {
smallstep = c->internal_to_interface (desc.lower + smallstep);
}
if (largestep == 0.0) {
largestep = up / 40.;
} else {
largestep = c->internal_to_interface (desc.lower + largestep);
}
_adjustment.set_lower (lo);
_adjustment.set_upper (up);
_adjustment.set_step_increment (smallstep);
_adjustment.set_page_increment (largestep);
_slider.set_default_value (normal);
_adjustment.signal_value_changed ().connect (sigc::mem_fun (*this, &Control::slider_adjusted));
// dup. currently timers are used :(
//c->Changed.connect (_connection, MISSING_INVALIDATOR, boost::bind (&Control::control_changed, this), gui_context ());
// yuck, do we really need to do this?
// according to c404374 this is only needed for send automation
timer_connection = Timers::rapid_connect (sigc::mem_fun (*this, &Control::control_changed));
control_changed ();
set_tooltip ();
/* We're providing our own PersistentTooltip */
set_no_tooltip_whatsoever (_slider);
}
PluginPinDialog::Control::~Control ()
{
timer_connection.disconnect ();
}
void
PluginPinDialog::Control::set_tooltip ()
{
boost::shared_ptr<AutomationControl> c = _control.lock ();
if (!c) {
return;
}
char tmp[256];
snprintf (tmp, sizeof (tmp), "%s: %.2f", _name.c_str (), c->internal_to_user (c->get_value ()));
string sm = Gtkmm2ext::markup_escape_text (tmp);
_slider_persistant_tooltip.set_tip (sm);
}
void
PluginPinDialog::Control::slider_adjusted ()
{
if (_ignore_ui_adjustment) {
return;
}
boost::shared_ptr<AutomationControl> c = _control.lock ();
if (!c) {
return;
}
c->set_value ( c->interface_to_internal (_adjustment.get_value ()) , Controllable::NoGroup);
set_tooltip ();
}
void
PluginPinDialog::Control::control_changed ()
{
boost::shared_ptr<AutomationControl> c = _control.lock ();
if (!c) {
return;
}
_ignore_ui_adjustment = true;
// as long as rapid timers are used, only update the tooltip
// if the value has changed.
const double nval = c->internal_to_interface (c->get_value ());
if (_adjustment.get_value () != nval) {
_adjustment.set_value (nval);
set_tooltip ();
}
_ignore_ui_adjustment = false;
}

View File

@ -27,6 +27,10 @@
#include "ardour/plugin_insert.h"
#include "ardour/route.h"
#include "gtkmm2ext/pixfader.h"
#include "gtkmm2ext/persistent_tooltip.h"
#include "gtkmm2ext/slider_controller.h"
#include "ardour_button.h"
#include "ardour_dropdown.h"
#include "ardour_window.h"
@ -37,7 +41,7 @@ class PluginPinDialog : public ArdourWindow
public:
PluginPinDialog (boost::shared_ptr<ARDOUR::PluginInsert>);
~PluginPinDialog ();
void set_session (ARDOUR::Session *);
private:
typedef enum {
Input,
@ -138,10 +142,10 @@ private:
bool handle_disconnect (const CtrlElem &, bool no_signal = false);
void disconnect_other_outputs (uint32_t skip_pc, ARDOUR::DataType dt, uint32_t id);
void disconnect_other_thru (ARDOUR::DataType dt, uint32_t id);
void add_port_to_table (boost::shared_ptr<ARDOUR::Port>, uint32_t, bool);
void remove_port (boost::weak_ptr<ARDOUR::Port>);
void disconnect_port (boost::weak_ptr<ARDOUR::Port>);
void connect_port (boost::weak_ptr<ARDOUR::Port>, boost::weak_ptr<ARDOUR::Port>);
uint32_t add_port_to_table (boost::shared_ptr<ARDOUR::Port>, uint32_t, bool);
uint32_t maybe_add_route_to_input_menu (boost::shared_ptr<ARDOUR::Route>, ARDOUR::DataType, boost::weak_ptr<ARDOUR::Port>);
void port_connected_or_disconnected (boost::weak_ptr<ARDOUR::Port>, boost::weak_ptr<ARDOUR::Port>);
@ -152,6 +156,9 @@ private:
PBD::ScopedConnection _io_connection;
boost::shared_ptr<ARDOUR::PluginInsert> _pi;
void queue_idle_update ();
bool idle_update ();
uint32_t _n_plugins;
ARDOUR::ChanCount _in, _ins, _out;
ARDOUR::ChanCount _sinks, _sources;
@ -172,6 +179,26 @@ private:
bool _dragging;
double _drag_x, _drag_y;
class Control: public sigc::trackable {
public:
Control (boost::shared_ptr<ARDOUR::AutomationControl>, std::string const &);
~Control ();
Gtk::Alignment box;
private:
void slider_adjusted ();
void control_changed ();
void set_tooltip ();
boost::weak_ptr<ARDOUR::AutomationControl> _control;
Gtk::Adjustment _adjustment;
Gtkmm2ext::HSliderController _slider;
Gtkmm2ext::PersistentTooltip _slider_persistant_tooltip;
bool _ignore_ui_adjustment;
sigc::connection timer_connection;
std::string _name;
};
std::list<Control*> _controls;
};
#endif