2 * Copyright (C) 2017-2018 Robin Gareus <robin@gareus.org>
3 * Copyright (C) 2018 Ben Loftis <ben@harrisonconsoles.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 /* Faderport 8 Control Surface
21 * This is the button "Controller" of the MVC surface inteface,
22 * see callbacks.cc for the "View".
25 #include "ardour/dB.h"
26 #include "ardour/plugin_insert.h"
27 #include "ardour/session.h"
28 #include "ardour/session_configuration.h"
29 #include "ardour/track.h"
30 #include "ardour/types.h"
32 #include "gtkmm2ext/actions.h"
34 #include "faderport8.h"
39 using namespace ARDOUR;
40 using namespace ArdourSurface::FP_NAMESPACE;
41 using namespace ArdourSurface::FP_NAMESPACE::FP8Types;
43 #define BindMethod(ID, CB) \
44 _ctrls.button (FP8Controls::ID).released.connect_same_thread (button_connections, boost::bind (&FaderPort8:: CB, this));
46 #define BindMethod2(ID, ACT, CB) \
47 _ctrls.button (FP8Controls::ID). ACT .connect_same_thread (button_connections, boost::bind (&FaderPort8:: CB, this));
49 #define BindFunction(ID, ACT, CB, ...) \
50 _ctrls.button (FP8Controls::ID). ACT .connect_same_thread (button_connections, boost::bind (&FaderPort8:: CB, this, __VA_ARGS__));
52 #define BindAction(ID, GRP, ITEM) \
53 _ctrls.button (FP8Controls::ID).released.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_action, this, GRP, ITEM));
55 #define BindUserAction(ID) \
56 _ctrls.button (ID).pressed.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_user, this, true, ID)); \
57 _ctrls.button (ID).released.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_user, this, false, ID));
60 /* Bind button signals (press, release) to callback methods
61 * (called once after constructing buttons).
62 * Bound actions are handled the the ctrl-surface thread.
65 FaderPort8::setup_actions ()
67 BindMethod2 (BtnPlay, pressed, button_play);
68 BindMethod2 (BtnStop, pressed, button_stop);
69 BindMethod2 (BtnLoop, pressed, button_loop);
70 BindMethod2 (BtnRecord, pressed, button_record);
71 BindMethod2 (BtnClick, pressed, button_metronom);
72 BindAction (BtnRedo, "Editor", "redo");
74 BindAction (BtnSave, "Common", "Save");
75 BindAction (BtnUndo, "Editor", "undo");
76 BindAction (BtnRedo, "Editor", "redo");
78 #ifdef FP8_MUTESOLO_UNDO
79 BindMethod (BtnSoloClear, button_solo_clear);
81 BindAction (BtnSoloClear, "Main", "cancel-solo");
83 BindMethod (BtnMuteClear, button_mute_clear);
85 BindMethod (FP8Controls::BtnArmAll, button_arm_all);
87 BindFunction (BtnRewind, pressed, button_varispeed, false);
88 BindFunction (BtnFastForward, pressed, button_varispeed, true);
90 BindFunction (BtnPrev, released, button_prev_next, false);
91 BindFunction (BtnNext, released, button_prev_next, true);
93 BindFunction (BtnArm, pressed, button_arm, true);
94 BindFunction (BtnArm, released, button_arm, false);
96 BindFunction (BtnAOff, released, button_automation, ARDOUR::Off);
97 BindFunction (BtnATouch, released, button_automation, ARDOUR::Touch);
98 BindFunction (BtnARead, released, button_automation, ARDOUR::Play);
99 BindFunction (BtnAWrite, released, button_automation, ARDOUR::Write);
100 BindFunction (BtnALatch, released, button_automation, ARDOUR::Latch);
102 _ctrls.button (FP8Controls::BtnEncoder).pressed.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_encoder, this));
104 _ctrls.button (FP8Controls::BtnParam).pressed.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_encoder, this));
106 _ctrls.button (FP8Controls::BtnParam).pressed.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_parameter, this));
110 BindMethod (BtnBypass, button_bypass);
111 BindAction (BtnBypassAll, "Mixer", "ab-plugins");
113 BindAction (BtnMacro, "Common", "toggle-editor-and-mixer");
114 BindMethod (BtnOpen, button_open);
116 BindMethod (BtnLink, button_link);
117 BindMethod (BtnLock, button_lock);
120 BindMethod (BtnChanLock, button_chanlock);
121 BindMethod (BtnFlip, button_flip);
125 for (FP8Controls::UserButtonMap::const_iterator i = _ctrls.user_buttons ().begin ();
126 i != _ctrls.user_buttons ().end (); ++i) {
127 BindUserAction ((*i).first);
131 /* ****************************************************************************
132 * Direct control callback Actions
136 FaderPort8::button_play ()
138 if (session->transport_rolling ()) {
139 if (session->transport_speed () != 1.0) {
140 session->request_transport_speed (1.0);
150 FaderPort8::button_stop ()
152 if (session->transport_rolling ()) {
155 AccessAction ("Transport", "GotoStart");
160 FaderPort8::button_record ()
162 set_record_enable (!get_record_enabled ());
166 FaderPort8::button_loop ()
172 FaderPort8::button_metronom ()
174 Config->set_clicking (!Config->get_clicking ());
178 FaderPort8::button_bypass ()
180 boost::shared_ptr<PluginInsert> pi = _plugin_insert.lock();
182 pi->enable (! pi->enabled ());
184 AccessAction ("Mixer", "ab-plugins");
189 FaderPort8::button_open ()
191 boost::shared_ptr<PluginInsert> pi = _plugin_insert.lock();
193 pi->ToggleUI (); /* EMIT SIGNAL */
195 AccessAction ("Common", "addExistingAudioFiles");
200 FaderPort8::button_chanlock ()
202 _chan_locked = !_chan_locked;
204 _ctrls.button (FP8Controls::BtnChannel).set_blinking (_chan_locked);
208 FaderPort8::button_flip ()
213 FaderPort8::button_lock ()
215 if (!_link_enabled) {
216 AccessAction ("Editor", "lock");
221 } else if (!_link_control.expired ()) {
227 FaderPort8::button_link ()
229 switch (_ctrls.fader_mode()) {
239 //AccessAction ("Window", "show-mixer");
245 FaderPort8::button_automation (ARDOUR::AutoState as)
247 FaderMode fadermode = _ctrls.fader_mode ();
250 #if 0 // Plugin Control Automation Mode
251 for (std::list <ProcessorCtrl>::iterator i = _proc_params.begin(); i != _proc_params.end(); ++i) {
252 ((*i).ac)->set_automation_state (as);
257 if (first_selected_stripable()) {
258 #if 0 // Send Level Automation
259 boost::shared_ptr<Stripable> s = first_selected_stripable();
260 boost::shared_ptr<AutomationControl> send;
262 while (0 != (send = s->send_level_controllable (i))) {
263 send->set_automation_state (as);
273 // TODO link/lock control automation?
275 // apply to all selected tracks
277 session->get_stripables (all);
278 for (StripableList::const_iterator i = all.begin(); i != all.end(); ++i) {
279 if ((*i)->is_master() || (*i)->is_monitor()) {
282 if (!(*i)->is_selected()) {
285 boost::shared_ptr<AutomationControl> ac;
288 ac = (*i)->gain_control ();
291 ac = (*i)->pan_azimuth_control ();
297 ac->set_automation_state (as);
303 FaderPort8::button_varispeed (bool ffw)
305 /* pressing both rew + ffwd -> return to zero */
306 FP8ButtonInterface& b_rew = _ctrls.button (FP8Controls::BtnRewind);
307 FP8ButtonInterface& b_ffw = _ctrls.button (FP8Controls::BtnFastForward);
308 if (b_rew.is_pressed () && b_ffw.is_pressed ()){
310 dynamic_cast<FP8RepeatButton*>(&b_ffw)->stop_repeat();
311 dynamic_cast<FP8RepeatButton*>(&b_rew)->stop_repeat();
312 session->request_locate (0, MustStop);
316 // switch play direction, if needed
318 if (session->transport_speed () <= 0) {
319 session->request_transport_speed (1.0);
323 if (session->transport_speed () >= 0) {
324 session->request_transport_speed (-1.0);
328 // incremetally increase speed. double speed every 10 clicks
329 // (keypress auto-repeat is 100ms)
330 float maxspeed = Config->get_shuttle_max_speed();
331 float speed = exp2f(0.1f) * session->transport_speed ();
332 speed = std::max (-maxspeed, std::min (maxspeed, speed));
333 session->request_transport_speed (speed, false);
336 #ifdef FP8_MUTESOLO_UNDO
338 FaderPort8::button_solo_clear ()
340 bool soloing = session->soloing() || session->listening();
342 soloing |= session->mixbus_soloed();
346 session->get_stripables (all);
347 for (StripableList::const_iterator i = all.begin(); i != all.end(); ++i) {
348 if ((*i)->is_master() || (*i)->is_auditioner() || (*i)->is_monitor()) {
351 boost::shared_ptr<SoloControl> sc = (*i)->solo_control();
352 if (sc && sc->self_soloed ()) {
353 _solo_state.push_back (boost::weak_ptr<AutomationControl>(sc));
356 cancel_all_solo (); // AccessAction ("Main", "cancel-solo");
359 boost::shared_ptr<ControlList> cl (new ControlList);
360 for (std::vector <boost::weak_ptr<AutomationControl> >::const_iterator i = _solo_state.begin(); i != _solo_state.end(); ++i) {
361 boost::shared_ptr<AutomationControl> ac = (*i).lock();
365 ac->start_touch (ac->session().transport_sample());
369 session->set_controls (cl, 1.0, PBD::Controllable::NoGroup);
376 FaderPort8::button_mute_clear ()
378 #ifdef FP8_MUTESOLO_UNDO
379 if (session->muted ()) {
380 _mute_state = session->cancel_all_mute ();
383 boost::shared_ptr<ControlList> cl (new ControlList);
384 for (std::vector <boost::weak_ptr<AutomationControl> >::const_iterator i = _mute_state.begin(); i != _mute_state.end(); ++i) {
385 boost::shared_ptr<AutomationControl> ac = (*i).lock();
390 ac->start_touch (ac->session().transport_sample());
393 session->set_controls (cl, 1.0, PBD::Controllable::NoGroup);
397 session->cancel_all_mute ();
402 FaderPort8::button_arm_all ()
404 BasicUI::all_tracks_rec_in ();
407 /* access generic action */
409 FaderPort8::button_action (const std::string& group, const std::string& item)
411 AccessAction (group, item);
414 /* ****************************************************************************
415 * Control Interaction (encoder)
419 FaderPort8::handle_encoder_pan (int steps)
421 boost::shared_ptr<Stripable> s = first_selected_stripable();
423 boost::shared_ptr<AutomationControl> ac;
424 if (shift_mod () || _ctrls.fader_mode() == ModePan) {
425 ac = s->pan_width_control ();
427 ac = s->pan_azimuth_control ();
430 ac->start_touch (ac->session().transport_sample());
432 ac->set_value (ac->normal(), PBD::Controllable::UseGroup);
434 double v = ac->internal_to_interface (ac->get_value());
435 v = std::max (0.0, std::min (1.0, v + steps * .01));
436 ac->set_value (ac->interface_to_internal(v), PBD::Controllable::UseGroup);
443 FaderPort8::handle_encoder_link (int steps)
445 if (_link_control.expired ()) {
448 boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (_link_control.lock ());
453 double v = ac->internal_to_interface (ac->get_value());
454 ac->start_touch (ac->session().transport_sample());
457 ac->set_value (ac->normal(), PBD::Controllable::UseGroup);
461 if (ac->desc().toggled) {
463 } else if (ac->desc().integer_step) {
464 v += steps / (1.f + ac->desc().upper - ac->desc().lower);
465 } else if (ac->desc().enumeration) {
466 ac->set_value (ac->desc().step_enum (ac->get_value(), steps < 0), PBD::Controllable::UseGroup);
469 v = std::max (0.0, std::min (1.0, v + steps * .01));
471 ac->set_value (ac->interface_to_internal(v), PBD::Controllable::UseGroup);
475 /* ****************************************************************************
476 * Mode specific and internal callbacks
479 /* handle "ARM" press -- act like shift, change "Select" button mode */
481 FaderPort8::button_arm (bool press)
484 boost::shared_ptr<Stripable> s = first_selected_stripable();
486 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(s);
488 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), PBD::Controllable::UseGroup);
492 FaderMode fadermode = _ctrls.fader_mode ();
493 if (fadermode == ModeTrack || fadermode == ModePan) {
494 _ctrls.button (FP8Controls::BtnArm).set_active (press);
495 ARMButtonChange (press); /* EMIT SIGNAL */
501 FaderPort8::button_prev_next (bool next)
503 switch (_ctrls.nav_mode()) {
506 select_prev_next (next);
519 VerticalZoomInSelected ();
521 VerticalZoomOutSelected ();
526 AccessAction ("Region", "nudge-forward");
528 AccessAction ("Region", "nudge-backward");
541 /* handle navigation encoder press */
543 FaderPort8::button_encoder ()
545 /* special-case metronome level */
546 if (_ctrls.button (FP8Controls::BtnClick).is_pressed ()) {
547 Config->set_click_gain (1.0);
548 _ctrls.button (FP8Controls::BtnClick).ignore_release();
551 switch (_ctrls.nav_mode()) {
553 ZoomToSession (); // XXX undo zoom
559 AccessAction ("Editor", "select-topmost");
562 move_selected_into_view ();
566 /* master || monitor level -- reset to 0dB */
567 boost::shared_ptr<AutomationControl> ac;
568 if (session->monitor_active() && !_ctrls.button (FP8Controls::BtnMaster).is_pressed ()) {
569 ac = session->monitor_out()->gain_control ();
570 } else if (session->master_out()) {
571 ac = session->master_out()->gain_control ();
574 ac->start_touch (ac->session().transport_sample());
575 ac->set_value (ac->normal(), PBD::Controllable::NoGroup);
587 /* Don't add another mark if one exists within 1/100th of a second of
588 * the current position and we're not rolling.
590 samplepos_t where = session->audible_sample();
591 if (session->transport_stopped_or_stopping() && session->locations()->mark_at (where, session->sample_rate() / 100.0)) {
595 session->locations()->next_available_name (markername,"mark");
596 add_marker (markername);
602 /* handle navigation encoder turn */
604 FaderPort8::encoder_navigate (bool neg, int steps)
606 /* special-case metronome level */
607 if (_ctrls.button (FP8Controls::BtnClick).is_pressed ()) {
608 // compare to ARDOUR_UI::click_button_scroll()
609 gain_t gain = Config->get_click_gain();
610 float gain_db = accurate_coefficient_to_dB (gain);
611 gain_db += (neg ? -1.f : 1.f) * steps;
612 gain_db = std::max (-60.f, gain_db);
613 gain = dB_to_coefficient (gain_db);
614 gain = std::min (gain, Config->get_max_gain());
615 Config->set_click_gain (gain);
616 _ctrls.button (FP8Controls::BtnClick).ignore_release();
620 switch (_ctrls.nav_mode()) {
623 AccessAction ("Mixer", "scroll-left");
624 AccessAction ("Editor", "step-tracks-up");
626 AccessAction ("Mixer", "scroll-right");
627 AccessAction ("Editor", "step-tracks-down");
639 ScrollTimeline ((neg ? -1.f : 1.f) * steps / (shift_mod() ? 1024.f : 256.f));
646 /* master || monitor level */
647 boost::shared_ptr<AutomationControl> ac;
648 if (session->monitor_active() && !_ctrls.button (FP8Controls::BtnMaster).is_pressed ()) {
649 ac = session->monitor_out()->gain_control ();
650 } else if (session->master_out()) {
651 ac = session->master_out()->gain_control ();
654 double v = ac->internal_to_interface (ac->get_value());
655 v = std::max (0.0, std::min (1.0, v + steps * (neg ? -.01 : .01)));
656 ac->start_touch (ac->session().transport_sample());
657 ac->set_value (ac->interface_to_internal(v), PBD::Controllable::NoGroup);
663 AccessAction ("Common", "nudge-playhead-backward");
665 AccessAction ("Common", "nudge-playhead-forward");
669 abort(); /*NOTREACHED*/
674 /* handle pan/param encoder press */
676 FaderPort8::button_parameter ()
678 switch (_ctrls.fader_mode()) {
681 if (_link_enabled || _link_locked) {
682 handle_encoder_link (0);
684 handle_encoder_pan (0);
688 toggle_preset_param_mode ();
695 /* handle pan/param encoder turn */
697 FaderPort8::encoder_parameter (bool neg, int steps)
699 switch (_ctrls.fader_mode()) {
703 if (_link_enabled || _link_locked) {
704 handle_encoder_link (neg ? -steps : steps);
706 handle_encoder_pan (neg ? -steps : steps);
713 bank_param (neg, shift_mod());
720 /* handle user-specific actions */
722 FaderPort8::button_user (bool press, FP8Controls::ButtonId btn)
724 _user_action_map[btn].call (*this, press);