ardour/libs/surfaces/launch_control_xl/launch_control_xl.h

657 lines
17 KiB
C++

/*
* Copyright (C) 2018 Jan Lentfer <jan.lentfer@web.de>
* Copyright (C) 2018 Robin Gareus <robin@gareus.org>
* Copyright (C) 2018 Térence Clastres <t.clastres@gmail.com>
*
* 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_launch_control_h__
#define __ardour_launch_control_h__
#include <vector>
#include <map>
#include <stack>
#include <list>
#include <set>
#define ABSTRACT_UI_EXPORTS
#include "pbd/abstract_ui.h"
#include "midi++/types.h"
#include "ardour/mode.h"
#include "ardour/types.h"
#include "control_protocol/control_protocol.h"
#include "control_protocol/types.h"
#include "midi_byte_array.h"
namespace MIDI {
class Parser;
class Port;
} // namespace MIDI
namespace ARDOUR {
class AsyncMIDIPort;
class Port;
class MidiBuffer;
class MidiTrack;
} // namespace ARDOUR
namespace ArdourSurface {
struct LaunchControlRequest : public BaseUI::BaseRequestObject {
public:
LaunchControlRequest() {}
~LaunchControlRequest() {}
};
class LCXLGUI;
class LaunchControlMenu;
class LaunchControlXL : public ARDOUR::ControlProtocol,
public AbstractUI<LaunchControlRequest>
{
public:
enum TrackMode {
TrackMute,
TrackSolo,
TrackRecord
};
enum ButtonID {
Focus1 = 0,
Focus2,
Focus3,
Focus4,
Focus5,
Focus6,
Focus7,
Focus8,
Control1,
Control2,
Control3,
Control4,
Control5,
Control6,
Control7,
Control8,
Device,
Mute,
Solo,
Record,
SelectUp,
SelectDown,
SelectLeft,
SelectRight
};
enum FaderID {
Fader1 = 0,
Fader2,
Fader3,
Fader4,
Fader5,
Fader6,
Fader7,
Fader8
};
enum KnobID {
SendA1 = 0,
SendA2,
SendA3,
SendA4,
SendA5,
SendA6,
SendA7,
SendA8,
SendB1,
SendB2,
SendB3,
SendB4,
SendB5,
SendB6,
SendB7,
SendB8,
Pan1,
Pan2,
Pan3,
Pan4,
Pan5,
Pan6,
Pan7,
Pan8
};
enum DeviceStatus {
dev_nonexistant = 0,
dev_inactive,
dev_active
};
enum LEDFlag { Normal = 0xC, Blink = 0x8, DoubleBuffering = 0x0 };
enum LEDColor { Off=0, RedLow = 1, RedFull = 3, GreenLow = 16, GreenFull = 48, YellowLow = 34, YellowFull = 51, AmberLow = 18, AmberFull = 35};
#ifdef MIXBUS
enum CompParam {
CompMakeup,
CompMode,
CompSpeed
};
#endif
struct Controller {
Controller(uint8_t cn, uint8_t val, boost::function<void ()> action)
: _controller_number(cn)
, _value(val)
, action_method(action) {}
uint8_t controller_number() const { return _controller_number; }
uint8_t value() const { return _value; }
void set_value(uint8_t val) { _value = val; }
protected:
uint8_t _controller_number;
uint8_t _value;
public:
boost::function<void ()> action_method;
};
struct LED {
LED(uint8_t i, LEDColor c, LaunchControlXL& l) : _index(i), _color(c), _flag(Normal), lcxl(&l) {}
LED(uint8_t i, LEDColor c, LEDFlag f, LaunchControlXL& lcxl) : _index(i), _color(c), _flag(f) {}
virtual ~LED() {}
LEDColor color() const { return _color; }
LEDFlag flag() const { return _flag; }
uint8_t index() const { return _index; }
void set_flag(LEDFlag f) { _flag = f; }
virtual MidiByteArray state_msg(bool light) const = 0;
protected:
uint8_t _index;
LEDColor _color;
LEDFlag _flag;
MidiByteArray _state_msg;
LaunchControlXL* lcxl;
};
struct MultiColorLED : public LED {
MultiColorLED (uint8_t i, LEDColor c, LaunchControlXL& l) : LED(i, c, l) {}
MultiColorLED (uint8_t i, LEDColor c, LEDFlag f, LaunchControlXL& l)
: LED(i, c, f, l) {}
void set_color(LEDColor c) { _color = c; }
};
struct Button {
Button(ButtonID id, boost::function<void ()> press, boost::function<void ()> release,
boost::function<void ()> long_press)
: press_method(press)
, release_method(release)
, long_press_method(long_press),
_id(id) {}
virtual ~Button() {}
ButtonID id() const { return _id; }
boost::function<void ()> press_method;
boost::function<void ()> release_method;
boost::function<void ()> long_press_method;
sigc::connection timeout_connection;
protected:
ButtonID _id;
};
struct ControllerButton : public Button {
ControllerButton(ButtonID id, uint8_t cn,
boost::function<void ()> press,
boost::function<void ()> release,
boost::function<void ()> long_release)
: Button(id, press, release, long_release), _controller_number(cn) {}
uint8_t controller_number() const { return _controller_number; }
private:
uint8_t _controller_number;
};
struct NoteButton : public Button {
NoteButton(ButtonID id, uint8_t cn,
boost::function<void ()> press,
boost::function<void ()> release,
boost::function<void ()> release_long)
: Button(id, press, release, release_long), _note_number(cn) {}
uint8_t note_number() const { return _note_number; }
private:
uint8_t _note_number;
};
struct TrackButton : public NoteButton, public MultiColorLED {
TrackButton(ButtonID id, uint8_t nn, uint8_t index, LEDColor c_on, LEDColor c_off,
boost::function<void ()> press,
boost::function<void ()> release,
boost::function<void ()> release_long,
boost::function<uint8_t ()> check,
LaunchControlXL& l)
: NoteButton(id, nn, press, release, release_long)
, MultiColorLED(index, Off, l)
, check_method(check)
, _color_enabled (c_on)
, _color_disabled (c_off) {}
LEDColor color_enabled() const { return _color_enabled; }
LEDColor color_disabled() const { return _color_disabled; }
void set_color_enabled (LEDColor c_on) { _color_enabled = c_on; }
void set_color_disabled (LEDColor c_off) { _color_disabled = c_off; }
boost::function<uint8_t ()> check_method;
MidiByteArray state_msg(bool light = true) const;
private:
LEDColor _color_enabled;
LEDColor _color_disabled;
};
struct SelectButton : public ControllerButton, public LED {
SelectButton(ButtonID id, uint8_t cn, uint8_t index,
boost::function<void ()> press,
boost::function<void ()> release,
boost::function<void ()> long_release,
LaunchControlXL& l)
: ControllerButton(id, cn, press, release, long_release), LED(index, RedFull, l) {}
MidiByteArray state_msg(bool light) const;
};
struct TrackStateButton : public NoteButton, public LED {
TrackStateButton(ButtonID id, uint8_t nn, uint8_t index,
boost::function<void ()> press,
boost::function<void ()> release,
boost::function<void ()> release_long,
LaunchControlXL& l)
: NoteButton(id, nn, press, release, release_long)
, LED(index, YellowLow, l) {}
MidiByteArray state_msg(bool light) const;
};
struct Fader : public Controller {
Fader(FaderID id, uint8_t cn, boost::function<void ()> action)
: Controller(cn, 0, action), _id(id) {} // minimal value
FaderID id() const { return _id; }
void controller_changed(Controller* controller);
private:
FaderID _id;
};
struct Knob : public Controller, public MultiColorLED {
Knob(KnobID id, uint8_t cn, uint8_t index, LEDColor c_on, LEDColor c_off, boost::function<void ()> action,
LaunchControlXL &l)
: Controller(cn, 64, action)
, MultiColorLED(index, Off, l)
, _id(id)
, _color_enabled (c_on)
, _color_disabled (c_off) {} // knob 50/50 value
Knob(KnobID id, uint8_t cn, uint8_t index, LEDColor c_on, LEDColor c_off, boost::function<void ()> action,
boost::function<uint8_t ()> check, LaunchControlXL &l)
: Controller(cn, 64, action)
, MultiColorLED(index, Off, l)
, check_method(check)
, _id(id)
, _color_enabled (c_on)
, _color_disabled (c_off) {} // knob 50/50 value
KnobID id() const { return _id; }
LEDColor color_enabled() const { return _color_enabled; }
LEDColor color_disabled() const { return _color_disabled; }
boost::function<uint8_t ()> check_method;
MidiByteArray state_msg(bool light = true) const;
private:
KnobID _id;
LEDColor _color_enabled;
LEDColor _color_disabled;
};
public:
LaunchControlXL(ARDOUR::Session &);
~LaunchControlXL();
std::list<std::shared_ptr<ARDOUR::Bundle> > bundles();
bool has_editor() const { return true; }
void *get_gui() const;
void tear_down_gui();
int get_amount_of_tracks();
int set_active(bool yn);
XMLNode& get_state() const;
int set_state(const XMLNode &node, int version);
PBD::Signal0<void> ConnectionChange;
std::shared_ptr<ARDOUR::Port> input_port();
std::shared_ptr<ARDOUR::Port> output_port();
Button *button_by_id(ButtonID);
static std::string button_name_by_id(ButtonID);
static std::string knob_name_by_id(KnobID);
static std::string fader_name_by_id(FaderID);
void write(const MidiByteArray &);
void reset(uint8_t chan);
void set_fader8master (bool yn);
bool fader8master () const { return _fader8master; }
void set_refresh_leds_flag (bool yn);
bool refresh_leds_flag () const { return _refresh_leds_flag; }
void set_device_mode (bool yn);
bool device_mode () const { return _device_mode; }
#ifdef MIXBUS
void set_ctrllowersends (bool yn);
bool ctrllowersends () const { return _ctrllowersends; }
void store_fss_type();
bool fss_is_mixbus() const { return _fss_is_mixbus; }
#endif
TrackMode track_mode() const { return _track_mode; }
void set_track_mode(TrackMode mode);
uint8_t template_number() const { return _template_number; }
void set_send_bank (int offset);
void send_bank_switch(bool up);
int send_bank_base () const { return _send_bank_base; }
CONTROL_PROTOCOL_THREADS_NEED_TEMPO_MAP_DECL();
private:
bool in_use;
TrackMode _track_mode;
uint8_t _template_number;
bool _fader8master;
bool _device_mode;
#ifdef MIXBUS
bool _ctrllowersends;
bool _fss_is_mixbus;
#endif
bool _refresh_leds_flag;
int _send_bank_base;
void do_request(LaunchControlRequest *);
int begin_using_device();
int stop_using_device();
int ports_acquire();
void ports_release();
void run_event_loop();
void stop_event_loop();
void relax() {}
/* map of NoteButtons by NoteNumber */
typedef std::map<int, std::shared_ptr<NoteButton> > NNNoteButtonMap;
NNNoteButtonMap nn_note_button_map;
/* map of NoteButtons by ButtonID */
typedef std::map<ButtonID, std::shared_ptr<NoteButton> > IDNoteButtonMap;
IDNoteButtonMap id_note_button_map;
/* map of ControllerNoteButtons by CC */
typedef std::map<int, std::shared_ptr<ControllerButton> > CCControllerButtonMap;
CCControllerButtonMap cc_controller_button_map;
/* map of ControllerButtons by ButtonID */
typedef std::map<ButtonID, std::shared_ptr<ControllerButton> > IDControllerButtonMap;
IDControllerButtonMap id_controller_button_map;
/* map of Fader by CC */
typedef std::map<int, std::shared_ptr<Fader> > CCFaderMap;
CCFaderMap cc_fader_map;
/* map of Fader by FaderID */
typedef std::map<FaderID, std::shared_ptr<Fader> > IDFaderMap;
IDFaderMap id_fader_map;
/* map of Knob by CC */
typedef std::map<int, std::shared_ptr<Knob> > CCKnobMap;
CCKnobMap cc_knob_map;
/* map of Knob by KnobID */
typedef std::map<KnobID, std::shared_ptr<Knob> > IDKnobMap;
IDKnobMap id_knob_map;
std::set<ButtonID> buttons_down;
std::set<ButtonID> consumed;
bool button_long_press_timeout(ButtonID id, std::shared_ptr<Button> button);
void start_press_timeout(std::shared_ptr<Button> , ButtonID);
void init_buttons();
void init_buttons(bool startup);
void init_buttons (ButtonID buttons[], uint8_t i);
void init_knobs();
void init_knobs(KnobID knobs[], uint8_t i);
void init_knobs_and_buttons();
void init_device_mode();
void init_dm_callbacks();
void switch_template(uint8_t t);
void filter_stripables (ARDOUR::StripableList& strips) const;
void build_maps();
// Bundle to represent our input ports
std::shared_ptr<ARDOUR::Bundle> _input_bundle;
// Bundle to represent our output ports
std::shared_ptr<ARDOUR::Bundle> _output_bundle;
MIDI::Port *_input_port;
MIDI::Port *_output_port;
std::shared_ptr<ARDOUR::Port> _async_in;
std::shared_ptr<ARDOUR::Port> _async_out;
void connect_to_parser();
void handle_button_message(std::shared_ptr<Button> button, MIDI::EventTwoBytes *);
bool check_pick_up(std::shared_ptr<Controller> controller, std::shared_ptr<ARDOUR::AutomationControl> ac, bool rotary = false);
void handle_midi_controller_message(MIDI::Parser &, MIDI::EventTwoBytes *, MIDI::channel_t chan);
void handle_midi_note_on_message(MIDI::Parser &, MIDI::EventTwoBytes *, MIDI::channel_t chan);
void handle_midi_note_off_message(MIDI::Parser &, MIDI::EventTwoBytes *, MIDI::channel_t chan);
void handle_midi_sysex(MIDI::Parser &, MIDI::byte *, size_t count);
bool midi_input_handler(Glib::IOCondition ioc, MIDI::Port *port);
void thread_init();
PBD::ScopedConnectionList session_connections;
void connect_session_signals();
void notify_transport_state_changed();
void notify_loop_state_changed();
void notify_parameter_changed(std::string);
/* Knob methods */
std::shared_ptr<Knob> knob_by_id(KnobID id);
std::shared_ptr<Knob>* knobs_by_column(uint8_t col, std::shared_ptr<Knob>* knob_col);
void update_knob_led_by_strip(uint8_t n);
void update_knob_led_by_id(uint8_t id, LEDColor color);
void knob_sendA(uint8_t n);
void knob_sendB(uint8_t n);
void knob_pan(uint8_t n);
uint8_t dm_check_dummy(DeviceStatus ds);
void dm_fader(FaderID id);
uint8_t dm_check_pan_azi ();
void dm_pan_azi(KnobID k);
uint8_t dm_check_pan_width();
void dm_pan_width (KnobID k);
uint8_t dm_check_trim ();
void dm_trim(KnobID k);
uint8_t dm_mute_enabled();
void dm_mute_switch();
uint8_t dm_solo_enabled();
void dm_solo_switch();
uint8_t dm_recenable_enabled();
void dm_recenable_switch();
void dm_select_prev_strip();
void dm_select_next_strip();
#ifdef MIXBUS
void dm_mb_eq_switch();
void dm_mb_eq (KnobID k, bool gain, uint8_t band);
uint8_t dm_mb_eq_freq_enabled();
uint8_t dm_mb_eq_gain_enabled(uint8_t band);
void dm_mb_eq_shape_switch(uint8_t band);
uint8_t dm_mb_eq_shape_enabled(uint8_t band);
uint8_t dm_mb_flt_enabled();
void dm_mb_flt_frq (KnobID k, bool hpf);
void dm_mb_flt_switch();
void dm_mb_send_enabled(KnobID k);
uint8_t dm_mb_check_send_knob(KnobID k);
uint8_t dm_mb_check_send_button(uint8_t s);
void dm_mb_sends (KnobID k);
void dm_mb_send_switch (ButtonID b);
uint8_t dm_mb_comp_enabled();
void dm_mb_comp_switch();
void dm_mb_comp (KnobID k, CompParam c);
void dm_mb_comp_thresh (FaderID id);
uint8_t dm_mb_has_tapedrive();
void dm_mb_tapedrive (KnobID k);
uint8_t dm_mb_master_assign_enabled();
void dm_mb_master_assign_switch();
#endif
/* Fader methods */
void fader(uint8_t n);
/* Button methods */
std::shared_ptr<TrackButton> track_button_by_range(uint8_t n, uint8_t first, uint8_t middle);
std::shared_ptr<TrackButton> focus_button_by_column(uint8_t col) { return track_button_by_range(col, 41, 57) ; }
std::shared_ptr<TrackButton> control_button_by_column(uint8_t col) { return track_button_by_range(col, 73, 89) ; }
void button_device();
void button_device_long_press();
void button_track_mode(TrackMode state);
void button_mute();
void button_mute_long_press();
void button_solo();
void button_solo_long_press();
void button_record();
void button_select_up();
void button_select_down();
void button_select_left();
void button_select_right();
void button_track_focus(uint8_t n);
void button_press_track_control(uint8_t n);
void button_release_track_control(uint8_t n);
std::shared_ptr<ARDOUR::AutomationControl> get_ac_by_state(uint8_t n);
void update_track_focus_led(uint8_t n);
void update_track_control_led(uint8_t n);
void send_bank_switch_0() { send_bank_switch(0); }
void send_bank_switch_1() { send_bank_switch(1); }
/* stripables */
int32_t bank_start;
PBD::ScopedConnectionList stripable_connections;
std::shared_ptr<ARDOUR::Stripable> stripable[8];
void stripables_added ();
void stripable_property_change (PBD::PropertyChange const& what_changed, uint32_t which);
void switch_bank (uint32_t base);
void solo_changed (uint32_t n) { solo_mute_rec_changed(n); }
void mute_changed (uint32_t n) { solo_mute_rec_changed(n); }
void rec_changed (uint32_t n) { solo_mute_rec_changed(n); }
void solo_iso_changed (uint32_t n);
void solo_iso_led_bank ();
#ifdef MIXBUS
void master_send_changed (uint32_t n);
void master_send_led_bank ();
#endif
void solo_mute_rec_changed (uint32_t n);
/* special Stripable */
std::shared_ptr<ARDOUR::Stripable> master;
void port_registration_handler();
enum ConnectionState { InputConnected = 0x1, OutputConnected = 0x2 };
int connection_state;
bool connection_handler(std::weak_ptr<ARDOUR::Port>, std::string name1,
std::weak_ptr<ARDOUR::Port>, std::string name2,
bool yn);
PBD::ScopedConnection port_connection;
void connected();
/* GUI */
mutable LCXLGUI *gui;
void build_gui();
void stripable_selection_changed();
bool in_range_select;
};
} // namespace ArdourSurface
#endif /* __ardour_launch_control_h__ */