void
ARDOUR_UI::soloing_changed (bool onoff)
{
+ cerr << "solo change, " << onoff << endl;
+
if (solo_alert_button.get_active() != onoff) {
solo_alert_button.set_active (onoff);
}
-/*
- 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 <cstdlib>
-#include <gtkmm2ext/gtk_ui.h>
-#include <boost/bind.hpp>
-#include <boost/bind/protect.hpp>
-
-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__ */
+#include "gtkmm2ext/gui_thread.h"
, _tearoff (0)
, gain_adjustment (0.781787, 0.0, 1.0, 0.01, 0.1) // initial value is unity gain
, gain_control (0)
- , dim_adjustment (0.2, 0.0, 1.0, 0.01, 0.1)
+ , dim_adjustment (0.2, 0.0, 1.0, 0.01, 0.1) // upper+lower will be reset to match model
, dim_control (0)
- , solo_boost_adjustment (1.0, 1.0, 3.0, 0.01, 0.1)
+ , solo_boost_adjustment (1.0, 1.0, 3.0, 0.01, 0.1) // upper and lower will be reset to match model
, solo_boost_control (0)
- , solo_cut_adjustment (0.0, 0.0, 1.0, 0.01, 0.1)
+ , solo_cut_adjustment (0.0, 0.0, 1.0, 0.01, 0.1) // upper and lower will be reset to match model
, solo_cut_control (0)
, solo_in_place_button (solo_model_group, _("SiP"))
, afl_button (solo_model_group, _("AFL"))
}
set_session (s);
-
+
VBox* spin_packer;
Label* spin_label;
/* Dim */
dim_control = new VolumeController (little_knob_pixbuf, &dim_adjustment, false, 30, 30);
- dim_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &MonitorSection::dim_level_changed));
HBox* dim_packer = manage (new HBox);
dim_packer->show ();
/* Solo Boost */
solo_boost_control = new VolumeController (little_knob_pixbuf, &solo_boost_adjustment, false, 30, 30);
- solo_boost_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &MonitorSection::solo_boost_changed));
HBox* solo_packer = manage (new HBox);
solo_packer->set_spacing (12);
/* Solo (SiP) cut */
solo_cut_control = new VolumeController (little_knob_pixbuf, &solo_cut_adjustment, false, 30, 30);
- solo_cut_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &MonitorSection::solo_cut_changed));
spin_label = manage (new Label (_("SiP Cut")));
spin_packer = manage (new VBox);
/* Gain */
gain_control = new VolumeController (big_knob_pixbuf, &gain_adjustment, false, 80, 80);
- gain_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &MonitorSection::gain_value_changed));
spin_label = manage (new Label (_("Gain")));
spin_packer = manage (new VBox);
populate_buttons ();
map_state ();
+ assign_controllables ();
_tearoff = new TearOff (hpacker);
if (_route) {
/* session with control outs */
_monitor = _route->monitor_control ();
+ assign_controllables ();
} else {
/* session with no control outs */
_monitor.reset ();
_route.reset ();
}
+
} else {
/* no session */
_monitor.reset ();
_route.reset ();
+ control_connections.drop_connections ();
}
/* both might be null */
}
}
-void
-MonitorSection::gain_value_changed ()
-{
- if (_route) {
- _route->set_gain (slider_position_to_gain (gain_adjustment.get_value()), this);
- }
-}
-
-void
-MonitorSection::dim_level_changed ()
-{
- if (_monitor) {
- _monitor->set_dim_level (dim_adjustment.get_value());
- }
-}
-
-void
-MonitorSection::solo_boost_changed ()
-{
- if (_monitor) {
- _monitor->set_solo_boost_level (solo_boost_adjustment.get_value());
- }
-}
-
bool
MonitorSection::nonlinear_gain_printer (SpinButton* button)
{
solo_cut_adjustment.set_value (gain_to_slider_position (Config->get_solo_mute_gain()));
}
}
+
+void
+MonitorSection::assign_controllables ()
+{
+ boost::shared_ptr<Controllable> none;
+
+ if (!gain_control) {
+ /* too early - GUI controls not set up yet */
+ return;
+ }
+
+ if (_route) {
+ gain_control->set_controllable (_route->gain_control());
+ control_link (control_connections, _route->gain_control(), gain_adjustment);
+ } else {
+ gain_control->set_controllable (none);
+ }
+
+ if (_monitor) {
+
+ cut_all_button.set_controllable (_monitor->cut_control());
+ cut_all_button.watch ();
+ dim_all_button.set_controllable (_monitor->dim_control());
+ dim_all_button.watch ();
+ mono_button.set_controllable (_monitor->mono_control());
+ mono_button.watch ();
+
+ boost::shared_ptr<Controllable> c (_monitor->dim_level_control ());
+
+ dim_control->set_controllable (c);
+ dim_adjustment.set_lower (c->lower());
+ dim_adjustment.set_upper (c->upper());
+ control_link (control_connections, c, dim_adjustment);
+
+ c = _monitor->solo_boost_control ();
+ solo_boost_control->set_controllable (c);
+ solo_boost_adjustment.set_lower (c->lower());
+ solo_boost_adjustment.set_upper (c->upper());
+ control_link (control_connections, c, solo_boost_adjustment);
+
+ } else {
+
+ cut_all_button.set_controllable (none);
+ dim_all_button.set_controllable (none);
+ mono_button.set_controllable (none);
+
+ dim_control->set_controllable (none);
+ solo_boost_control->set_controllable (none);
+ }
+}
void parameter_changed (std::string);
PBD::ScopedConnection config_connection;
+ PBD::ScopedConnectionList control_connections;
+
+ void assign_controllables ();
};
#include "i18n.h"
#include "rgb_macros.h"
#include "canvas_impl.h"
+#include "gui_thread.h"
using namespace std;
using namespace Gtk;
return o;
}
+
+static void
+adjustment_to_controllable (Gtk::Adjustment* adj, boost::weak_ptr<Controllable> wcont)
+{
+ boost::shared_ptr<Controllable> cont = wcont.lock();
+
+ if (cont) {
+ double val = adj->get_value();
+ if (val != cont->get_value()) {
+ cont->set_value (val);
+ }
+ }
+}
+
+static void
+controllable_to_adjustment (Gtk::Adjustment* adj, boost::weak_ptr<Controllable> wcont)
+{
+ boost::shared_ptr<Controllable> cont = wcont.lock();
+
+ if (cont) {
+ float val = cont->get_value();
+
+ if (val != adj->get_value()) {
+ adj->set_value (val);
+ }
+ }
+}
+
+void
+control_link (ScopedConnectionList& scl, boost::shared_ptr<Controllable> c, Gtk::Adjustment& a)
+{
+ boost::weak_ptr<Controllable> wc (c);
+
+ a.signal_value_changed().connect (sigc::bind (sigc::ptr_fun (adjustment_to_controllable), &a, wc));
+ c->Changed.connect (scl, MISSING_INVALIDATOR, boost::bind (controllable_to_adjustment, &a, wc),
+ gui_context());
+}
+
#include "canvas.h"
+namespace PBD {
+ class Controllable;
+ class ScopedConnectionList;
+}
+
namespace Gtk {
class Window;
class ComboBoxText;
class Paned;
+ class Adjustment;
}
Glib::ustring fit_to_pixels (const Glib::ustring&, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses = false);
std::string escape_underscores (std::string const &);
+void control_link (PBD::ScopedConnectionList& scl, boost::shared_ptr<PBD::Controllable> c, Gtk::Adjustment& a);
+
#endif /* __ardour_gtk_utils_h__ */
*/
float get_value() const;
+ float lower() const { return parameter().min(); }
+ float upper() const { return parameter().max(); }
+
protected:
ARDOUR::Session& _session;
};
#ifndef __ardour_monitor_processor_h__
#define __ardour_monitor_processor_h__
+#include <iostream>
#include <vector>
#include "pbd/signals.h"
+#include "pbd/compose.h"
+#include "pbd/controllable.h"
#include "ardour/types.h"
#include "ardour/processor.h"
class Session;
+template<typename T> 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;
bool mono () const;
PBD::Signal0<void> Changed;
+
+ boost::shared_ptr<PBD::Controllable> channel_cut_control (uint32_t) const;
+ boost::shared_ptr<PBD::Controllable> channel_dim_control (uint32_t) const;
+ boost::shared_ptr<PBD::Controllable> channel_polarity_control (uint32_t) const;
+ boost::shared_ptr<PBD::Controllable> channel_solo_control (uint32_t) const;
+ boost::shared_ptr<PBD::Controllable> dim_control () const { return _dim_all_control; }
+ boost::shared_ptr<PBD::Controllable> cut_control () const { return _cut_all_control; }
+ boost::shared_ptr<PBD::Controllable> mono_control () const { return _mono_control; }
+ boost::shared_ptr<PBD::Controllable> dim_level_control () const { return _dim_level_control; }
+ boost::shared_ptr<PBD::Controllable> 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<gain_t>* cut_ptr;
+ MPControl<bool>* dim_ptr;
+ MPControl<gain_t>* polarity_ptr;
+ MPControl<bool>* soloed_ptr;
+
+ /* shared ptr access and lifetime management, for external users */
+
+ boost::shared_ptr<PBD::Controllable> cut_control;
+ boost::shared_ptr<PBD::Controllable> dim_control;
+ boost::shared_ptr<PBD::Controllable> polarity_control;
+ boost::shared_ptr<PBD::Controllable> soloed_control;
+
+ /* typed controllables for internal use */
+
+ MPControl<gain_t>& cut;
+ MPControl<bool>& dim;
+ MPControl<gain_t>& polarity;
+ MPControl<bool>& soloed;
+
+ ChannelRecord (uint32_t chn) : current_gain(1.0)
+ , cut_ptr (new MPControl<gain_t> (1.0, string_compose (_("cut control %1"), chn), PBD::Controllable::GainLike))
+ , dim_ptr (new MPControl<bool> (false, string_compose (_("dim control"), chn), PBD::Controllable::Toggle))
+ , polarity_ptr (new MPControl<gain_t> (1.0, string_compose (_("polarity control"), chn), PBD::Controllable::Toggle))
+ , soloed_ptr (new MPControl<bool> (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<ChannelRecord> _channels;
+
+ std::vector<ChannelRecord*> _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<bool>* _dim_all_ptr;
+ MPControl<bool>* _cut_all_ptr;
+ MPControl<bool>* _mono_ptr;
+ MPControl<volatile gain_t>* _dim_level_ptr;
+ MPControl<volatile gain_t>* _solo_boost_level_ptr;
+
+ /* shared ptr access and lifetime management, for external users */
+
+ boost::shared_ptr<PBD::Controllable> _dim_all_control;
+ boost::shared_ptr<PBD::Controllable> _cut_all_control;
+ boost::shared_ptr<PBD::Controllable> _mono_control;
+ boost::shared_ptr<PBD::Controllable> _dim_level_control;
+ boost::shared_ptr<PBD::Controllable> _solo_boost_level_control;
+
+ /* typed controllables for internal use */
+
+ MPControl<bool>& _dim_all;
+ MPControl<bool>& _cut_all;
+ MPControl<bool>& _mono;
+ MPControl<volatile gain_t>& _dim_level;
+ MPControl<volatile gain_t>& _solo_boost_level;
void allocate_channels (uint32_t);
};
using namespace PBD;
using namespace std;
+/* specialize for bool because of set_value() semantics */
+
+namespace ARDOUR {
+ template<> void MPControl<bool>::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<bool> (false, _("monitor dim"), Controllable::Toggle))
+ , _cut_all_ptr (new MPControl<bool> (false, _("monitor cut"), Controllable::Toggle))
+ , _mono_ptr (new MPControl<bool> (false, _("monitor mono"), Controllable::Toggle))
+ , _dim_level_ptr (new MPControl<volatile gain_t>
+ (0.2, _("monitor mono"), Controllable::Flag (0), 0.0f, 1.0f))
+ , _solo_boost_level_ptr (new MPControl<volatile gain_t>
+ (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));
}
}
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;
}
<< endmsg;
return -1;
}
- ChannelRecord& cr (_channels[chn]);
+ ChannelRecord& cr (*_channels[chn]);
if ((prop = (*i)->property ("cut")) != 0) {
if (string_is_affirmative (prop->value())){
solo_cnt = 0;
- for (vector<ChannelRecord>::const_iterator x = _channels.begin(); x != _channels.end(); ++x) {
- if (x->soloed) {
+ for (vector<ChannelRecord*>::const_iterator x = _channels.begin(); x != _channels.end(); ++x) {
+ if ((*x)->soloed) {
solo_cnt++;
}
}
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"));
XMLNode* chn_node;
uint32_t chn = 0;
- for (vector<ChannelRecord>::const_iterator x = _channels.begin(); x != _channels.end(); ++x, ++chn) {
+ for (vector<ChannelRecord*>::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);
}
/* 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;
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++;
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
{
return _cut_all;
}
+
+boost::shared_ptr<Controllable>
+MonitorProcessor::channel_cut_control (uint32_t chn) const
+{
+ if (chn < _channels.size()) {
+ return _channels[chn]->cut_control;
+ }
+ return boost::shared_ptr<Controllable>();
+}
+
+boost::shared_ptr<Controllable>
+MonitorProcessor::channel_dim_control (uint32_t chn) const
+{
+ if (chn < _channels.size()) {
+ return _channels[chn]->dim_control;
+ }
+ return boost::shared_ptr<Controllable>();
+}
+
+boost::shared_ptr<Controllable>
+MonitorProcessor::channel_polarity_control (uint32_t chn) const
+{
+ if (chn < _channels.size()) {
+ return _channels[chn]->polarity_control;
+ }
+ return boost::shared_ptr<Controllable>();
+}
+
+boost::shared_ptr<Controllable>
+MonitorProcessor::channel_solo_control (uint32_t chn) const
+{
+ if (chn < _channels.size()) {
+ return _channels[chn]->soloed_control;
+ }
+ return boost::shared_ptr<Controllable>();
+}
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.
*/
_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 */
}
if (!(*i)->is_hidden() && (*i)->listening()) {
- listeners++;
+ if (Config->get_solo_control_is_listen_control()) {
+ listeners++;
+ } else {
+ (*i)->set_listen (false, this);
+ }
}
}
*/
#include <string>
-#include <climits>
#include <iostream>
-#include <midi++/controllable.h>
+#include "pbd/controllable.h"
-#include <gtkmm2ext/gtk_ui.h>
-#include <gtkmm2ext/bindable_button.h>
+#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<PBD::Controllable> 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<Controllable> 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);
}
-
-
#include <string>
-#include <gtkmm2ext/stateful_button.h>
+#include "pbd/signals.h"
+#include "gtkmm2ext/stateful_button.h"
#include "binding_proxy.h"
namespace PBD {
}
boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); }
- void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); }
-
+ void set_controllable (boost::shared_ptr<PBD::Controllable> c);
+ void watch ();
+
+ protected:
+ void controllable_changed ();
+ PBD::ScopedConnection watch_connection;
+
private:
BindingProxy binding_proxy;
};
--- /dev/null
+/*
+ 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 <cstdlib>
+#include <gtkmm2ext/gtk_ui.h>
+#include <boost/bind.hpp>
+#include <boost/bind/protect.hpp>
+
+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__ */
#include <gtkmm/box.h>
#include <gtkmm/eventbox.h>
+#include "gtkmm2ext/binding_proxy.h"
+
namespace Gtk {
class Adjustment;
class SpinButton;
gfloat upper () { return _upper; }
gfloat range () { return _range; }
+ void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); }
+
protected:
gfloat _range;
gfloat _lower;
Gtk::SpinButton* value;
Gtk::Adjustment* adjustment;
Glib::RefPtr<Gdk::Pixbuf> pixbuf;
+ BindingProxy binding_proxy;
double default_value;
double step_inc;
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 ? */
'auto_spin.cc',
'barcontroller.cc',
'binding_proxy.cc',
+ 'bindable_button.cc',
'cell_renderer_pixbuf_multi.cc',
'cell_renderer_pixbuf_toggle.cc',
'choice.cc',
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);
#include <stdint.h>
#include <cmath>
#include <climits>
+#include <iostream>
#include "pbd/error.h"
#include "pbd/controllable_descriptor.h"
}
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<ARDOUR::AutomationControl*>(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;
}
float
MIDIControllable::midi_to_control(float val)
{
- float control_min = 0.0f;
- float control_max = 1.0f;
- ARDOUR::AutomationControl* ac = dynamic_cast<ARDOUR::AutomationControl*>(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;
}
return;
}
-
if (!controllable->is_toggle()) {
/* XXX gack - get rid of assumption about typeof pitchbend_t */
controllable->set_value ((pb/(float) SHRT_MAX));