From e69aca28426dd17a0f82ea01c7c98e217b4fdcc3 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 6 Apr 2010 16:57:35 +0000 Subject: MIDI/Controllables for monitor section, and related fixes git-svn-id: svn://localhost/ardour2/branches/3.0@6863 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/automation_control.h | 3 + libs/ardour/ardour/monitor_processor.h | 158 ++++++++++++++++++++++-- libs/ardour/monitor_processor.cc | 164 ++++++++++++++++++------- libs/ardour/session.cc | 16 ++- libs/gtkmm2ext/bindable_button.cc | 115 +++-------------- libs/gtkmm2ext/gtkmm2ext/bindable_button.h | 12 +- libs/gtkmm2ext/gtkmm2ext/gui_thread.h | 40 ++++++ libs/gtkmm2ext/gtkmm2ext/motionfeedback.h | 5 + libs/gtkmm2ext/motionfeedback.cc | 4 + libs/gtkmm2ext/wscript | 1 + libs/pbd/pbd/controllable.h | 3 + libs/surfaces/generic_midi/midicontrollable.cc | 38 +++--- 12 files changed, 376 insertions(+), 183 deletions(-) create mode 100644 libs/gtkmm2ext/gtkmm2ext/gui_thread.h (limited to 'libs') diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h index 15bac5fef8..3c832ae704 100644 --- a/libs/ardour/ardour/automation_control.h +++ b/libs/ardour/ardour/automation_control.h @@ -83,6 +83,9 @@ public: */ float get_value() const; + float lower() const { return parameter().min(); } + float upper() const { return parameter().max(); } + protected: ARDOUR::Session& _session; }; diff --git a/libs/ardour/ardour/monitor_processor.h b/libs/ardour/ardour/monitor_processor.h index 18c50e5104..8b8e90573d 100644 --- a/libs/ardour/ardour/monitor_processor.h +++ b/libs/ardour/ardour/monitor_processor.h @@ -20,9 +20,12 @@ #ifndef __ardour_monitor_processor_h__ #define __ardour_monitor_processor_h__ +#include #include #include "pbd/signals.h" +#include "pbd/compose.h" +#include "pbd/controllable.h" #include "ardour/types.h" #include "ardour/processor.h" @@ -33,10 +36,77 @@ namespace ARDOUR { class Session; +template class MPControl : public PBD::Controllable { + public: + MPControl (T initial, const std::string& name, PBD::Controllable::Flag flag, + float lower = 0.0f, float upper = 1.0f) + : PBD::Controllable (name, flag) + , _value (initial) + , _lower (lower) + , _upper (upper) + {} + + /* Controllable API */ + + void set_value (float v) { + T newval = (T) v; + if (newval != _value) { + _value = newval; + Changed(); /* EMIT SIGNAL */ + } + } + + float get_value () const { + return (float) _value; + } + + float lower () const { return _lower; } + float upper () const { return _upper; } + + /* "access as T" API */ + + MPControl& operator=(const T& v) { + if (v != _value) { + _value = v; + Changed (); /* EMIT SIGNAL */ + } + return *this; + } + + bool operator==(const T& v) const { + return _value == v; + } + + bool operator<(const T& v) const { + return _value < v; + } + + bool operator<=(const T& v) const { + return _value <= v; + } + + bool operator>(const T& v) const { + return _value > v; + } + + bool operator>=(const T& v) const { + return _value >= v; + } + + operator T() const { return _value; } + T val() const { return _value; } + + protected: + T _value; + T _lower; + T _upper; +}; + class MonitorProcessor : public Processor { public: MonitorProcessor (Session&); + ~MonitorProcessor (); bool display_to_user() const; @@ -71,27 +141,89 @@ class MonitorProcessor : public Processor bool mono () const; PBD::Signal0 Changed; + + boost::shared_ptr channel_cut_control (uint32_t) const; + boost::shared_ptr channel_dim_control (uint32_t) const; + boost::shared_ptr channel_polarity_control (uint32_t) const; + boost::shared_ptr channel_solo_control (uint32_t) const; + boost::shared_ptr dim_control () const { return _dim_all_control; } + boost::shared_ptr cut_control () const { return _cut_all_control; } + boost::shared_ptr mono_control () const { return _mono_control; } + boost::shared_ptr dim_level_control () const { return _dim_level_control; } + boost::shared_ptr solo_boost_control () const { return _solo_boost_level_control; } + private: struct ChannelRecord { gain_t current_gain; - gain_t cut; - bool dim; - gain_t polarity; - bool soloed; - ChannelRecord () - : current_gain(1.0), cut(1.0), dim(false), polarity(1.0), soloed (false) {} + /* pointers - created first, but managed by boost::shared_ptr<> */ + + MPControl* cut_ptr; + MPControl* dim_ptr; + MPControl* polarity_ptr; + MPControl* soloed_ptr; + + /* shared ptr access and lifetime management, for external users */ + + boost::shared_ptr cut_control; + boost::shared_ptr dim_control; + boost::shared_ptr polarity_control; + boost::shared_ptr soloed_control; + + /* typed controllables for internal use */ + + MPControl& cut; + MPControl& dim; + MPControl& polarity; + MPControl& soloed; + + ChannelRecord (uint32_t chn) : current_gain(1.0) + , cut_ptr (new MPControl (1.0, string_compose (_("cut control %1"), chn), PBD::Controllable::GainLike)) + , dim_ptr (new MPControl (false, string_compose (_("dim control"), chn), PBD::Controllable::Toggle)) + , polarity_ptr (new MPControl (1.0, string_compose (_("polarity control"), chn), PBD::Controllable::Toggle)) + , soloed_ptr (new MPControl (false, string_compose (_("solo control"), chn), PBD::Controllable::Toggle)) + + , cut_control (cut_ptr) + , dim_control (dim_ptr) + , polarity_control (polarity_ptr) + , soloed_control (soloed_ptr) + + , cut (*cut_ptr) + , dim (*dim_ptr) + , polarity (*polarity_ptr) + , soloed (*soloed_ptr) + + {} }; - - std::vector _channels; + + std::vector _channels; uint32_t solo_cnt; - bool _dim_all; - bool _cut_all; - bool _mono; - volatile gain_t _dim_level; - volatile gain_t _solo_boost_level; + + /* pointers - created first, but managed by boost::shared_ptr<> */ + + MPControl* _dim_all_ptr; + MPControl* _cut_all_ptr; + MPControl* _mono_ptr; + MPControl* _dim_level_ptr; + MPControl* _solo_boost_level_ptr; + + /* shared ptr access and lifetime management, for external users */ + + boost::shared_ptr _dim_all_control; + boost::shared_ptr _cut_all_control; + boost::shared_ptr _mono_control; + boost::shared_ptr _dim_level_control; + boost::shared_ptr _solo_boost_level_control; + + /* typed controllables for internal use */ + + MPControl& _dim_all; + MPControl& _cut_all; + MPControl& _mono; + MPControl& _dim_level; + MPControl& _solo_boost_level; void allocate_channels (uint32_t); }; diff --git a/libs/ardour/monitor_processor.cc b/libs/ardour/monitor_processor.cc index 51bd30a389..80ed2b8e5d 100644 --- a/libs/ardour/monitor_processor.cc +++ b/libs/ardour/monitor_processor.cc @@ -15,30 +15,68 @@ using namespace ARDOUR; using namespace PBD; using namespace std; +/* specialize for bool because of set_value() semantics */ + +namespace ARDOUR { + template<> void MPControl::set_value (float v) { + bool newval = fabs (v) >= 0.5; + if (newval != _value) { + _value = newval; + Changed(); /* EMIT SIGNAL */ + } + } +} + MonitorProcessor::MonitorProcessor (Session& s) : Processor (s, X_("MonitorOut")) + , solo_cnt (0) + + , _dim_all_ptr (new MPControl (false, _("monitor dim"), Controllable::Toggle)) + , _cut_all_ptr (new MPControl (false, _("monitor cut"), Controllable::Toggle)) + , _mono_ptr (new MPControl (false, _("monitor mono"), Controllable::Toggle)) + , _dim_level_ptr (new MPControl + (0.2, _("monitor mono"), Controllable::Flag (0), 0.0f, 1.0f)) + , _solo_boost_level_ptr (new MPControl + (1.0, _("monitor mono"), Controllable::Flag (0), 1.0f, 3.0f)) + + , _dim_all_control (_dim_all_ptr) + , _cut_all_control (_cut_all_ptr) + , _mono_control (_mono_ptr) + , _dim_level_control (_dim_level_ptr) + , _solo_boost_level_control (_solo_boost_level_ptr) + + , _dim_all (*_dim_all_ptr) + , _cut_all (*_cut_all_ptr) + , _mono (*_mono_ptr) + , _dim_level (*_dim_level_ptr) + , _solo_boost_level (*_solo_boost_level_ptr) + { - solo_cnt = 0; - _cut_all = false; - _dim_all = false; - _dim_level = 0.2; - _solo_boost_level = 1.0; +} + +MonitorProcessor::~MonitorProcessor () +{ + allocate_channels (0); } void MonitorProcessor::allocate_channels (uint32_t size) { while (_channels.size() > size) { - if (_channels.back().soloed) { + if (_channels.back()->soloed) { if (solo_cnt > 0) { --solo_cnt; } } + ChannelRecord* cr = _channels.back(); _channels.pop_back(); + delete cr; } + uint32_t n = _channels.size() + 1; + while (_channels.size() < size) { - _channels.push_back (ChannelRecord()); + _channels.push_back (new ChannelRecord (n)); } } @@ -74,12 +112,12 @@ MonitorProcessor::set_state (const XMLNode& node, int version) allocate_channels (atoi (prop->value())); if ((prop = node.property (X_("dim-level"))) != 0) { - double val = atof (prop->value()); + gain_t val = atof (prop->value()); _dim_level = val; } if ((prop = node.property (X_("solo-boost-level"))) != 0) { - double val = atof (prop->value()); + gain_t val = atof (prop->value()); _solo_boost_level = val; } @@ -118,7 +156,7 @@ MonitorProcessor::set_state (const XMLNode& node, int version) << endmsg; return -1; } - ChannelRecord& cr (_channels[chn]); + ChannelRecord& cr (*_channels[chn]); if ((prop = (*i)->property ("cut")) != 0) { if (string_is_affirmative (prop->value())){ @@ -152,8 +190,8 @@ MonitorProcessor::set_state (const XMLNode& node, int version) solo_cnt = 0; - for (vector::const_iterator x = _channels.begin(); x != _channels.end(); ++x) { - if (x->soloed) { + for (vector::const_iterator x = _channels.begin(); x != _channels.end(); ++x) { + if ((*x)->soloed) { solo_cnt++; } } @@ -171,10 +209,10 @@ MonitorProcessor::state (bool full) node.add_property (X_("type"), X_("monitor")); - snprintf (buf, sizeof(buf), "%.12g", _dim_level); + snprintf (buf, sizeof(buf), "%.12g", _dim_level.val()); node.add_property (X_("dim-level"), buf); - snprintf (buf, sizeof(buf), "%.12g", _solo_boost_level); + snprintf (buf, sizeof(buf), "%.12g", _solo_boost_level.val()); node.add_property (X_("solo-boost-level"), buf); node.add_property (X_("cut-all"), (_cut_all ? "yes" : "no")); @@ -189,16 +227,16 @@ MonitorProcessor::state (bool full) XMLNode* chn_node; uint32_t chn = 0; - for (vector::const_iterator x = _channels.begin(); x != _channels.end(); ++x, ++chn) { + for (vector::const_iterator x = _channels.begin(); x != _channels.end(); ++x, ++chn) { chn_node = new XMLNode (X_("Channel")); snprintf (buf, sizeof (buf), "%u", chn); chn_node->add_property ("id", buf); - - chn_node->add_property (X_("cut"), x->cut == 1.0 ? "no" : "yes"); - chn_node->add_property (X_("invert"), x->polarity == 1.0 ? "no" : "yes"); - chn_node->add_property (X_("dim"), x->dim ? "yes" : "no"); - chn_node->add_property (X_("solo"), x->soloed ? "yes" : "no"); + + chn_node->add_property (X_("cut"), (*x)->cut == 1.0f ? "no" : "yes"); + chn_node->add_property (X_("invert"), (*x)->polarity == 1.0f ? "no" : "yes"); + chn_node->add_property (X_("dim"), (*x)->dim ? "yes" : "no"); + chn_node->add_property (X_("solo"), (*x)->soloed ? "yes" : "no"); node.add_child_nocopy (*chn_node); } @@ -226,36 +264,38 @@ MonitorProcessor::run (BufferSet& bufs, sframes_t /*start_frame*/, sframes_t /*e /* don't double-scale by both track dim and global dim coefficients */ - gain_t dim_level = (global_dim == 1.0 ? (_channels[chn].dim ? dim_level_this_time : 1.0) : 1.0); + gain_t dim_level = (global_dim == 1.0 ? (_channels[chn]->dim ? dim_level_this_time : 1.0) : 1.0); - if (_channels[chn].soloed) { - target_gain = _channels[chn].polarity * _channels[chn].cut * dim_level * global_cut * global_dim * solo_boost; + if (_channels[chn]->soloed) { + target_gain = _channels[chn]->polarity * _channels[chn]->cut * dim_level * global_cut * global_dim * solo_boost; } else { if (solo_cnt == 0) { - target_gain = _channels[chn].polarity * _channels[chn].cut * dim_level * global_cut * global_dim * solo_boost; + target_gain = _channels[chn]->polarity * _channels[chn]->cut * dim_level * global_cut * global_dim * solo_boost; } else { target_gain = 0.0; } } DEBUG_TRACE (DEBUG::Monitor, - string_compose("channel %1 sb %2 gc %3 gd %4 cd %5 dl %6 cp %7 cc %8 cs %9 sc %10 TG %11\n", + string_compose("channel %1 SB %12 sb %2 gc %3 gd %4 cd %5 dl %6 cp %7 cc %8 cs %9 sc %10 TG %11\n", chn, solo_boost, global_cut, global_dim, - _channels[chn].dim, + _channels[chn]->dim, dim_level, - _channels[chn].polarity, - _channels[chn].cut, - _channels[chn].soloed, + _channels[chn]->polarity, + _channels[chn]->cut, + _channels[chn]->soloed, solo_cnt, - target_gain)); + target_gain, + (float) _solo_boost_level.val() + )); - if (target_gain != _channels[chn].current_gain || target_gain != 1.0f) { + if (target_gain != _channels[chn]->current_gain || target_gain != 1.0f) { - Amp::apply_gain (*b, nframes, _channels[chn].current_gain, target_gain); - _channels[chn].current_gain = target_gain; + Amp::apply_gain (*b, nframes, _channels[chn]->current_gain, target_gain); + _channels[chn]->current_gain = target_gain; } ++chn; @@ -317,33 +357,33 @@ void MonitorProcessor::set_polarity (uint32_t chn, bool invert) { if (invert) { - _channels[chn].polarity = -1.0f; + _channels[chn]->polarity = -1.0f; } else { - _channels[chn].polarity = 1.0f; + _channels[chn]->polarity = 1.0f; } } void MonitorProcessor::set_dim (uint32_t chn, bool yn) { - _channels[chn].dim = yn; + _channels[chn]->dim = yn; } void MonitorProcessor::set_cut (uint32_t chn, bool yn) { if (yn) { - _channels[chn].cut = 0.0f; + _channels[chn]->cut = 0.0f; } else { - _channels[chn].cut = 1.0f; + _channels[chn]->cut = 1.0f; } } void MonitorProcessor::set_solo (uint32_t chn, bool solo) { - if (solo != _channels[chn].soloed) { - _channels[chn].soloed = solo; + if (solo != _channels[chn]->soloed) { + _channels[chn]->soloed = solo; if (solo) { solo_cnt++; @@ -394,27 +434,27 @@ MonitorProcessor::set_solo_boost_level (gain_t val) bool MonitorProcessor::soloed (uint32_t chn) const { - return _channels[chn].soloed; + return _channels[chn]->soloed; } bool MonitorProcessor::inverted (uint32_t chn) const { - return _channels[chn].polarity < 0.0f; + return _channels[chn]->polarity < 0.0f; } bool MonitorProcessor::cut (uint32_t chn) const { - return _channels[chn].cut == 0.0f; + return _channels[chn]->cut == 0.0f; } bool MonitorProcessor::dimmed (uint32_t chn) const { - return _channels[chn].dim; + return _channels[chn]->dim; } bool @@ -434,3 +474,39 @@ MonitorProcessor::cut_all () const { return _cut_all; } + +boost::shared_ptr +MonitorProcessor::channel_cut_control (uint32_t chn) const +{ + if (chn < _channels.size()) { + return _channels[chn]->cut_control; + } + return boost::shared_ptr(); +} + +boost::shared_ptr +MonitorProcessor::channel_dim_control (uint32_t chn) const +{ + if (chn < _channels.size()) { + return _channels[chn]->dim_control; + } + return boost::shared_ptr(); +} + +boost::shared_ptr +MonitorProcessor::channel_polarity_control (uint32_t chn) const +{ + if (chn < _channels.size()) { + return _channels[chn]->polarity_control; + } + return boost::shared_ptr(); +} + +boost::shared_ptr +MonitorProcessor::channel_solo_control (uint32_t chn) const +{ + if (chn < _channels.size()) { + return _channels[chn]->soloed_control; + } + return boost::shared_ptr(); +} diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index ad04552820..22d2fc8037 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -2245,7 +2245,7 @@ Session::route_solo_changed (void* /*src*/, boost::weak_ptr wpr) delta = -1; } - /* now mod the solo level of all other routes except master & control outs + /* now mod the solo level of all other routes except master/control outs/auditioner so that they will be silent if appropriate. */ @@ -2269,12 +2269,18 @@ Session::route_solo_changed (void* /*src*/, boost::weak_ptr wpr) _master_out->mod_solo_by_others (1); } - /* ditto for control outs make sure master is never muted by solo */ + /* ditto for control outs make sure it is never muted by solo */ if (_monitor_out && route != _monitor_out && _monitor_out && _monitor_out->soloed_by_others() == 0) { _monitor_out->mod_solo_by_others (1); } + /* ditto for auditioner make sure it is never muted by solo */ + + if (auditioner) { + auditioner->mod_solo_by_others (1); + } + solo_update_disabled = false; update_route_solo_state (r); SoloChanged (); /* EMIT SIGNAL */ @@ -2300,7 +2306,11 @@ Session::update_route_solo_state (boost::shared_ptr r) } if (!(*i)->is_hidden() && (*i)->listening()) { - listeners++; + if (Config->get_solo_control_is_listen_control()) { + listeners++; + } else { + (*i)->set_listen (false, this); + } } } diff --git a/libs/gtkmm2ext/bindable_button.cc b/libs/gtkmm2ext/bindable_button.cc index 3c3cad6e46..5c0cc3c958 100644 --- a/libs/gtkmm2ext/bindable_button.cc +++ b/libs/gtkmm2ext/bindable_button.cc @@ -18,122 +18,43 @@ */ #include -#include #include -#include +#include "pbd/controllable.h" -#include -#include +#include "gtkmm2ext/gtk_ui.h" +#include "gtkmm2ext/bindable_button.h" +#include "gtkmm2ext/gui_thread.h" #include "i18n.h" using namespace Gtkmm2ext; using namespace std; - -BindableToggleButton::BindableToggleButton (MIDI::Controllable *mc) - : prompter (Gtk::WIN_POS_MOUSE, 30000, false), - midi_control (mc), - bind_button (2), - bind_statemask (Gdk::CONTROL_MASK) - -{ - init_events (); -} - -BindableToggleButton::BindableToggleButton(MIDI::Controllable *mc, const string &label) - : StatefulButton (label), - prompter (Gtk::WIN_POS_MOUSE, 30000, false), - midi_control (mc), - bind_button (2), - bind_statemask (Gdk::CONTROL_MASK) -{ - init_events (); -} - +using namespace PBD; void -BindableToggleButton::init_events () +BindableToggleButton::set_controllable (boost::shared_ptr c) { - prompter.signal_unmap_event().connect (mem_fun (*this, &BindableToggleButton::prompter_hiding)); - - prompting = false; - unprompting = false; - - if (midi_control) { - midi_control->learning_started.connect (mem_fun (*this, &BindableToggleButton::midicontrol_prompt)); - midi_control->learning_stopped.connect (mem_fun (*this, &BindableToggleButton::midicontrol_unprompt)); - } + watch_connection.disconnect (); + binding_proxy.set_controllable (c); } void -BindableToggleButton::set_bind_button_state (guint button, guint statemask) +BindableToggleButton::watch () { - bind_button = button; - bind_statemask = statemask; -} + boost::shared_ptr c (binding_proxy.get_controllable ()); -void -BindableToggleButton::get_bind_button_state (guint &button, guint &statemask) -{ - button = bind_button; - statemask = bind_statemask; -} + if (!c) { + warning << _("button cannot watch state of non-existing Controllable\n") << endl; + return; + } -void -BindableToggleButton::midi_learn() -{ - if (midi_control) { - prompting = true; - midi_control->learn_about_external_control (); - } -} - -bool -BindableToggleButton::prompter_hiding (GdkEventAny *ev) -{ - if (unprompting) { - if (midi_control) { - midi_control->stop_learning(); - } - unprompting = false; - } - - return false; -} - - -void -BindableToggleButton::midicontrol_set_tip () - -{ - if (midi_control) { - // Gtkmm2ext::UI::instance()->set_tip (evbox, midi_control->control_description()); - } -} - -void -BindableToggleButton::midicontrol_prompt () - -{ - if (prompting) { - string prompt = _("operate MIDI controller now"); - prompter.set_text (prompt); - Gtkmm2ext::UI::instance()->touch_display (&prompter); - - unprompting = true; - prompting = false; - } + c->Changed.connect (watch_connection, invalidator(*this), boost::bind (&BindableToggleButton::controllable_changed, this), gui_context()); } void -BindableToggleButton::midicontrol_unprompt () - +BindableToggleButton::controllable_changed () { - if (unprompting) { - Gtkmm2ext::UI::instance()->touch_display (&prompter); - unprompting = false; - } + float val = binding_proxy.get_controllable()->get_value(); + set_active (fabs (val) >= 0.5f); } - - diff --git a/libs/gtkmm2ext/gtkmm2ext/bindable_button.h b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h index 18e3ceb339..5ac81d8507 100644 --- a/libs/gtkmm2ext/gtkmm2ext/bindable_button.h +++ b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h @@ -22,7 +22,8 @@ #include -#include +#include "pbd/signals.h" +#include "gtkmm2ext/stateful_button.h" #include "binding_proxy.h" namespace PBD { @@ -48,8 +49,13 @@ class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton } boost::shared_ptr get_controllable() { return binding_proxy.get_controllable(); } - void set_controllable (boost::shared_ptr c) { binding_proxy.set_controllable (c); } - + void set_controllable (boost::shared_ptr c); + void watch (); + + protected: + void controllable_changed (); + PBD::ScopedConnection watch_connection; + private: BindingProxy binding_proxy; }; diff --git a/libs/gtkmm2ext/gtkmm2ext/gui_thread.h b/libs/gtkmm2ext/gtkmm2ext/gui_thread.h new file mode 100644 index 0000000000..16dc0600a1 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/gui_thread.h @@ -0,0 +1,40 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_gtk_gui_thread_h__ +#define __ardour_gtk_gui_thread_h__ + +#include +#include +#include +#include + +namespace sigc { + class trackable; +} + +#define ENSURE_GUI_THREAD(obj,method, ...) if (!Gtkmm2ext::UI::instance()->caller_is_self()) { abort (); } + +#define gui_context() Gtkmm2ext::UI::instance() /* a UICallback-derived object that specifies the event loop for GUI signal handling */ +#define ui_bind(f, ...) boost::protect (boost::bind (f, __VA_ARGS__)) + +extern PBD::EventLoop::InvalidationRecord* __invalidator (sigc::trackable& trackable, const char*, int); +#define invalidator(x) __invalidator ((x), __FILE__, __LINE__) + +#endif /* __ardour_gtk_gui_thread_h__ */ diff --git a/libs/gtkmm2ext/gtkmm2ext/motionfeedback.h b/libs/gtkmm2ext/gtkmm2ext/motionfeedback.h index a3a06d39d3..cb256bed22 100644 --- a/libs/gtkmm2ext/gtkmm2ext/motionfeedback.h +++ b/libs/gtkmm2ext/gtkmm2ext/motionfeedback.h @@ -24,6 +24,8 @@ #include #include +#include "gtkmm2ext/binding_proxy.h" + namespace Gtk { class Adjustment; class SpinButton; @@ -59,6 +61,8 @@ class MotionFeedback : public Gtk::VBox gfloat upper () { return _upper; } gfloat range () { return _range; } + void set_controllable (boost::shared_ptr c) { binding_proxy.set_controllable (c); } + protected: gfloat _range; gfloat _lower; @@ -84,6 +88,7 @@ class MotionFeedback : public Gtk::VBox Gtk::SpinButton* value; Gtk::Adjustment* adjustment; Glib::RefPtr pixbuf; + BindingProxy binding_proxy; double default_value; double step_inc; diff --git a/libs/gtkmm2ext/motionfeedback.cc b/libs/gtkmm2ext/motionfeedback.cc index 19ce16d815..06aa2e507e 100644 --- a/libs/gtkmm2ext/motionfeedback.cc +++ b/libs/gtkmm2ext/motionfeedback.cc @@ -138,6 +138,10 @@ MotionFeedback::set_adjustment (Adjustment *adj) bool MotionFeedback::pixwin_button_press_event (GdkEventButton *ev) { + if (binding_proxy.button_press_handler (ev)) { + return true; + } + switch (ev->button) { case 2: return FALSE; /* XXX why ? */ diff --git a/libs/gtkmm2ext/wscript b/libs/gtkmm2ext/wscript index dec5c94c5d..1db7016a24 100644 --- a/libs/gtkmm2ext/wscript +++ b/libs/gtkmm2ext/wscript @@ -23,6 +23,7 @@ gtkmm2ext_sources = [ 'auto_spin.cc', 'barcontroller.cc', 'binding_proxy.cc', + 'bindable_button.cc', 'cell_renderer_pixbuf_multi.cc', 'cell_renderer_pixbuf_toggle.cc', 'choice.cc', diff --git a/libs/pbd/pbd/controllable.h b/libs/pbd/pbd/controllable.h index f8d8f82855..9f5ed5251b 100644 --- a/libs/pbd/pbd/controllable.h +++ b/libs/pbd/pbd/controllable.h @@ -72,6 +72,9 @@ class Controllable : public PBD::StatefulDestructible { bool is_gain_like() const { return _flags & GainLike; } bool is_integral_only() const { return _flags & IntegerOnly; } + virtual float lower() const { return 0.0f; } + virtual float upper() const { return 1.0f; } + Flag flags() const { return _flags; } void set_flags (Flag f); diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc index 6087a857be..32b6ff8fe1 100644 --- a/libs/surfaces/generic_midi/midicontrollable.cc +++ b/libs/surfaces/generic_midi/midicontrollable.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include "pbd/error.h" #include "pbd/controllable_descriptor.h" @@ -133,18 +134,17 @@ MIDIControllable::stop_learning () } float -MIDIControllable::control_to_midi(float val) +MIDIControllable::control_to_midi (float val) { - float control_min = 0.0f; - float control_max = 1.0f; - ARDOUR::AutomationControl* ac = dynamic_cast(controllable); - if (ac) { - control_min = ac->parameter().min(); - control_max = ac->parameter().max(); - } + const float midi_range = 127.0f; // TODO: NRPN etc. + + if (controllable->is_gain_like()) { + return gain_to_slider_position (val/midi_range); + } + float control_min = controllable->lower (); + float control_max = controllable->upper (); const float control_range = control_max - control_min; - const float midi_range = 127.0f; // TODO: NRPN etc. return (val - control_min) / control_range * midi_range; } @@ -152,23 +152,16 @@ MIDIControllable::control_to_midi(float val) float MIDIControllable::midi_to_control(float val) { - float control_min = 0.0f; - float control_max = 1.0f; - ARDOUR::AutomationControl* ac = dynamic_cast(controllable); - const float midi_range = 127.0f; // TODO: NRPN etc. - - if (ac) { - if (ac->is_gain_like()) { - return slider_position_to_gain (val/midi_range); - } - - control_min = ac->parameter().min(); - control_max = ac->parameter().max(); - } + if (controllable->is_gain_like()) { + return slider_position_to_gain (val/midi_range); + } + float control_min = controllable->lower (); + float control_max = controllable->upper (); const float control_range = control_max - control_min; + return val / midi_range * control_range + control_min; } @@ -254,7 +247,6 @@ MIDIControllable::midi_sense_pitchbend (Parser &, pitchbend_t pb) return; } - if (!controllable->is_toggle()) { /* XXX gack - get rid of assumption about typeof pitchbend_t */ controllable->set_value ((pb/(float) SHRT_MAX)); -- cgit v1.2.3