/* * Copyright (C) 2017 Robin Gareus * * 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. */ #ifndef ardour_surface_faderport8_h #define ardour_surface_faderport8_h // allow to undo "mute clear", "solo clear" // eventually this should use some libardour mixer history/undo #define FP8_MUTESOLO_UNDO #include #include #include #define ABSTRACT_UI_EXPORTS #include "pbd/abstract_ui.h" #include "pbd/properties.h" #include "pbd/controllable.h" #include "ardour/types.h" #include "ardour/async_midi_port.h" #include "ardour/midi_port.h" #include "control_protocol/control_protocol.h" #include "fp8_base.h" #include "fp8_controls.h" namespace MIDI { class Parser; } namespace ARDOUR { class Bundle; class Session; class Processor; class PluginInsert; } namespace ArdourSurface { namespace FP_NAMESPACE { struct FaderPort8Request : public BaseUI::BaseRequestObject { public: FaderPort8Request () {} ~FaderPort8Request () {} }; class FaderPort8 : public FP8Base, public ARDOUR::ControlProtocol, public AbstractUI { public: FaderPort8 (ARDOUR::Session&); virtual ~FaderPort8(); static bool probe (std::string&, std::string&); int set_active (bool yn); XMLNode& get_state () const; int set_state (const XMLNode&, int version); /* configuration GUI */ bool has_editor () const { return true; } void* get_gui () const; void tear_down_gui (); PBD::Signal ConnectionChange; void set_button_action (FP8Controls::ButtonId, bool, std::string const&); std::string get_button_action (FP8Controls::ButtonId, bool); FP8Controls const& control () const { return _ctrls; } void set_clock_mode (uint32_t m) { _clock_mode = m; } void set_scribble_mode (uint32_t m) { _scribble_mode = m; } void set_two_line_text (bool yn) { _two_line_text = yn; } void set_auto_pluginui (bool yn) { _auto_pluginui = yn; } uint32_t clock_mode () const { return _clock_mode; } uint32_t scribble_mode () const { return _scribble_mode; } bool twolinetext () const { return _two_line_text; } bool auto_pluginui () const { return _auto_pluginui; } void stop (); void do_request (FaderPort8Request*); void thread_init (); std::shared_ptr input_port() const { return _input_port; } std::shared_ptr output_port() const { return _output_port; } std::list > bundles (); size_t tx_midi (std::vector const&) const; CONTROL_PROTOCOL_THREADS_NEED_TEMPO_MAP_DECL(); private: void close (); void start_midi_handling (); void stop_midi_handling (); /* I/O Ports */ PBD::ScopedConnectionList port_connections; std::shared_ptr _input_port; std::shared_ptr _output_port; std::shared_ptr _input_bundle; std::shared_ptr _output_bundle; bool midi_input_handler (Glib::IOCondition ioc, std::weak_ptr port); bool connection_handler (std::string name1, std::string name2); void engine_reset (); enum ConnectionState { InputConnected = 0x1, OutputConnected = 0x2 }; void connected (); void disconnected (); int _connection_state; bool _device_active; /* MIDI input message handling */ void sysex_handler (MIDI::Parser &p, MIDI::byte *, size_t); void polypressure_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb); void pitchbend_handler (MIDI::Parser &, uint8_t chan, MIDI::pitchbend_t pb); void controller_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb); void note_on_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb); void note_off_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb); PBD::ScopedConnectionList midi_connections; /* *************************************************************************** * Control Elements */ FP8Controls _ctrls; void notify_stripable_added_or_removed (); void notify_fader_mode_changed (); void filter_stripables (ARDOUR::StripableList& strips) const; void assign_stripables (bool select_only = false); void set_periodic_display_mode (FP8Strip::DisplayMode); void assign_strips (); void bank (bool down, bool page); void move_selected_into_view (); void select_prev_next (bool next); void assign_sends (); void spill_plugins (); void assign_processor_ctrls (); bool assign_plugin_presets (std::shared_ptr); void build_well_known_processor_ctrls (std::shared_ptr, int); void preset_changed (); void select_plugin (int num); void select_plugin_preset (size_t num); void toggle_preset_param_mode (); void bank_param (bool down, bool page); /* bank offsets */ int get_channel_off (FP8Types::MixMode m) const { return _channel_off [m]; } void set_channel_off (FP8Types::MixMode m, int off) {_channel_off [m] = off ; } int _channel_off[FP8Types::MixModeMax + 1]; int _plugin_off; int _parameter_off; /* plugin + send mode stripable * * This is used when parameters of one strip are assigned to * individual FP8Strip controls (Edit Send, Edit Plugins). * * When there's one stripable per FP8Strip, FP8Strip itself keeps * track of the object lifetime and these are NULL. */ PBD::ScopedConnectionList processor_connections; PBD::ScopedConnectionList assigned_stripable_connections; typedef std::map, uint8_t> StripAssignmentMap; StripAssignmentMap _assigned_strips; void drop_ctrl_connections (); void select_strip (std::weak_ptr); void notify_pi_property_changed (const PBD::PropertyChange&); void notify_stripable_property_changed (std::weak_ptr, const PBD::PropertyChange&); void stripable_selection_changed (); void subscribe_to_strip_signals (); PBD::ScopedConnection selection_connection; PBD::ScopedConnectionList route_state_connections; PBD::ScopedConnectionList modechange_connections; /* **************************************************************************/ struct ProcessorCtrl { ProcessorCtrl (std::string const &n, std::shared_ptr c) : name (n) , ac (c) {} std::string name; std::shared_ptr ac; inline bool operator< (const ProcessorCtrl& other) const; }; std::list _proc_params; std::weak_ptr _plugin_insert; bool _show_presets; int _showing_well_known; /* **************************************************************************/ /* periodic updates, parameter poll */ sigc::connection _periodic_connection; bool periodic (); std::string _timecode; std::string _musical_time; std::string const& timecode () const { return _timecode; } std::string const& musical_time () const { return _musical_time; } int _timer_divider; bool show_meters () const { return _scribble_mode & 1; } bool show_panner () const { return _scribble_mode & 2; } /* sync button blink -- the FP's blink mode does not work */ sigc::connection _blink_connection; bool _blink_onoff; bool blink_it (); /* shift key */ sigc::connection _shift_connection; bool _shift_lock; int _shift_pressed; bool shift_timeout () { _shift_lock = true; return false; } bool shift_mod () const { return _shift_lock || (_shift_pressed > 0); } /* GUI */ void build_gui (); mutable void *gui; /* setup callbacks & actions */ void connect_session_signals (); void setup_actions (); void send_session_state (); /* callbacks */ PBD::ScopedConnectionList session_connections; void notify_parameter_changed (std::string); void notify_record_state_changed (); void notify_transport_state_changed (); void notify_loop_state_changed (); void notify_snap_change (); void notify_session_dirty_changed (); void notify_history_changed (); void notify_solo_changed (); void notify_mute_changed (); void notify_route_state_changed (); void notify_plugin_active_changed (); /* actions */ PBD::ScopedConnectionList button_connections; void button_play (); void button_stop (); void button_record (); void button_loop (); void button_metronom (); void button_bypass (); void button_open (); void button_link (); void button_lock (); void button_varispeed (bool); #ifdef FP8_MUTESOLO_UNDO void button_solo_clear (); #endif void button_mute_clear (); void button_arm (bool); void button_arm_all (); void button_automation (ARDOUR::AutoState); void button_prev_next (bool); void button_action (const std::string& group, const std::string& item); void button_chanlock (); /* FP2 only */ void button_flip (); /* FP2 only */ void button_encoder (); void button_parameter (); void encoder_navigate (bool, int); void encoder_parameter (bool, int); /* mute undo history */ #ifdef FP8_MUTESOLO_UNDO std::vector > _mute_state; std::vector > _solo_state; #endif /* Encoder handlers */ void handle_encoder_pan (int steps); void handle_encoder_link (int steps); /* Control Link */ void stop_link (); void start_link (); void lock_link (); void unlock_link (bool drop = false); void nofity_focus_control (std::weak_ptr); PBD::ScopedConnection link_connection; PBD::ScopedConnection link_locked_connection; std::weak_ptr _link_control; bool _link_enabled; bool _link_locked; // can only be true if _link_enabled bool _chan_locked; /* FP2 only */ /* user prefs */ uint32_t _clock_mode; uint32_t _scribble_mode; bool _two_line_text; bool _auto_pluginui; /* user bound actions */ void button_user (bool, FP8Controls::ButtonId); enum ActionType { Unset, NamedAction, // InternalFunction, // unused }; struct UserAction { UserAction () : _type (Unset) {} ActionType _type; std::string _action_name; //std::function function; // unused void clear () { _type = Unset; _action_name.clear(); } void assign_action (std::string const& action_name) { if (action_name.empty ()) { _type = Unset; _action_name.clear(); } else { _type = NamedAction; _action_name = action_name; } } bool empty () const { return _type == Unset; } void call (FaderPort8& _base) const { switch (_type) { case NamedAction: _base.access_action (_action_name); break; default: break; } } }; struct ButtonAction { UserAction on_press; UserAction on_release; UserAction& action (bool press) { return press ? on_press : on_release; } UserAction const& action (bool press) const { return press ? on_press : on_release; } void call (FaderPort8& _base, bool press) const { action (press).call (_base); } bool empty () const { return on_press.empty () && on_release.empty(); } }; typedef std::map UserActionMap; UserActionMap _user_action_map; }; } } /* namespace */ #endif /* ardour_surface_faderport8_h */