diff options
author | Robin Gareus <robin@gareus.org> | 2017-04-05 11:04:16 +0200 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2017-04-13 21:21:59 +0200 |
commit | d43a23fe28c6f54ed8ca6cde6497661c6cb73ce0 (patch) | |
tree | d89166f438d4a3d42034d6b106506cb892d2f068 /libs/surfaces/faderport8/actions.cc | |
parent | d64ca9be08331756e936018ea4d06404faa2ca90 (diff) |
Faderport8 control surface support
Diffstat (limited to 'libs/surfaces/faderport8/actions.cc')
-rw-r--r-- | libs/surfaces/faderport8/actions.cc | 470 |
1 files changed, 470 insertions, 0 deletions
diff --git a/libs/surfaces/faderport8/actions.cc b/libs/surfaces/faderport8/actions.cc new file mode 100644 index 0000000000..949d19a958 --- /dev/null +++ b/libs/surfaces/faderport8/actions.cc @@ -0,0 +1,470 @@ +/* Faderport 8 Control Surface + * This is the button "Controller" of the MVC surface inteface, + * see callbacks.cc for the "View". + * + * Copyright (C) 2017 Robin Gareus <robin@gareus.org> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "ardour/dB.h" +#include "ardour/session.h" +#include "ardour/session_configuration.h" +#include "ardour/types.h" + +#include "gtkmm2ext/actions.h" + +#include "faderport8.h" + +#include "pbd/i18n.h" + +using namespace ARDOUR; +using namespace ArdourSurface; +using namespace std; +using namespace ArdourSurface::FP8Types; + +#define BindMethod(ID, CB) \ + _ctrls.button (FP8Controls::ID).released.connect_same_thread (button_connections, boost::bind (&FaderPort8:: CB, this)); + +#define BindFunction(ID, ACT, CB, ...) \ + _ctrls.button (FP8Controls::ID). ACT .connect_same_thread (button_connections, boost::bind (&FaderPort8:: CB, this, __VA_ARGS__)); + +#define BindAction(ID, GRP, ITEM) \ + _ctrls.button (FP8Controls::ID).released.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_action, this, GRP, ITEM)); + +#define BindUserAction(ID) \ + _ctrls.button (ID).pressed.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_user, this, true, ID)); \ +_ctrls.button (ID).released.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_user, this, false, ID)); + +void +FaderPort8::setup_actions () +{ + BindMethod (BtnPlay, button_play); + BindMethod (BtnStop, button_stop); + BindMethod (BtnLoop, button_loop); + BindMethod (BtnRecord, button_record); + BindMethod (BtnClick, button_metronom); + BindAction (BtnRedo, "Editor", "redo"); + + BindAction (BtnSave, "Common", "Save"); + BindAction (BtnUndo, "Editor", "undo"); + BindAction (BtnRedo, "Editor", "redo"); + + BindAction (BtnSoloClear, "Main", "cancel-solo"); + BindMethod (BtnMuteClear, button_mute_clear); + + BindMethod (FP8Controls::BtnArmAll, button_arm_all); + + BindFunction (BtnRewind, pressed, button_varispeed, false); + BindFunction (BtnFastForward, pressed, button_varispeed, true); + + BindFunction (BtnPrev, released, button_prev_next, false); + BindFunction (BtnNext, released, button_prev_next, true); + + BindFunction (BtnArm, pressed, button_arm, true); + BindFunction (BtnArm, released, button_arm, false); + + BindFunction (BtnAOff, released, button_automation, ARDOUR::Off); + BindFunction (BtnATouch, released, button_automation, ARDOUR::Touch); + BindFunction (BtnARead, released, button_automation, ARDOUR::Play); + BindFunction (BtnAWrite, released, button_automation, ARDOUR::Write); + + _ctrls.button (FP8Controls::BtnEncoder).pressed.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_encoder, this)); + _ctrls.button (FP8Controls::BtnParam).pressed.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_parameter, this)); + + + BindAction (BtnBypass, "Mixer", "ab-plugins"); + BindAction (BtnBypassAll, "Mixer", "ab-plugins"); // XXX + + BindAction (BtnMacro, "Mixer", "show-editor"); + BindAction (BtnLink, "Window", "show-mixer"); + + BindAction (BtnOpen, "Common", "addExistingAudioFiles"); + BindAction (BtnLock, "Editor", "lock"); + + // user-specific + for (FP8Controls::UserButtonMap::const_iterator i = _ctrls.user_buttons ().begin (); + i != _ctrls.user_buttons ().end (); ++i) { + BindUserAction ((*i).first); + } +} + +void +FaderPort8::button_play () +{ + if (session->transport_rolling ()) { + if (session->transport_speed () != 1.0) { + session->request_transport_speed (1.0); + } else { + transport_stop (); + } + } else { + transport_play (); + } +} + +void +FaderPort8::button_stop () +{ + transport_stop (); +} + +void +FaderPort8::button_record () +{ + set_record_enable (!get_record_enabled ()); +} + +void +FaderPort8::button_loop () +{ + loop_toggle (); +} + +void +FaderPort8::button_metronom () +{ + Config->set_clicking (!Config->get_clicking ()); +} + +void +FaderPort8::button_automation (ARDOUR::AutoState as) +{ + FaderMode fadermode = _ctrls.fader_mode (); + switch (fadermode) { + case ModePlugins: +#if 0 // Plugin Control Automation Mode + for ( std::list <ProcessorCtrl>::iterator i = _proc_params.begin(); i != _proc_params.end(); ++i) { + ((*i).ac)->set_automation_state (as); + } +#endif + return; + case ModeSend: + if (first_selected_stripable()) { +#if 0 // Send Level Automation + boost::shared_ptr<Stripable> s = first_selected_stripable(); + boost::shared_ptr<AutomationControl> send; + uint32_t i = 0; + while (0 != (send = s->send_level_controllable (i))) { + send->set_automation_state (as); + ++i; + } +#endif + } + return; + default: + break; + } + + // apply to all selected tracks + StripableList all; + session->get_stripables (all); + for (StripableList::const_iterator i = all.begin(); i != all.end(); ++i) { + if ((*i)->is_master() || (*i)->is_monitor()) { + continue; + } + if (!(*i)->is_selected()) { + continue; + } + boost::shared_ptr<AutomationControl> ac; + switch (fadermode) { + case ModeTrack: + ac = (*i)->gain_control (); + break; + case ModePan: + ac = (*i)->pan_azimuth_control (); + break; + default: + break; + } + if (ac) { + ac->set_automation_state (as); + } + } +} + +void +FaderPort8::button_varispeed (bool ffw) +{ + /* pressing both rew + ffwd -> return to zero */ + FP8ButtonInterface& b_rew = _ctrls.button (FP8Controls::BtnRewind); + FP8ButtonInterface& b_ffw = _ctrls.button (FP8Controls::BtnFastForward); + if (b_rew.is_pressed () && b_ffw.is_pressed ()){ + // stop key-repeat + dynamic_cast<FP8RepeatButton*>(&b_ffw)->stop_repeat(); + dynamic_cast<FP8RepeatButton*>(&b_rew)->stop_repeat(); + AccessAction ("Transport", "GotoStart"); + return; + } + + // switch play direction, if needed + if (ffw) { + if (session->transport_speed () <= 0) { + session->request_transport_speed (1.0); + return ; + } + } else { + if (session->transport_speed () >= 0) { + session->request_transport_speed (-1.0); + return ; + } + } + // incremetally increase speed. double speed every 10 clicks + // (keypress auto-repeat is 100ms) + float maxspeed = Config->get_shuttle_max_speed(); + float speed = exp2f(0.1f) * session->transport_speed (); + speed = std::max (-maxspeed, std::min (maxspeed, speed)); + session->request_transport_speed (speed, false); +} + +void +FaderPort8::button_mute_clear () +{ + StripableList all; + session->get_stripables (all); + boost::shared_ptr<ControlList> cl (new ControlList); + for (StripableList::const_iterator i = all.begin(); i != all.end(); ++i) { + if ((*i)->is_master() || (*i)->is_monitor()) { + continue; + } + boost::shared_ptr<AutomationControl> ac = (*i)->mute_control(); + if (ac) { + cl->push_back (ac); + } + } + session->set_controls (cl, 0.0, PBD::Controllable::UseGroup); +} + +void +FaderPort8::button_arm (bool press) +{ + FaderMode fadermode = _ctrls.fader_mode (); + if (fadermode == ModeTrack || fadermode == ModePan) { + _ctrls.button (FP8Controls::BtnArm).set_active (press); + ARMButtonChange (press); + } +} + +void +FaderPort8::button_arm_all () +{ + BasicUI::all_tracks_rec_in (); +} + +void +FaderPort8::button_action (const std::string& group, const std::string& item) +{ + AccessAction (group, item); +} + +void +FaderPort8::button_prev_next (bool next) +{ + switch (_ctrls.nav_mode()) { + case NavMaster: + case NavChannel: + case NavScroll: + bank (!next, false); + break; + case NavBank: + bank (!next, true); + break; + case NavZoom: + if (next) { + StepTracksDown (); + } else { + StepTracksUp (); + } + break; + case NavSection: + // TODO nudge + break; + case NavMarker: + if (next) { + next_marker (); + } else { + prev_marker (); + } + break; + } +} + +/* handle navigation encoder press */ +void +FaderPort8::button_encoder () +{ + switch (_ctrls.nav_mode()) { + case NavZoom: + ZoomToSession (); // XXX undo zoom + break; + case NavScroll: + ZoomToSession (); + break; + case NavChannel: + case NavBank: + move_selected_into_view (); + break; + case NavMaster: + { + /* master || monitor level -- reset to 0dB */ + boost::shared_ptr<AutomationControl> ac; + if (session->monitor_active() && !_ctrls.button (FP8Controls::BtnMaster).is_pressed ()) { + ac = session->monitor_out()->gain_control (); + } else if (session->master_out()) { + ac = session->master_out()->gain_control (); + } + if (ac) { + ac->set_value (ac->normal(), PBD::Controllable::NoGroup); + } + } + break; + case NavSection: + break; + case NavMarker: + { + string markername; + /* Don't add another mark if one exists within 1/100th of a second of + * the current position and we're not rolling. + */ + framepos_t where = session->audible_frame(); + if (session->transport_stopped() && session->locations()->mark_at (where, session->frame_rate() / 100.0)) { + return; + } + + session->locations()->next_available_name (markername,"mark"); + add_marker (markername); + } + break; + } +} + +/* handle navigation encoder turn */ +void +FaderPort8::encoder_navigate (bool neg, int steps) +{ + /* special-case metronome level */ + if (_ctrls.button (FP8Controls::BtnClick).is_pressed ()) { + // compare to ARDOUR_UI::click_button_scroll() + gain_t gain = Config->get_click_gain(); + float gain_db = accurate_coefficient_to_dB (gain); + gain_db += (neg ? -1.f : 1.f) * steps; + gain_db = std::max (-60.f, gain_db); + gain = dB_to_coefficient (gain_db); + gain = std::min (gain, Config->get_max_gain()); + Config->set_click_gain (gain); + _ctrls.button (FP8Controls::BtnClick).ignore_release(); + return; + } + + switch (_ctrls.nav_mode()) { + case NavChannel: + if (neg) { + StepTracksUp (); + } else { + StepTracksDown (); + } + break; + case NavZoom: + if (neg) { + ZoomOut (); + } else { + ZoomIn (); + } + break; + case NavMarker: + case NavScroll: + ScrollTimeline ((neg ? -1.f : 1.f) * steps / (shift_mod() ? 1024.f : 256.f)); + break; + case NavBank: + bank (neg, false); + break; + case NavMaster: + { + /* master || monitor level */ + boost::shared_ptr<AutomationControl> ac; + if (session->monitor_active() && !_ctrls.button (FP8Controls::BtnMaster).is_pressed ()) { + ac = session->monitor_out()->gain_control (); + } else if (session->master_out()) { + ac = session->master_out()->gain_control (); + } + if (ac) { + double v = ac->internal_to_interface (ac->get_value()); + v = std::max (0.0, std::min (1.0, v + steps * (neg ? -.01 : .01))); + ac->set_value (ac->interface_to_internal(v), PBD::Controllable::NoGroup); + } + } + break; + case NavSection: + // nudge event + break; + } +} + +/* handle pan/param encoder press */ +void +FaderPort8::button_parameter () +{ + switch (_ctrls.fader_mode()) { + case ModeTrack: + case ModePan: + // pan-width see FaderPort8::encoder_parameter() + break; + case ModePlugins: + break; + case ModeSend: + break; + } +} + +/* handle pan/param encoder turn */ +void +FaderPort8::encoder_parameter (bool neg, int steps) +{ + switch (_ctrls.fader_mode()) { + case ModeTrack: + case ModePan: + { + boost::shared_ptr<Stripable> s = first_selected_stripable(); + if (s) { + boost::shared_ptr<AutomationControl> ac; + if (_ctrls.button (FP8Controls::BtnParam).is_pressed ()) { + ac = s->pan_width_control (); + } else { + ac = s->pan_azimuth_control (); + } + if (ac) { + double v = ac->internal_to_interface (ac->get_value()); + v = std::max (0.0, std::min (1.0, v + steps * (neg ? -.01 : .01))); + ac->set_value (ac->interface_to_internal(v), PBD::Controllable::UseGroup); + } + } + } + break; + case ModePlugins: + case ModeSend: + while (steps > 0) { + bank_param (neg, false); + --steps; + } + break; + } +} + +/* handle user-specific actions */ +void +FaderPort8::button_user (bool press, FP8Controls::ButtonId btn) +{ + _user_action_map[btn].call (*this, press); +} |