/* * Copyright (C) 2006-2012 David Robillard * Copyright (C) 2006-2017 Paul Davis * Copyright (C) 2009-2010 Carl Hetherington * Copyright (C) 2013-2017 John Emmas * * 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_control_protocols_h #define ardour_control_protocols_h #include #include #include #include #include "pbd/signals.h" #include "pbd/stateful.h" #include "pbd/glib_event_source.h" #include "control_protocol/basic_ui.h" #include "control_protocol/types.h" #include "control_protocol/visibility.h" namespace ARDOUR { class Route; class Session; class Bundle; class Stripable; class LIBCONTROLCP_API ControlProtocol : public PBD::Stateful, public PBD::ScopedConnectionList, public BasicUI { public: ControlProtocol (Session&, std::string name); virtual ~ControlProtocol (); virtual std::string name () const { return _name; } virtual int set_active (bool yn); virtual bool active () const { return _active; } virtual int set_feedback (bool /*yn*/) { return 0; } virtual bool get_feedback () const { return false; } virtual void midi_connectivity_established () {} virtual void stripable_selection_changed () = 0; PBD::Signal0 ActiveChanged; /* signals that a control protocol can emit and other (presumably graphical) * user interfaces can respond to */ static PBD::Signal0 ZoomToSession; static PBD::Signal0 ZoomIn; static PBD::Signal0 ZoomOut; static PBD::Signal0 Enter; static PBD::Signal0 Undo; static PBD::Signal0 Redo; static PBD::Signal1 ScrollTimeline; static PBD::Signal1 GotoView; static PBD::Signal0 CloseDialog; static PBD::Signal0 VerticalZoomInAll; static PBD::Signal0 VerticalZoomOutAll; static PBD::Signal0 VerticalZoomInSelected; static PBD::Signal0 VerticalZoomOutSelected; static PBD::Signal0 StepTracksDown; static PBD::Signal0 StepTracksUp; void add_stripable_to_selection (boost::shared_ptr); void set_stripable_selection (boost::shared_ptr); void toggle_stripable_selection (boost::shared_ptr); void remove_stripable_from_selection (boost::shared_ptr); void clear_stripable_selection (); virtual void add_rid_to_selection (int rid); virtual void set_rid_selection (int rid); virtual void toggle_rid_selection (int rid); virtual void remove_rid_from_selection (int rid); boost::shared_ptr first_selected_stripable () const; /* the model here is as follows: we imagine most control surfaces being able to control from 1 to N tracks at a time, with a session that may contain 1 to M tracks, where M may be smaller, larger or equal to N. the control surface has a fixed set of physical controllers which can potentially be mapped onto different tracks/busses via some mechanism. therefore, the control protocol object maintains a table that reflects the current mapping between the controls and route object. */ void set_route_table_size (uint32_t size); void set_route_table (uint32_t table_index, boost::shared_ptr); bool set_route_table (uint32_t table_index, uint32_t remote_control_id); void route_set_rec_enable (uint32_t table_index, bool yn); bool route_get_rec_enable (uint32_t table_index); float route_get_gain (uint32_t table_index); void route_set_gain (uint32_t table_index, float); float route_get_effective_gain (uint32_t table_index); float route_get_peak_input_power (uint32_t table_index, uint32_t which_input); bool route_get_muted (uint32_t table_index); void route_set_muted (uint32_t table_index, bool); bool route_get_soloed (uint32_t table_index); void route_set_soloed (uint32_t table_index, bool); std::string route_get_name (uint32_t table_index); virtual std::list > bundles (); virtual bool has_editor () const { return false; } virtual void* get_gui () const { return 0; } virtual void tear_down_gui () {} XMLNode& get_state () const; int set_state (XMLNode const&, int version); static const std::string state_node_name; static StripableNotificationList const& last_selected () { return _last_selected; } static void notify_stripable_selection_changed (StripableNotificationListPtr); protected: void next_track (uint32_t initial_id); void prev_track (uint32_t initial_id); std::vector > route_table; std::string _name; GlibEventLoopCallback glib_event_callback; virtual void event_loop_precall (); void install_precall_handler (Glib::RefPtr); private: LIBCONTROLCP_LOCAL ControlProtocol (const ControlProtocol&); /* noncopyable */ bool _active; static StripableNotificationList _last_selected; static PBD::ScopedConnection selection_connection; static bool selection_connected; }; extern "C" { class ControlProtocolDescriptor { public: const char* name; /* descriptive */ const char* id; /* unique and version-specific */ void* ptr; /* protocol can store a value here */ void* module; /* not for public access */ int mandatory; /* if non-zero, always load and do not make optional */ bool supports_feedback; /* if true, protocol has toggleable feedback mechanism */ bool (*probe) (ControlProtocolDescriptor*); ControlProtocol* (*initialize) (ControlProtocolDescriptor*, Session*); void (*destroy) (ControlProtocolDescriptor*, ControlProtocol*); /* this is required if the control protocol connects to signals * from libardour. they all do. It should allocate a * type-specific request buffer for the calling thread, and * store it in a thread-local location that will be used to * find it when sending the event loop a message * (e.g. call_slot()). It should also return the allocated * buffer as a void*. */ void* (*request_buffer_factory) (uint32_t); }; } } /* this is where the strange inheritance pattern hits the wall. A control protocol thread/event loop is inherited from AbstractUI, but the precall handler is inherited from ControlProtocol. When the AbstractUI sets up the event loop, it will call attach_request_source() which will in turn pass a Glib::MainContext to maybe_install_precall_handler(). We override the definition of that method here to make it actuall install the ControlProtocol's handler. */ #define CONTROL_PROTOCOL_THREADS_NEED_TEMPO_MAP_DECL() \ void maybe_install_precall_handler (Glib::RefPtr ctxt) { install_precall_handler (ctxt); } #endif // ardour_control_protocols_h