mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-08 15:54:57 +01:00
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:
parent
30633cd2e7
commit
514765631b
2 changed files with 236 additions and 14 deletions
|
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
#include "plugin_pin_dialog.h"
|
#include "plugin_pin_dialog.h"
|
||||||
#include "gui_thread.h"
|
#include "gui_thread.h"
|
||||||
|
#include "timers.h"
|
||||||
#include "tooltips.h"
|
#include "tooltips.h"
|
||||||
#include "ui_config.h"
|
#include "ui_config.h"
|
||||||
|
|
||||||
|
|
@ -79,15 +80,15 @@ PluginPinDialog::PluginPinDialog (boost::shared_ptr<ARDOUR::PluginInsert> pi)
|
||||||
assert (pi->owner ()); // Route
|
assert (pi->owner ()); // Route
|
||||||
|
|
||||||
_pi->PluginIoReConfigure.connect (
|
_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 (
|
_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 (
|
_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);
|
_pin_box_size = 2 * ceil (max (8., 10. * UIConfiguration::instance ().get_ui_scale ()) * .5);
|
||||||
|
|
@ -223,6 +224,45 @@ PluginPinDialog::~PluginPinDialog ()
|
||||||
delete _sidechain_selector;
|
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
|
void
|
||||||
PluginPinDialog::plugin_reconfigured ()
|
PluginPinDialog::plugin_reconfigured ()
|
||||||
{
|
{
|
||||||
|
|
@ -348,6 +388,10 @@ PluginPinDialog::refill_sidechain_table ()
|
||||||
i = kids.erase (i);
|
i = kids.erase (i);
|
||||||
}
|
}
|
||||||
_sidechain_tbl->resize (1, 1);
|
_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) {
|
if (!_pi->has_sidechain () && _sidechain_selector) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -359,11 +403,11 @@ PluginPinDialog::refill_sidechain_table ()
|
||||||
uint32_t r = 0;
|
uint32_t r = 0;
|
||||||
PortSet& p (io->ports ());
|
PortSet& p (io->ports ());
|
||||||
bool can_remove = p.num_ports () > 1;
|
bool can_remove = p.num_ports () > 1;
|
||||||
for (PortSet::iterator i = p.begin (DataType::MIDI); i != p.end (DataType::MIDI); ++i, ++r) {
|
for (PortSet::iterator i = p.begin (DataType::MIDI); i != p.end (DataType::MIDI); ++i) {
|
||||||
add_port_to_table (*i, r, can_remove);
|
r += add_port_to_table (*i, r, can_remove);
|
||||||
}
|
}
|
||||||
for (PortSet::iterator i = p.begin (DataType::AUDIO); i != p.end (DataType::AUDIO); ++i, ++r) {
|
for (PortSet::iterator i = p.begin (DataType::AUDIO); i != p.end (DataType::AUDIO); ++i) {
|
||||||
add_port_to_table (*i, r, can_remove);
|
r += add_port_to_table (*i, r, can_remove);
|
||||||
}
|
}
|
||||||
_sidechain_tbl->show_all ();
|
_sidechain_tbl->show_all ();
|
||||||
}
|
}
|
||||||
|
|
@ -386,7 +430,7 @@ PluginPinDialog::refill_output_presets ()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pi->strict_io () && ppc.size () == 1) {
|
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 ()) {
|
if (ppc.find (2) != ppc.end ()) {
|
||||||
need_dropdown = false;
|
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)
|
PluginPinDialog::add_port_to_table (boost::shared_ptr<Port> p, uint32_t r, bool can_remove)
|
||||||
{
|
{
|
||||||
std::string lbl;
|
std::string lbl;
|
||||||
|
|
@ -507,6 +551,41 @@ PluginPinDialog::add_port_to_table (boost::shared_ptr<Port> p, uint32_t r, bool
|
||||||
} else {
|
} else {
|
||||||
pb->set_sensitive (false);
|
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
|
void
|
||||||
|
|
@ -1473,6 +1552,9 @@ PluginPinDialog::add_sidechain_port (DataType dt)
|
||||||
if (!io) {
|
if (!io) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this triggers a PluginIoReConfigure with process and processor write lock held
|
||||||
|
// from /this/ thread.
|
||||||
io->add_port ("", this, dt);
|
io->add_port ("", this, dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1619,9 +1701,122 @@ PluginPinDialog::port_connected_or_disconnected (boost::weak_ptr<ARDOUR::Port> w
|
||||||
if (!io) { return; }
|
if (!io) { return; }
|
||||||
|
|
||||||
if (p0 && io->has_port (p0)) {
|
if (p0 && io->has_port (p0)) {
|
||||||
plugin_reconfigured ();
|
queue_idle_update ();
|
||||||
}
|
}
|
||||||
else if (p1 && io->has_port (p1)) {
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,10 @@
|
||||||
#include "ardour/plugin_insert.h"
|
#include "ardour/plugin_insert.h"
|
||||||
#include "ardour/route.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_button.h"
|
||||||
#include "ardour_dropdown.h"
|
#include "ardour_dropdown.h"
|
||||||
#include "ardour_window.h"
|
#include "ardour_window.h"
|
||||||
|
|
@ -37,7 +41,7 @@ class PluginPinDialog : public ArdourWindow
|
||||||
public:
|
public:
|
||||||
PluginPinDialog (boost::shared_ptr<ARDOUR::PluginInsert>);
|
PluginPinDialog (boost::shared_ptr<ARDOUR::PluginInsert>);
|
||||||
~PluginPinDialog ();
|
~PluginPinDialog ();
|
||||||
|
void set_session (ARDOUR::Session *);
|
||||||
private:
|
private:
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Input,
|
Input,
|
||||||
|
|
@ -138,10 +142,10 @@ private:
|
||||||
bool handle_disconnect (const CtrlElem &, bool no_signal = false);
|
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_outputs (uint32_t skip_pc, ARDOUR::DataType dt, uint32_t id);
|
||||||
void disconnect_other_thru (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 remove_port (boost::weak_ptr<ARDOUR::Port>);
|
||||||
void disconnect_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>);
|
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>);
|
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>);
|
void port_connected_or_disconnected (boost::weak_ptr<ARDOUR::Port>, boost::weak_ptr<ARDOUR::Port>);
|
||||||
|
|
||||||
|
|
@ -152,6 +156,9 @@ private:
|
||||||
PBD::ScopedConnection _io_connection;
|
PBD::ScopedConnection _io_connection;
|
||||||
boost::shared_ptr<ARDOUR::PluginInsert> _pi;
|
boost::shared_ptr<ARDOUR::PluginInsert> _pi;
|
||||||
|
|
||||||
|
void queue_idle_update ();
|
||||||
|
bool idle_update ();
|
||||||
|
|
||||||
uint32_t _n_plugins;
|
uint32_t _n_plugins;
|
||||||
ARDOUR::ChanCount _in, _ins, _out;
|
ARDOUR::ChanCount _in, _ins, _out;
|
||||||
ARDOUR::ChanCount _sinks, _sources;
|
ARDOUR::ChanCount _sinks, _sources;
|
||||||
|
|
@ -172,6 +179,26 @@ private:
|
||||||
bool _dragging;
|
bool _dragging;
|
||||||
double _drag_x, _drag_y;
|
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
|
#endif
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue