13
0

faderport: some code cleanups, add timing for button presses, add new comboboxes to GUI to allow more button programming, save button state

This commit is contained in:
Paul Davis 2015-11-30 12:51:18 -05:00
parent 149f6795bb
commit 682e152aaf
5 changed files with 547 additions and 280 deletions

View File

@ -94,77 +94,73 @@ FaderPort::FaderPort (Session& s)
/* Catch port connections and disconnections */
ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort::connection_handler, this, _1, _2, _3, _4, _5), this);
buttons.insert (std::make_pair (Mute, ButtonInfo (*this, _("Mute"), Mute, 21)));
buttons.insert (std::make_pair (Solo, ButtonInfo (*this, _("Solo"), Solo, 22)));
buttons.insert (std::make_pair (Rec, ButtonInfo (*this, _("Rec"), Rec, 23)));
buttons.insert (std::make_pair (Left, ButtonInfo (*this, _("Left"), Left, 20)));
buttons.insert (std::make_pair (Bank, ButtonInfo (*this, _("Bank"), Bank, 19)));
buttons.insert (std::make_pair (Right, ButtonInfo (*this, _("Right"), Right, 18)));
buttons.insert (std::make_pair (Output, ButtonInfo (*this, _("Output"), Output, 17)));
buttons.insert (std::make_pair (FP_Read, ButtonInfo (*this, _("Read"), FP_Read, 13)));
buttons.insert (std::make_pair (FP_Write, ButtonInfo (*this, _("Write"), FP_Write, 14)));
buttons.insert (std::make_pair (FP_Touch, ButtonInfo (*this, _("Touch"), FP_Touch, 15)));
buttons.insert (std::make_pair (FP_Off, ButtonInfo (*this, _("Off"), FP_Off, 16)));
buttons.insert (std::make_pair (Mix, ButtonInfo (*this, _("Mix"), Mix, 12)));
buttons.insert (std::make_pair (Proj, ButtonInfo (*this, _("Proj"), Proj, 11)));
buttons.insert (std::make_pair (Trns, ButtonInfo (*this, _("Trns"), Trns, 10)));
buttons.insert (std::make_pair (Undo, ButtonInfo (*this, _("Undo"), Undo, 9)));
buttons.insert (std::make_pair (Shift, ButtonInfo (*this, _("Shift"), Shift, 5)));
buttons.insert (std::make_pair (Punch, ButtonInfo (*this, _("Punch"), Punch, 6)));
buttons.insert (std::make_pair (User, ButtonInfo (*this, _("User"), User, 7)));
buttons.insert (std::make_pair (Loop, ButtonInfo (*this, _("Loop"), Loop, 8)));
buttons.insert (std::make_pair (Rewind, ButtonInfo (*this, _("Rewind"), Rewind, 4)));
buttons.insert (std::make_pair (Ffwd, ButtonInfo (*this, _("Ffwd"), Ffwd, 3)));
buttons.insert (std::make_pair (Stop, ButtonInfo (*this, _("Stop"), Stop, 2)));
buttons.insert (std::make_pair (Play, ButtonInfo (*this, _("Play"), Play, 1)));
buttons.insert (std::make_pair (RecEnable, ButtonInfo (*this, _("RecEnable"), RecEnable, 0)));
buttons.insert (std::make_pair (FaderTouch, ButtonInfo (*this, _("Fader (touch)"), FaderTouch, -1)));
buttons.insert (std::make_pair (Mute, Button (*this, _("Mute"), Mute, 21)));
buttons.insert (std::make_pair (Solo, Button (*this, _("Solo"), Solo, 22)));
buttons.insert (std::make_pair (Rec, Button (*this, _("Rec"), Rec, 23)));
buttons.insert (std::make_pair (Left, Button (*this, _("Left"), Left, 20)));
buttons.insert (std::make_pair (Bank, Button (*this, _("Bank"), Bank, 19)));
buttons.insert (std::make_pair (Right, Button (*this, _("Right"), Right, 18)));
buttons.insert (std::make_pair (Output, Button (*this, _("Output"), Output, 17)));
buttons.insert (std::make_pair (FP_Read, Button (*this, _("Read"), FP_Read, 13)));
buttons.insert (std::make_pair (FP_Write, Button (*this, _("Write"), FP_Write, 14)));
buttons.insert (std::make_pair (FP_Touch, Button (*this, _("Touch"), FP_Touch, 15)));
buttons.insert (std::make_pair (FP_Off, Button (*this, _("Off"), FP_Off, 16)));
buttons.insert (std::make_pair (Mix, Button (*this, _("Mix"), Mix, 12)));
buttons.insert (std::make_pair (Proj, Button (*this, _("Proj"), Proj, 11)));
buttons.insert (std::make_pair (Trns, Button (*this, _("Trns"), Trns, 10)));
buttons.insert (std::make_pair (Undo, Button (*this, _("Undo"), Undo, 9)));
buttons.insert (std::make_pair (Shift, Button (*this, _("Shift"), Shift, 5)));
buttons.insert (std::make_pair (Punch, Button (*this, _("Punch"), Punch, 6)));
buttons.insert (std::make_pair (User, Button (*this, _("User"), User, 7)));
buttons.insert (std::make_pair (Loop, Button (*this, _("Loop"), Loop, 8)));
buttons.insert (std::make_pair (Rewind, Button (*this, _("Rewind"), Rewind, 4)));
buttons.insert (std::make_pair (Ffwd, Button (*this, _("Ffwd"), Ffwd, 3)));
buttons.insert (std::make_pair (Stop, Button (*this, _("Stop"), Stop, 2)));
buttons.insert (std::make_pair (Play, Button (*this, _("Play"), Play, 1)));
buttons.insert (std::make_pair (RecEnable, Button (*this, _("RecEnable"), RecEnable, 0)));
buttons.insert (std::make_pair (FaderTouch, Button (*this, _("Fader (touch)"), FaderTouch, -1)));
button_info (Mix).set_action ( string("Common/toggle-editor-mixer"), true);
button_info (Proj).set_action ( string("Common/toggle-meterbridge"), true);
button_info (Trns).set_action ( string("Window/toggle-locations"), true);
get_button (Left).set_action ( boost::bind (&FaderPort::left, this), true);
get_button (Right).set_action ( boost::bind (&FaderPort::right, this), true);
button_info (Left).set_action ( boost::bind (&FaderPort::left, this), true);
button_info (Right).set_action ( boost::bind (&FaderPort::right, this), true);
get_button (Undo).set_action (boost::bind (&FaderPort::undo, this), true);
get_button (Undo).set_action (boost::bind (&FaderPort::redo, this), true, ShiftDown);
get_button (Undo).set_flash (true);
button_info (Undo).set_action (boost::bind (&FaderPort::undo, this), true);
button_info (Undo).set_action (boost::bind (&FaderPort::redo, this), true, ShiftDown);
button_info (Undo).set_flash (true);
get_button (FP_Read).set_action (boost::bind (&FaderPort::read, this), true);
get_button (FP_Write).set_action (boost::bind (&FaderPort::write, this), true);
get_button (FP_Touch).set_action (boost::bind (&FaderPort::touch, this), true);
get_button (FP_Off).set_action (boost::bind (&FaderPort::off, this), true);
button_info (FP_Read).set_action (boost::bind (&FaderPort::read, this), true);
button_info (FP_Write).set_action (boost::bind (&FaderPort::write, this), true);
button_info (FP_Touch).set_action (boost::bind (&FaderPort::touch, this), true);
button_info (FP_Off).set_action (boost::bind (&FaderPort::off, this), true);
button_info (Play).set_action (boost::bind (&BasicUI::transport_play, this, true), true);
button_info (RecEnable).set_action (boost::bind (&BasicUI::rec_enable_toggle, this), true);
get_button (Play).set_action (boost::bind (&BasicUI::transport_play, this, true), true);
get_button (RecEnable).set_action (boost::bind (&BasicUI::rec_enable_toggle, this), true);
/* Stop is a modifier, so we have to use its own button state to get
the default action (since StopDown will be set when looking for the
action to invoke.
*/
button_info (Stop).set_action (boost::bind (&BasicUI::transport_stop, this), true, StopDown);
button_info (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
get_button (Stop).set_action (boost::bind (&BasicUI::transport_stop, this), true, StopDown);
get_button (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
/* See comments about Stop above .. */
button_info (Rewind).set_action (boost::bind (&BasicUI::rewind, this), true, RewindDown);
button_info (Rewind).set_action (boost::bind (&BasicUI::goto_zero, this), true, ButtonState (RewindDown|StopDown));
button_info (Rewind).set_action (boost::bind (&BasicUI::goto_start, this), true, ButtonState (RewindDown|ShiftDown));
get_button (Rewind).set_action (boost::bind (&BasicUI::rewind, this), true, RewindDown);
get_button (Rewind).set_action (boost::bind (&BasicUI::goto_zero, this), true, ButtonState (RewindDown|StopDown));
get_button (Rewind).set_action (boost::bind (&BasicUI::goto_start, this), true, ButtonState (RewindDown|ShiftDown));
button_info (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
button_info (Ffwd).set_action (boost::bind (&BasicUI::goto_end, this), true, ShiftDown);
get_button (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
get_button (Ffwd).set_action (boost::bind (&BasicUI::goto_end, this), true, ShiftDown);
button_info (Loop).set_action (boost::bind (&BasicUI::loop_toggle, this), true);
button_info (Loop).set_action (boost::bind (&BasicUI::add_marker, this, string()), true, ShiftDown);
get_button (Loop).set_action (boost::bind (&BasicUI::loop_toggle, this), true);
get_button (Loop).set_action (boost::bind (&BasicUI::add_marker, this, string()), true, ShiftDown);
button_info (Punch).set_action (boost::bind (&BasicUI::prev_marker, this), true, ShiftDown);
button_info (User).set_action (boost::bind (&BasicUI::next_marker, this), true, ShiftDown);
get_button (Punch).set_action (boost::bind (&BasicUI::prev_marker, this), true, ShiftDown);
get_button (User).set_action (boost::bind (&BasicUI::next_marker, this), true, ShiftDown);
button_info (Mute).set_action (boost::bind (&FaderPort::mute, this), true);
button_info (Solo).set_action (boost::bind (&FaderPort::solo, this), true);
button_info (Rec).set_action (boost::bind (&FaderPort::rec_enable, this), true);
get_button (Mute).set_action (boost::bind (&FaderPort::mute, this), true);
get_button (Solo).set_action (boost::bind (&FaderPort::solo, this), true);
get_button (Rec).set_action (boost::bind (&FaderPort::rec_enable, this), true);
button_info (Output).set_action (boost::bind (&FaderPort::use_master, this), true);
button_info (Output).set_action (boost::bind (&FaderPort::use_monitor, this), true, ShiftDown);
get_button (Output).set_action (boost::bind (&FaderPort::use_master, this), true);
get_button (Output).set_action (boost::bind (&FaderPort::use_monitor, this), true, ShiftDown);
}
FaderPort::~FaderPort ()
@ -190,8 +186,8 @@ FaderPort::start_midi_handling ()
{
/* handle device inquiry response */
_input_port->parser()->sysex.connect_same_thread (midi_connections, boost::bind (&FaderPort::sysex_handler, this, _1, _2, _3));
/* handle switches */
_input_port->parser()->poly_pressure.connect_same_thread (midi_connections, boost::bind (&FaderPort::switch_handler, this, _1, _2));
/* handle buttons */
_input_port->parser()->poly_pressure.connect_same_thread (midi_connections, boost::bind (&FaderPort::button_handler, this, _1, _2));
/* handle encoder */
_input_port->parser()->pitchbend.connect_same_thread (midi_connections, boost::bind (&FaderPort::encoder_handler, this, _1, _2));
/* handle fader */
@ -263,18 +259,21 @@ FaderPort::all_lights_out ()
}
}
FaderPort::ButtonInfo&
FaderPort::button_info (ButtonID id) const
FaderPort::Button&
FaderPort::get_button (ButtonID id) const
{
ButtonMap::const_iterator b = buttons.find (id);
assert (b != buttons.end());
return const_cast<ButtonInfo&>(b->second);
return const_cast<Button&>(b->second);
}
void
FaderPort::switch_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
FaderPort::button_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
{
ButtonID id (ButtonID (tb->controller_number));
Button& button (get_button (id));
button.do_timing (tb->value ? true : false);
switch (id) {
case Shift:
@ -307,13 +306,11 @@ FaderPort::switch_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
break;
}
ButtonInfo& bi (button_info (id));
if (bi.uses_flash()) {
bi.set_led_state (_output_port, (int)tb->value);
if (button.uses_flash()) {
button.set_led_state (_output_port, (int)tb->value);
}
bi.invoke (button_state, tb->value ? true : false);
button.invoke (button_state, tb->value ? true : false);
}
void
@ -489,7 +486,7 @@ FaderPort::blink ()
blink_state = !blink_state;
for (Blinkers::iterator b = blinkers.begin(); b != blinkers.end(); b++) {
button_info(*b).set_led_state (_output_port, blink_state);
get_button(*b).set_led_state (_output_port, blink_state);
}
return true;
@ -517,15 +514,15 @@ FaderPort::notify_record_state_changed ()
{
switch (session->record_status()) {
case Session::Disabled:
button_info (RecEnable).set_led_state (_output_port, false);
get_button (RecEnable).set_led_state (_output_port, false);
blinkers.remove (RecEnable);
break;
case Session::Enabled:
button_info (RecEnable).set_led_state (_output_port, true);
get_button (RecEnable).set_led_state (_output_port, true);
blinkers.push_back (RecEnable);
break;
case Session::Recording:
button_info (RecEnable).set_led_state (_output_port, true);
get_button (RecEnable).set_led_state (_output_port, true);
blinkers.remove (RecEnable);
break;
}
@ -534,11 +531,11 @@ FaderPort::notify_record_state_changed ()
void
FaderPort::notify_transport_state_changed ()
{
button_info (Loop).set_led_state (_output_port, session->get_play_loop());
button_info (Play).set_led_state (_output_port, session->transport_speed() == 1.0);
button_info (Stop).set_led_state (_output_port, session->transport_stopped ());
button_info (Rewind).set_led_state (_output_port, session->transport_speed() < 0.0);
button_info (Ffwd).set_led_state (_output_port, session->transport_speed() > 1.0);
get_button (Loop).set_led_state (_output_port, session->get_play_loop());
get_button (Play).set_led_state (_output_port, session->transport_speed() == 1.0);
get_button (Stop).set_led_state (_output_port, session->transport_stopped ());
get_button (Rewind).set_led_state (_output_port, session->transport_speed() < 0.0);
get_button (Ffwd).set_led_state (_output_port, session->transport_speed() > 1.0);
}
void
@ -588,6 +585,17 @@ FaderPort::get_state ()
child->add_child_nocopy (boost::shared_ptr<ARDOUR::Port>(_output_port)->get_state());
node.add_child_nocopy (*child);
/* Save action state for Mix, Proj, Trns and User buttons, since these
* are user controlled. We can only save named-action operations, since
* internal functions are just pointers to functions and hard to
* serialize without enumerating them all somewhere.
*/
node.add_child_nocopy (get_button (Mix).get_state());
node.add_child_nocopy (get_button (Proj).get_state());
node.add_child_nocopy (get_button (Trns).get_state());
node.add_child_nocopy (get_button (User).get_state());
return node;
}
@ -616,6 +624,21 @@ FaderPort::set_state (const XMLNode& node, int version)
}
}
for (XMLNodeList::const_iterator n = node.children().begin(); n != node.children().end(); ++n) {
if ((*n)->name() == X_("Button")) {
XMLProperty const * prop = (*n)->property (X_("id"));
if (!prop) {
continue;
}
int xid = atoi (prop->value());
ButtonMap::iterator b = buttons.find (ButtonID (xid));
if (b == buttons.end()) {
continue;
}
b->second.set_state (**n);
}
}
return 0;
}
@ -646,6 +669,8 @@ FaderPort::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1,
return false;
}
cerr << "Connection state = " << hex << connection_state << dec << endl;
if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
/* XXX this is a horrible hack. Without a short sleep here,
@ -661,13 +686,15 @@ FaderPort::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1,
_device_active = false;
}
ConnectionChange (); /* emit signal for our GUI */
return true; /* connection status changed */
}
void
FaderPort::connected ()
{
std::cerr << "faderport connected\n";
std::cerr << "faderport connected or disconnected\n";
start_midi_handling ();
@ -686,68 +713,91 @@ FaderPort::connected ()
}
void
FaderPort::ButtonInfo::invoke (FaderPort::ButtonState bs, bool press)
FaderPort::Button::invoke (FaderPort::ButtonState bs, bool press)
{
switch (type) {
if (!press) {
if (long_press == 1) {
bs = FaderPort::ButtonState (bs | LongishPress);
} else if (long_press == 2) {
bs = FaderPort::ButtonState (bs | LongPress);
}
}
ToDoMap::iterator x;
if (press) {
if ((x = on_press.find (bs)) == on_press.end()) {
return;
}
} else {
if ((x = on_press.find (bs)) == on_release.end()) {
return;
}
}
switch (x->second.type) {
case NamedAction:
if (press) {
ToDoMap::iterator x = on_press.find (bs);
if (x != on_press.end()) {
if (!x->second.action_name.empty()) {
fp.access_action (x->second.action_name);
}
}
} else {
ToDoMap::iterator x = on_release.find (bs);
if (x != on_release.end()) {
if (!x->second.action_name.empty()) {
fp.access_action (x->second.action_name);
}
}
if (!x->second.action_name.empty()) {
fp.access_action (x->second.action_name);
}
break;
break;
case InternalFunction:
if (press) {
ToDoMap::iterator x = on_press.find (bs);
if (x != on_press.end()) {
if (x->second.function) {
x->second.function ();
}
}
} else {
ToDoMap::iterator x = on_release.find (bs);
if (x != on_release.end()) {
if (x->second.function) {
x->second.function ();
}
}
if (x->second.function) {
x->second.function ();
}
break;
}
}
void
FaderPort::ButtonInfo::set_action (string const& name, bool when_pressed, FaderPort::ButtonState bs)
FaderPort::Button::do_timing (bool press)
{
if (press) {
pressed_at = get_microseconds ();
long_press = 0;
} else {
if (pressed_at > 0) {
const ARDOUR::microseconds_t delta = ARDOUR::get_microseconds () - pressed_at;
if (delta < 500000) {
long_press = 0;
} else if (delta < 1000000) {
long_press = 1;
} else {
long_press = 2;
}
pressed_at = 0;
}
}
}
void
FaderPort::Button::set_action (string const& name, bool when_pressed, FaderPort::ButtonState bs)
{
ToDo todo;
type = NamedAction;
todo.type = NamedAction;
if (when_pressed) {
todo.action_name = name;
on_press[bs] = todo;
if (name.empty()) {
on_press.erase (bs);
} else {
todo.action_name = name;
on_press[bs] = todo;
}
} else {
todo.action_name = name;
on_release[bs] = todo;
if (name.empty()) {
on_release.erase (bs);
} else {
todo.action_name = name;
on_release[bs] = todo;
}
}
}
void
FaderPort::ButtonInfo::set_action (boost::function<void()> f, bool when_pressed, FaderPort::ButtonState bs)
FaderPort::Button::set_action (boost::function<void()> f, bool when_pressed, FaderPort::ButtonState bs)
{
ToDo todo;
type = InternalFunction;
todo.type = InternalFunction;
if (when_pressed) {
todo.function = f;
@ -759,7 +809,7 @@ FaderPort::ButtonInfo::set_action (boost::function<void()> f, bool when_pressed,
}
void
FaderPort::ButtonInfo::set_led_state (boost::shared_ptr<MIDI::Port> port, int onoff, bool force)
FaderPort::Button::set_led_state (boost::shared_ptr<MIDI::Port> port, int onoff, bool force)
{
if (!force && (led_on == (bool) onoff)) {
/* nothing to do */
@ -779,6 +829,87 @@ FaderPort::ButtonInfo::set_led_state (boost::shared_ptr<MIDI::Port> port, int on
led_on = (onoff ? true : false);
}
int
FaderPort::Button::set_state (XMLNode const& node)
{
const XMLProperty* prop = node.property ("id");
if (!prop) {
return -1;
}
int xid = atoi (prop->value());
if (xid != id) {
return -1;
}
typedef pair<string,FaderPort::ButtonState> state_pair_t;
vector<state_pair_t> state_pairs;
state_pairs.push_back (make_pair (string ("plain"), ButtonState (0)));
state_pairs.push_back (make_pair (string ("shift"), ShiftDown));
state_pairs.push_back (make_pair (string ("longish"), LongishPress));
state_pairs.push_back (make_pair (string ("long"), LongPress));
on_press.clear ();
on_release.clear ();
for (vector<state_pair_t>::const_iterator sp = state_pairs.begin(); sp != state_pairs.end(); ++sp) {
string propname;
propname = sp->first + X_("-press");
if ((prop = node.property (propname)) == 0) {
continue;
}
set_action (prop->value(), true, sp->second);
propname = sp->first + X_("-release");
if ((prop = node.property (propname)) == 0) {
continue;
}
set_action (prop->value(), false, sp->second);
}
return 0;
}
XMLNode&
FaderPort::Button::get_state () const
{
XMLNode* node = new XMLNode (X_("Button"));
char buf[16];
snprintf (buf, sizeof (buf), "%d", id);
node->add_property (X_("id"), buf);
ToDoMap::const_iterator x;
ToDo null;
null.type = NamedAction;
typedef pair<string,FaderPort::ButtonState> state_pair_t;
vector<state_pair_t> state_pairs;
state_pairs.push_back (make_pair (string ("plain"), ButtonState (0)));
state_pairs.push_back (make_pair (string ("shift"), ShiftDown));
state_pairs.push_back (make_pair (string ("longish"), LongishPress));
state_pairs.push_back (make_pair (string ("long"), LongPress));
for (vector<state_pair_t>::const_iterator sp = state_pairs.begin(); sp != state_pairs.end(); ++sp) {
if ((x = on_press.find (sp->second)) != on_press.end()) {
if (x->second.type == NamedAction) {
node->add_property (string (sp->first + X_("-press")).c_str(), x->second.action_name);
}
}
if ((x = on_release.find (sp->second)) != on_release.end()) {
if (x->second.type == NamedAction) {
node->add_property (string (sp->first + X_("-release")).c_str(), x->second.action_name);
}
}
}
return *node;
}
void
FaderPort::gui_track_selection_changed (RouteNotificationListPtr routes)
{
@ -813,7 +944,7 @@ FaderPort::set_current_route (boost::shared_ptr<Route> r)
/* turn this off. It will be turned on back on in use_master() or
use_monitor() as appropriate.
*/
button_info(Output).set_led_state (_output_port, false);
get_button(Output).set_led_state (_output_port, false);
if (_current_route) {
_current_route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::drop_current_route, this), this);
@ -850,7 +981,7 @@ FaderPort::map_cut ()
if (mp) {
bool yn = mp->cut_all ();
button_info (Mute).set_led_state (_output_port, yn);
get_button (Mute).set_led_state (_output_port, yn);
if (yn) {
blinkers.push_back (Mute);
} else {
@ -864,19 +995,19 @@ FaderPort::map_cut ()
void
FaderPort::map_mute (void*)
{
button_info (Mute).set_led_state (_output_port, _current_route->muted());
get_button (Mute).set_led_state (_output_port, _current_route->muted());
}
void
FaderPort::map_solo (bool, void*, bool)
{
button_info (Solo).set_led_state (_output_port, _current_route->soloed() || _current_route->listening_via_monitor());
get_button (Solo).set_led_state (_output_port, _current_route->soloed() || _current_route->listening_via_monitor());
}
void
FaderPort::map_listen (void*, bool)
{
button_info (Solo).set_led_state (_output_port, _current_route->listening_via_monitor());
get_button (Solo).set_led_state (_output_port, _current_route->listening_via_monitor());
}
void
@ -884,9 +1015,9 @@ FaderPort::map_recenable ()
{
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_route);
if (t) {
button_info (Rec).set_led_state (_output_port, t->record_enabled());
get_button (Rec).set_led_state (_output_port, t->record_enabled());
} else {
button_info (Rec).set_led_state (_output_port, false);
get_button (Rec).set_led_state (_output_port, false);
}
}
@ -944,9 +1075,9 @@ void
FaderPort::map_route_state ()
{
if (!_current_route) {
button_info (Mute).set_led_state (_output_port, false);
button_info (Solo).set_led_state (_output_port, false);
button_info (Rec).set_led_state (_output_port, false);
get_button (Mute).set_led_state (_output_port, false);
get_button (Solo).set_led_state (_output_port, false);
get_button (Rec).set_led_state (_output_port, false);
blinkers.remove (Mute);
blinkers.remove (Solo);
} else {
@ -974,5 +1105,5 @@ FaderPort::input_port()
void
FaderPort::set_action (ButtonID id, std::string const& action_name, bool on_press, ButtonState bs)
{
button_info(id).set_action (action_name, on_press, bs);
get_button(id).set_action (action_name, on_press, bs);
}

View File

@ -151,6 +151,8 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
RewindDown = 0x2,
StopDown = 0x4,
UserDown = 0x8,
LongishPress = 0x10,
LongPress = 0x20
};
void set_action (ButtonID, std::string const& action_name, bool on_press, FaderPort::ButtonState = ButtonState (0));
@ -190,15 +192,15 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
int last_encoder_delta, last_last_encoder_delta;
void sysex_handler (MIDI::Parser &p, MIDI::byte *, size_t);
void switch_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb);
void button_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb);
void encoder_handler (MIDI::Parser &, MIDI::pitchbend_t pb);
void fader_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb);
ButtonState button_state;
friend class ButtonInfo;
friend class Button;
class ButtonInfo {
class Button {
public:
enum ActionType {
@ -206,14 +208,15 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
InternalFunction,
};
ButtonInfo (FaderPort& f, std::string const& str, ButtonID i, int o)
Button (FaderPort& f, std::string const& str, ButtonID i, int o)
: fp (f)
, name (str)
, id (i)
, out (o)
, type (NamedAction)
, led_on (false)
, flash (false)
, pressed_at (0)
, long_press (0)
{}
void set_action (std::string const& action_name, bool on_press, FaderPort::ButtonState = ButtonState (0));
@ -222,20 +225,26 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
void invoke (ButtonState bs, bool press);
bool uses_flash () const { return flash; }
void set_flash (bool yn) { flash = yn; }
void do_timing (bool press);
XMLNode& get_state () const;
int set_state (XMLNode const&);
private:
FaderPort& fp;
std::string name;
ButtonID id;
int out;
ActionType type;
bool led_on;
bool flash;
ARDOUR::microseconds_t pressed_at;
int long_press;
/* could be a union if boost::function didn't require a
* constructor
*/
struct ToDo {
ActionType type;
/* could be a union if boost::function didn't require a
* constructor
*/
std::string action_name;
boost::function<void()> function;
};
@ -245,10 +254,10 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
ToDoMap on_release;
};
typedef std::map<ButtonID,ButtonInfo> ButtonMap;
typedef std::map<ButtonID,Button> ButtonMap;
ButtonMap buttons;
ButtonInfo& button_info (ButtonID) const;
Button& get_button (ButtonID) const;
void all_lights_out ();
void close ();

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2009-2012 Paul Davis
Copyright (C) 2015 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
@ -17,24 +17,9 @@
*/
#include <iostream>
#include <list>
#include <vector>
#include <string>
#include <gtkmm/adjustment.h>
#include <gtkmm/alignment.h>
#include <gtkmm/box.h>
#include <gtkmm/combobox.h>
#include <gtkmm/liststore.h>
#include <gtkmm/label.h>
#include <gtkmm/spinbutton.h>
#include <gtkmm/table.h>
#include <gtkmm/treestore.h>
namespace Gtk {
class CellRendererCombo;
}
#include <gtkmm/liststore.h>
#include "pbd/unwind.h"
#include "pbd/strsplit.h"
@ -47,68 +32,10 @@ namespace Gtk {
#include "ardour/audioengine.h"
#include "faderport.h"
#include "gui.h"
#include "i18n.h"
namespace ArdourSurface {
class FPGUI : public Gtk::VBox
{
public:
FPGUI (FaderPort&);
~FPGUI ();
private:
FaderPort& fp;
Gtk::Table table;
Gtk::ComboBox input_combo;
Gtk::ComboBox output_combo;
Gtk::ComboBox mix_combo;
Gtk::ComboBox proj_combo;
Gtk::ComboBox trns_combo;
void update_port_combos (std::vector<std::string> const&, std::vector<std::string> const&);
PBD::ScopedConnection connection_change_connection;
void connection_handler ();
struct MidiPortColumns : public Gtk::TreeModel::ColumnRecord {
MidiPortColumns() {
add (short_name);
add (full_name);
}
Gtk::TreeModelColumn<std::string> short_name;
Gtk::TreeModelColumn<std::string> full_name;
};
MidiPortColumns midi_port_columns;
bool ignore_active_change;
Glib::RefPtr<Gtk::ListStore> build_midi_port_list (std::vector<std::string> const & ports, bool for_input);
void active_port_changed (Gtk::ComboBox*,bool for_input);
struct ActionColumns : public Gtk::TreeModel::ColumnRecord {
ActionColumns() {
add (name);
add (path);
}
Gtk::TreeModelColumn<std::string> name;
Gtk::TreeModelColumn<std::string> path;
};
ActionColumns action_columns;
Glib::RefPtr<Gtk::TreeStore> available_action_model;
std::map<std::string,std::string> action_map; // map from action names to paths
void build_mix_action_combo (Gtk::ComboBox&);
void build_proj_action_combo (Gtk::ComboBox&);
void build_trns_action_combo (Gtk::ComboBox&);
void build_available_action_menu ();
void action_changed (Gtk::ComboBox*, FaderPort::ButtonID);
};
}
using namespace PBD;
using namespace ARDOUR;
using namespace ArdourSurface;
@ -136,7 +63,7 @@ FaderPort::tear_down_gui ()
delete w;
}
}
delete (FPGUI*) gui;
delete static_cast<FPGUI*> (gui);
gui = 0;
}
@ -151,6 +78,7 @@ FaderPort::build_gui ()
FPGUI::FPGUI (FaderPort& p)
: fp (p)
, table (2, 5)
, action_table (4, 5)
, ignore_active_change (false)
{
set_border_width (12);
@ -164,65 +92,138 @@ FPGUI::FPGUI (FaderPort& p)
Gtk::Alignment* align;
int row = 0;
vector<string> midi_inputs;
vector<string> midi_outputs;
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsPhysical), midi_inputs);
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsPhysical), midi_outputs);
update_port_combos (midi_inputs, midi_outputs);
input_combo.pack_start (midi_port_columns.short_name);
output_combo.pack_start (midi_port_columns.short_name);
input_combo.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FPGUI::active_port_changed), &input_combo, true));
output_combo.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FPGUI::active_port_changed), &output_combo, false));
l = manage (new Gtk::Label (_("Sends MIDI via:")));
l = manage (new Gtk::Label (_("Sends MIDI to:")));
l->set_alignment (1.0, 0.5);
table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
table.attach (input_combo, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
row++;
l = manage (new Gtk::Label (_("Receives MIDI via:")));
l = manage (new Gtk::Label (_("Receives MIDI from:")));
l->set_alignment (1.0, 0.5);
table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
table.attach (output_combo, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
row++;
build_mix_action_combo (mix_combo);
build_proj_action_combo (proj_combo);
build_trns_action_combo (trns_combo);
build_mix_action_combo (mix_combo[0], FaderPort::ButtonState(0));
build_mix_action_combo (mix_combo[1], FaderPort::ShiftDown);
build_mix_action_combo (mix_combo[2], FaderPort::LongishPress);
build_mix_action_combo (mix_combo[3], FaderPort::LongPress);
l = manage (new Gtk::Label (_("Mix Button")));
build_proj_action_combo (proj_combo[0], FaderPort::ButtonState(0));
build_proj_action_combo (proj_combo[1], FaderPort::ShiftDown);
build_proj_action_combo (proj_combo[2], FaderPort::LongishPress);
build_proj_action_combo (proj_combo[3], FaderPort::LongPress);
build_trns_action_combo (trns_combo[0], FaderPort::ButtonState(0));
build_trns_action_combo (trns_combo[1], FaderPort::ShiftDown);
build_trns_action_combo (trns_combo[2], FaderPort::LongishPress);
build_trns_action_combo (trns_combo[3], FaderPort::LongPress);
action_table.set_row_spacings (4);
action_table.set_col_spacings (6);
action_table.set_border_width (12);
action_table.set_homogeneous (false);
int action_row = 0;
l = manage (new Gtk::Label (_("Button")));
l->set_alignment (1.0, 0.5);
table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
action_table.attach (*l, 0, 1, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
l = manage (new Gtk::Label (_("Press")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 1, 2, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
l = manage (new Gtk::Label (_("Shift")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 2, 3, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
l = manage (new Gtk::Label (_("Medium")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 3, 4, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
l = manage (new Gtk::Label (_("Long")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 4, 5, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
action_row++;
l = manage (new Gtk::Label (_("Mix")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 0, 1, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (mix_combo);
table.attach (*align, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
row++;
l = manage (new Gtk::Label (_("Proj Button")));
l->set_alignment (1.0, 0.5);
table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align->add (mix_combo[0]);
action_table.attach (*align, 1, 2, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (proj_combo);
table.attach (*align, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
row++;
l = manage (new Gtk::Label (_("Trns Button")));
l->set_alignment (1.0, 0.5);
table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align->add (mix_combo[1]);
action_table.attach (*align, 2, 3, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (trns_combo);
table.attach (*align, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align->add (mix_combo[2]);
action_table.attach (*align, 3, 4, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (mix_combo[3]);
action_table.attach (*align, 4, 5, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
action_row++;
l = manage (new Gtk::Label (_("Proj")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 0, 1, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (proj_combo[0]);
action_table.attach (*align, 1, 2, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (proj_combo[1]);
action_table.attach (*align, 2, 3, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (proj_combo[2]);
action_table.attach (*align, 3, 4, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (proj_combo[3]);
action_table.attach (*align, 4, 5, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
action_row++;
l = manage (new Gtk::Label (_("Trns")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 0, 1, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (trns_combo[0]);
action_table.attach (*align, 1, 2, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (trns_combo[1]);
action_table.attach (*align, 2, 3, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (trns_combo[2]);
action_table.attach (*align, 3, 4, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (trns_combo[3]);
action_table.attach (*align, 4, 5, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
action_row++;
table.attach (action_table, 0, 5, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
row++;
pack_start (table, false, false);
/* update the port connection combos */
update_port_combos ();
/* catch future changes to connection state */
fp.ConnectionChange.connect (connection_change_connection, invalidator (*this), boost::bind (&FPGUI::connection_handler, this), gui_context());
}
@ -240,18 +241,18 @@ FPGUI::connection_handler ()
PBD::Unwinder<bool> ici (ignore_active_change, true);
update_port_combos ();
}
void
FPGUI::update_port_combos ()
{
vector<string> midi_inputs;
vector<string> midi_outputs;
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsTerminal), midi_inputs);
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsTerminal), midi_outputs);
update_port_combos (midi_inputs, midi_outputs);
}
void
FPGUI::update_port_combos (vector<string> const& midi_inputs, vector<string> const& midi_outputs)
{
Glib::RefPtr<Gtk::ListStore> input = build_midi_port_list (midi_inputs, true);
Glib::RefPtr<Gtk::ListStore> output = build_midi_port_list (midi_outputs, false);
bool input_found = false;
@ -411,7 +412,16 @@ FPGUI::build_available_action_menu ()
}
void
FPGUI::build_mix_action_combo (Gtk::ComboBox& cb)
FPGUI::action_changed (Gtk::ComboBox* cb, FaderPort::ButtonID id)
{
TreeModel::const_iterator row = cb->get_active ();
string action_path = (*row)[action_columns.path];
fp.set_action (id, action_path, true);
}
void
FPGUI::build_action_combo (Gtk::ComboBox& cb, vector<pair<string,string> > const & actions, FaderPort::ButtonID id, FaderPort::ButtonState bs)
{
Glib::RefPtr<Gtk::ListStore> model (Gtk::ListStore::create (action_columns));
TreeIter rowp;
@ -419,29 +429,51 @@ FPGUI::build_mix_action_combo (Gtk::ComboBox& cb)
rowp = model->append();
row = *(rowp);
row[action_columns.name] = _("Toggle Editor & Mixer Windows");
row[action_columns.path] = X_("Common/toggle-editor-mixer");
row[action_columns.name] = _("Disabled");
row[action_columns.path] = string();
rowp = model->append();
row = *(rowp);
row[action_columns.name] = _("Show/Hide Editor mixer strip");
row[action_columns.path] = X_("Editor/show-editor-mixer");
for (vector<pair<string,string> >::const_iterator i = actions.begin(); i != actions.end(); ++i) {
rowp = model->append();
row = *(rowp);
row[action_columns.name] = i->first;
row[action_columns.path] = i->second;
}
cb.set_model (model);
cb.pack_start (action_columns.name);
cb.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FPGUI::action_changed), &cb, FaderPort::Mix));
cb.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FPGUI::action_changed), &cb, id));
}
void
FPGUI::build_proj_action_combo (Gtk::ComboBox& cb)
FPGUI::build_mix_action_combo (Gtk::ComboBox& cb, FaderPort::ButtonState bs)
{
vector<pair<string,string> > actions;
actions.push_back (make_pair (string (_("Toggle Editor & Mixer Windows")), string (X_("Common/toggle-editor-mixer"))));
actions.push_back (make_pair (string (_("Show/Hide Editor mixer strip")), string (X_("Editor/show-editor-mixer"))));
build_action_combo (cb, actions, FaderPort::Mix, bs);
}
void
FPGUI::build_proj_action_combo (Gtk::ComboBox& cb, FaderPort::ButtonState bs)
{
vector<pair<string,string> > actions;
actions.push_back (make_pair (string("Toggle Meterbridge"), string(X_("Common/toggle-meterbridge"))));
build_action_combo (cb, actions, FaderPort::Proj, bs);
}
void
FPGUI::build_trns_action_combo (Gtk::ComboBox& cb)
FPGUI::build_trns_action_combo (Gtk::ComboBox& cb, FaderPort::ButtonState bs)
{
vector<pair<string,string> > actions;
actions.push_back (make_pair (string("Toggle Locations"), string(X_("Window/toggle-locations"))));
build_action_combo (cb, actions, FaderPort::Trns, bs);
}
Glib::RefPtr<Gtk::ListStore>
@ -499,14 +531,3 @@ FPGUI::active_port_changed (Gtk::ComboBox* combo, bool for_input)
}
}
}
void
FPGUI::action_changed (Gtk::ComboBox* cb, FaderPort::ButtonID id)
{
TreeModel::const_iterator row = cb->get_active ();
string action_path = (*row)[action_columns.path];
cerr << "Change " << id << " to " << action_path << endl;
fp.set_action (id, action_path, true);
}

View File

@ -0,0 +1,106 @@
/*
Copyright (C) 2015 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_faderport_gui_h__
#define __ardour_faderport_gui_h__
#include <vector>
#include <string>
#include <gtkmm/box.h>
#include <gtkmm/combobox.h>
#include <gtkmm/table.h>
#include <gtkmm/treestore.h>
namespace Gtk {
class CellRendererCombo;
class ListStore;
}
#include "faderport.h"
namespace ArdourSurface {
class FPGUI : public Gtk::VBox
{
public:
FPGUI (FaderPort&);
~FPGUI ();
private:
FaderPort& fp;
Gtk::Table table;
Gtk::Table action_table;
Gtk::ComboBox input_combo;
Gtk::ComboBox output_combo;
/* the mix, proj, trns and user buttons have no obvious semantics for
* ardour, mixbus etc., so we allow the user to define their
* functionality from a small, curated set of options.
*/
Gtk::ComboBox mix_combo[4];
Gtk::ComboBox proj_combo[4];
Gtk::ComboBox trns_combo[4];
Gtk::ComboBox user_combo[4];
void update_port_combos ();
PBD::ScopedConnection connection_change_connection;
void connection_handler ();
struct MidiPortColumns : public Gtk::TreeModel::ColumnRecord {
MidiPortColumns() {
add (short_name);
add (full_name);
}
Gtk::TreeModelColumn<std::string> short_name;
Gtk::TreeModelColumn<std::string> full_name;
};
MidiPortColumns midi_port_columns;
bool ignore_active_change;
Glib::RefPtr<Gtk::ListStore> build_midi_port_list (std::vector<std::string> const & ports, bool for_input);
void active_port_changed (Gtk::ComboBox*,bool for_input);
struct ActionColumns : public Gtk::TreeModel::ColumnRecord {
ActionColumns() {
add (name);
add (path);
}
Gtk::TreeModelColumn<std::string> name;
Gtk::TreeModelColumn<std::string> path;
};
ActionColumns action_columns;
Glib::RefPtr<Gtk::TreeStore> available_action_model;
std::map<std::string,std::string> action_map; // map from action names to paths
void build_action_combo (Gtk::ComboBox& cb, std::vector<std::pair<std::string,std::string> > const & actions, FaderPort::ButtonID, FaderPort::ButtonState);
void build_mix_action_combo (Gtk::ComboBox&, FaderPort::ButtonState);
void build_proj_action_combo (Gtk::ComboBox&, FaderPort::ButtonState);
void build_trns_action_combo (Gtk::ComboBox&, FaderPort::ButtonState);
void build_available_action_menu ();
void action_changed (Gtk::ComboBox*, FaderPort::ButtonID);
};
}
#endif /* __ardour_faderport_gui_h__ */

View File

@ -171,14 +171,14 @@ FaderPort::use_master ()
if (_current_route == r) {
r = pre_master_route.lock();
set_current_route (r);
button_info(Output).set_led_state (_output_port, false);
get_button(Output).set_led_state (_output_port, false);
blinkers.remove (Output);
} else {
if (_current_route != session->master_out() && _current_route != session->monitor_out()) {
pre_master_route = boost::weak_ptr<Route> (_current_route);
}
set_current_route (r);
button_info(Output).set_led_state (_output_port, true);
get_button(Output).set_led_state (_output_port, true);
blinkers.remove (Output);
}
}
@ -193,14 +193,14 @@ FaderPort::use_monitor ()
if (_current_route == r) {
r = pre_monitor_route.lock();
set_current_route (r);
button_info(Output).set_led_state (_output_port, false);
get_button(Output).set_led_state (_output_port, false);
blinkers.remove (Output);
} else {
if (_current_route != session->master_out() && _current_route != session->monitor_out()) {
pre_monitor_route = boost::weak_ptr<Route> (_current_route);
}
set_current_route (r);
button_info(Output).set_led_state (_output_port, true);
get_button(Output).set_led_state (_output_port, true);
blinkers.push_back (Output);
}
} else {