2017-04-05 05:04:16 -04:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2017 Robin Gareus <robin@gareus.org>
|
|
|
|
*
|
2019-08-03 08:34:29 -04:00
|
|
|
* 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.
|
2017-04-05 05:04:16 -04:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
2019-08-03 08:34:29 -04:00
|
|
|
* 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.
|
2017-04-05 05:04:16 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef ardour_surface_faderport8_h
|
|
|
|
#define ardour_surface_faderport8_h
|
|
|
|
|
2017-05-05 09:26:52 -04:00
|
|
|
// allow to undo "mute clear", "solo clear"
|
|
|
|
// eventually this should use some libardour mixer history/undo
|
|
|
|
#define FP8_MUTESOLO_UNDO
|
|
|
|
|
2017-04-05 05:04:16 -04:00
|
|
|
#include <list>
|
|
|
|
#include <map>
|
|
|
|
#include <glibmm/threads.h>
|
|
|
|
|
|
|
|
#define ABSTRACT_UI_EXPORTS
|
|
|
|
#include "pbd/abstract_ui.h"
|
|
|
|
#include "pbd/properties.h"
|
2017-07-02 12:16:54 -04:00
|
|
|
#include "pbd/controllable.h"
|
2017-04-05 05:04:16 -04:00
|
|
|
|
|
|
|
#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;
|
2017-06-29 19:59:12 -04:00
|
|
|
class PluginInsert;
|
2017-04-05 05:04:16 -04:00
|
|
|
}
|
|
|
|
|
2017-12-12 08:09:40 -05:00
|
|
|
namespace ArdourSurface { namespace FP_NAMESPACE {
|
2017-04-05 05:04:16 -04:00
|
|
|
|
|
|
|
struct FaderPort8Request : public BaseUI::BaseRequestObject
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FaderPort8Request () {}
|
|
|
|
~FaderPort8Request () {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class FaderPort8 : public FP8Base, public ARDOUR::ControlProtocol, public AbstractUI<FaderPort8Request>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FaderPort8 (ARDOUR::Session&);
|
|
|
|
virtual ~FaderPort8();
|
|
|
|
|
|
|
|
int set_active (bool yn);
|
|
|
|
|
|
|
|
/* we probe for a device when our ports are connected. Before that,
|
|
|
|
* there's no way to know if the device exists or not.
|
|
|
|
*/
|
|
|
|
static bool probe() { return true; }
|
|
|
|
static void* request_factory (uint32_t);
|
|
|
|
|
2022-04-06 23:56:32 -04:00
|
|
|
XMLNode& get_state () const;
|
2017-04-05 05:04:16 -04:00
|
|
|
int set_state (const XMLNode&, int version);
|
|
|
|
|
|
|
|
/* configuration GUI */
|
|
|
|
bool has_editor () const { return true; }
|
|
|
|
void* get_gui () const;
|
|
|
|
void tear_down_gui ();
|
|
|
|
PBD::Signal0<void> 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; }
|
|
|
|
|
2017-06-30 13:55:03 -04:00
|
|
|
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; }
|
2017-07-01 20:06:48 -04:00
|
|
|
void set_auto_pluginui (bool yn) { _auto_pluginui = yn; }
|
2017-06-30 13:55:03 -04:00
|
|
|
|
|
|
|
uint32_t clock_mode () const { return _clock_mode; }
|
|
|
|
uint32_t scribble_mode () const { return _scribble_mode; }
|
|
|
|
bool twolinetext () const { return _two_line_text; }
|
2017-07-01 20:06:48 -04:00
|
|
|
bool auto_pluginui () const { return _auto_pluginui; }
|
2017-06-30 13:55:03 -04:00
|
|
|
|
2017-07-06 10:55:02 -04:00
|
|
|
void stop ();
|
2017-04-05 05:04:16 -04:00
|
|
|
void do_request (FaderPort8Request*);
|
|
|
|
void thread_init ();
|
|
|
|
|
2023-02-16 18:33:28 -05:00
|
|
|
std::shared_ptr<ARDOUR::Port> input_port() const { return _input_port; }
|
|
|
|
std::shared_ptr<ARDOUR::Port> output_port() const { return _output_port; }
|
|
|
|
std::list<std::shared_ptr<ARDOUR::Bundle> > bundles ();
|
2017-04-05 05:04:16 -04:00
|
|
|
|
|
|
|
size_t tx_midi (std::vector<uint8_t> const&) const;
|
|
|
|
|
2022-05-16 17:24:27 -04:00
|
|
|
CONTROL_PROTOCOL_THREADS_NEED_TEMPO_MAP_DECL();
|
|
|
|
|
2017-04-05 05:04:16 -04:00
|
|
|
private:
|
|
|
|
void close ();
|
|
|
|
|
|
|
|
void start_midi_handling ();
|
|
|
|
void stop_midi_handling ();
|
|
|
|
|
|
|
|
/* I/O Ports */
|
2017-04-18 09:14:00 -04:00
|
|
|
PBD::ScopedConnectionList port_connections;
|
2023-02-16 18:33:28 -05:00
|
|
|
std::shared_ptr<ARDOUR::AsyncMIDIPort> _input_port;
|
|
|
|
std::shared_ptr<ARDOUR::AsyncMIDIPort> _output_port;
|
|
|
|
std::shared_ptr<ARDOUR::Bundle> _input_bundle;
|
|
|
|
std::shared_ptr<ARDOUR::Bundle> _output_bundle;
|
2017-04-05 05:04:16 -04:00
|
|
|
|
2023-02-16 18:33:28 -05:00
|
|
|
bool midi_input_handler (Glib::IOCondition ioc, std::weak_ptr<ARDOUR::AsyncMIDIPort> port);
|
2017-04-05 05:04:16 -04:00
|
|
|
|
2017-04-18 09:14:00 -04:00
|
|
|
bool connection_handler (std::string name1, std::string name2);
|
|
|
|
void engine_reset ();
|
2017-04-05 05:04:16 -04:00
|
|
|
|
|
|
|
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;
|
2017-04-14 07:57:14 -04:00
|
|
|
void assign_stripables (bool select_only = false);
|
2017-04-05 05:04:16 -04:00
|
|
|
void set_periodic_display_mode (FP8Strip::DisplayMode);
|
|
|
|
|
2017-07-18 21:04:58 -04:00
|
|
|
void assign_strips ();
|
2017-04-05 05:04:16 -04:00
|
|
|
void bank (bool down, bool page);
|
|
|
|
void move_selected_into_view ();
|
2017-04-14 07:57:14 -04:00
|
|
|
void select_prev_next (bool next);
|
2017-04-05 05:04:16 -04:00
|
|
|
|
|
|
|
void assign_sends ();
|
|
|
|
void spill_plugins ();
|
|
|
|
void assign_processor_ctrls ();
|
2023-02-16 18:33:28 -05:00
|
|
|
bool assign_plugin_presets (std::shared_ptr<ARDOUR::PluginInsert>);
|
|
|
|
void build_well_known_processor_ctrls (std::shared_ptr<ARDOUR::Stripable>, bool);
|
2017-06-30 06:13:21 -04:00
|
|
|
void preset_changed ();
|
2017-04-05 05:04:16 -04:00
|
|
|
void select_plugin (int num);
|
2017-06-30 06:13:21 -04:00
|
|
|
void select_plugin_preset (size_t num);
|
2017-04-05 05:04:16 -04:00
|
|
|
|
2017-06-30 06:13:21 -04:00
|
|
|
void toggle_preset_param_mode ();
|
2017-04-05 05:04:16 -04:00
|
|
|
void bank_param (bool down, bool page);
|
|
|
|
/* bank offsets */
|
2017-07-18 21:04:58 -04:00
|
|
|
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];
|
2017-04-05 05:04:16 -04:00
|
|
|
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;
|
2023-02-16 18:33:28 -05:00
|
|
|
typedef std::map<std::shared_ptr<ARDOUR::Stripable>, uint8_t> StripAssignmentMap;
|
2017-04-05 05:04:16 -04:00
|
|
|
StripAssignmentMap _assigned_strips;
|
|
|
|
|
|
|
|
void drop_ctrl_connections ();
|
|
|
|
|
2023-02-16 18:33:28 -05:00
|
|
|
void select_strip (std::weak_ptr<ARDOUR::Stripable>);
|
2017-04-20 10:06:47 -04:00
|
|
|
|
2017-04-05 05:04:16 -04:00
|
|
|
void notify_pi_property_changed (const PBD::PropertyChange&);
|
2023-02-16 18:33:28 -05:00
|
|
|
void notify_stripable_property_changed (std::weak_ptr<ARDOUR::Stripable>, const PBD::PropertyChange&);
|
2017-05-12 09:51:31 -04:00
|
|
|
void stripable_selection_changed ();
|
2018-07-31 08:46:20 -04:00
|
|
|
void subscribe_to_strip_signals ();
|
2017-04-05 05:04:16 -04:00
|
|
|
|
|
|
|
PBD::ScopedConnection selection_connection;
|
2018-07-31 08:46:20 -04:00
|
|
|
PBD::ScopedConnectionList route_state_connections;
|
2017-04-05 05:04:16 -04:00
|
|
|
PBD::ScopedConnectionList modechange_connections;
|
|
|
|
/* **************************************************************************/
|
|
|
|
struct ProcessorCtrl {
|
2023-02-16 18:33:28 -05:00
|
|
|
ProcessorCtrl (std::string const &n, std::shared_ptr<ARDOUR::AutomationControl> c)
|
2017-04-05 05:04:16 -04:00
|
|
|
: name (n)
|
|
|
|
, ac (c)
|
|
|
|
{}
|
|
|
|
std::string name;
|
2023-02-16 18:33:28 -05:00
|
|
|
std::shared_ptr<ARDOUR::AutomationControl> ac;
|
2020-11-20 00:04:32 -05:00
|
|
|
|
|
|
|
inline bool operator< (const ProcessorCtrl& other) const;
|
2017-04-05 05:04:16 -04:00
|
|
|
};
|
2020-11-20 00:04:32 -05:00
|
|
|
|
2017-04-05 05:04:16 -04:00
|
|
|
std::list <ProcessorCtrl> _proc_params;
|
2023-02-16 18:33:28 -05:00
|
|
|
std::weak_ptr<ARDOUR::PluginInsert> _plugin_insert;
|
2017-06-30 06:13:21 -04:00
|
|
|
bool _show_presets;
|
2017-04-14 07:57:14 -04:00
|
|
|
int _showing_well_known;
|
2017-04-05 05:04:16 -04:00
|
|
|
/* **************************************************************************/
|
|
|
|
|
|
|
|
/* periodic updates, parameter poll */
|
|
|
|
sigc::connection _periodic_connection;
|
|
|
|
bool periodic ();
|
|
|
|
std::string _timecode;
|
2017-06-30 13:55:03 -04:00
|
|
|
std::string _musical_time;
|
2017-04-05 05:04:16 -04:00
|
|
|
std::string const& timecode () const { return _timecode; }
|
2017-06-30 13:55:03 -04:00
|
|
|
std::string const& musical_time () const { return _musical_time; }
|
|
|
|
|
2017-12-12 07:29:54 -05:00
|
|
|
int _timer_divider;
|
|
|
|
|
2017-06-30 13:55:03 -04:00
|
|
|
bool show_meters () const { return _scribble_mode & 1; }
|
|
|
|
bool show_panner () const { return _scribble_mode & 2; }
|
2017-04-05 05:04:16 -04:00
|
|
|
|
|
|
|
/* 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;
|
2017-04-15 15:20:51 -04:00
|
|
|
int _shift_pressed;
|
2017-04-05 05:04:16 -04:00
|
|
|
bool shift_timeout () { _shift_lock = true; return false; }
|
2017-04-15 15:20:51 -04:00
|
|
|
bool shift_mod () const { return _shift_lock || (_shift_pressed > 0); }
|
2017-04-05 05:04:16 -04:00
|
|
|
|
|
|
|
/* 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 ();
|
2018-07-31 08:46:20 -04:00
|
|
|
void notify_route_state_changed ();
|
2017-06-29 19:59:12 -04:00
|
|
|
void notify_plugin_active_changed ();
|
2017-04-05 05:04:16 -04:00
|
|
|
|
|
|
|
/* actions */
|
|
|
|
PBD::ScopedConnectionList button_connections;
|
|
|
|
void button_play ();
|
|
|
|
void button_stop ();
|
|
|
|
void button_record ();
|
|
|
|
void button_loop ();
|
|
|
|
void button_metronom ();
|
2017-06-29 19:59:12 -04:00
|
|
|
void button_bypass ();
|
2017-07-01 20:06:48 -04:00
|
|
|
void button_open ();
|
2017-07-02 12:16:54 -04:00
|
|
|
void button_link ();
|
|
|
|
void button_lock ();
|
2017-04-05 05:04:16 -04:00
|
|
|
void button_varispeed (bool);
|
2017-05-05 09:26:52 -04:00
|
|
|
#ifdef FP8_MUTESOLO_UNDO
|
|
|
|
void button_solo_clear ();
|
|
|
|
#endif
|
2017-04-05 05:04:16 -04:00
|
|
|
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);
|
|
|
|
|
2018-07-31 08:46:20 -04:00
|
|
|
void button_chanlock (); /* FP2 only */
|
|
|
|
void button_flip (); /* FP2 only */
|
|
|
|
|
2017-04-05 05:04:16 -04:00
|
|
|
void button_encoder ();
|
|
|
|
void button_parameter ();
|
|
|
|
void encoder_navigate (bool, int);
|
|
|
|
void encoder_parameter (bool, int);
|
|
|
|
|
2017-05-05 09:26:52 -04:00
|
|
|
/* mute undo history */
|
|
|
|
#ifdef FP8_MUTESOLO_UNDO
|
2023-02-16 18:33:28 -05:00
|
|
|
std::vector <std::weak_ptr<ARDOUR::AutomationControl> > _mute_state;
|
|
|
|
std::vector <std::weak_ptr<ARDOUR::AutomationControl> > _solo_state;
|
2017-05-05 09:26:52 -04:00
|
|
|
#endif
|
|
|
|
|
2017-07-02 12:16:54 -04:00
|
|
|
/* 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);
|
2023-02-16 18:33:28 -05:00
|
|
|
void nofity_focus_control (std::weak_ptr<PBD::Controllable>);
|
2017-07-02 12:16:54 -04:00
|
|
|
PBD::ScopedConnection link_connection;
|
|
|
|
PBD::ScopedConnection link_locked_connection;
|
2023-02-16 18:33:28 -05:00
|
|
|
std::weak_ptr<PBD::Controllable> _link_control;
|
2017-07-02 12:16:54 -04:00
|
|
|
bool _link_enabled;
|
|
|
|
bool _link_locked; // can only be true if _link_enabled
|
|
|
|
|
2018-07-31 08:46:20 -04:00
|
|
|
bool _chan_locked; /* FP2 only */
|
|
|
|
|
2017-06-30 13:55:03 -04:00
|
|
|
/* user prefs */
|
|
|
|
uint32_t _clock_mode;
|
|
|
|
uint32_t _scribble_mode;
|
|
|
|
bool _two_line_text;
|
2017-07-01 20:06:48 -04:00
|
|
|
bool _auto_pluginui;
|
2017-06-30 13:55:03 -04:00
|
|
|
|
2017-04-05 05:04:16 -04:00
|
|
|
/* 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;
|
|
|
|
//boost::function<void()> 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<FP8Controls::ButtonId, ButtonAction> UserActionMap;
|
|
|
|
UserActionMap _user_action_map;
|
|
|
|
};
|
|
|
|
|
2017-12-12 08:09:40 -05:00
|
|
|
} } /* namespace */
|
2017-04-05 05:04:16 -04:00
|
|
|
|
|
|
|
#endif /* ardour_surface_faderport8_h */
|