X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fsurfaces%2Fpush2%2Fpush2.h;h=38421a10bce8d923782ee271bc627a0ef45fc2cf;hb=1b830f2604f18149d88b3f2c34cb64660f46d7aa;hp=8f7c5e9abaf74272df351c02948301cadc15b499;hpb=a96b320e3dd186cc84b24226adc13b35526fe70d;p=ardour.git diff --git a/libs/surfaces/push2/push2.h b/libs/surfaces/push2/push2.h index 8f7c5e9aba..38421a10bc 100644 --- a/libs/surfaces/push2/push2.h +++ b/libs/surfaces/push2/push2.h @@ -21,25 +21,26 @@ #include #include +#include #include #include #include -#include - #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" +#include "canvas/colors.h" -namespace Cairo { - class ImageSurface; - class Context; -} +#include "midi_byte_array.h" namespace Pango { class Layout; @@ -53,6 +54,8 @@ namespace MIDI { namespace ARDOUR { class AsyncMIDIPort; class Port; + class MidiBuffer; + class MidiTrack; } namespace ArdourSurface { @@ -63,41 +66,15 @@ public: ~Push2Request () {} }; +class P2GUI; +class Push2Menu; +class Push2Layout; +class Push2Canvas; + class Push2 : public ARDOUR::ControlProtocol , public AbstractUI { - public: - Push2 (ARDOUR::Session&); - ~Push2 (); - - static bool probe (); - static void* request_factory (uint32_t); - - int set_active (bool yn); - XMLNode& get_state(); - int set_state (const XMLNode & node, int version); - - private: - libusb_device_handle *handle; - uint8_t frame_header[16]; - uint16_t* device_frame_buffer; - int device_buffer; - Cairo::RefPtr frame_buffer; - sigc::connection vblank_connection; - sigc::connection periodic_connection; - - static const int cols; - static const int rows; - static const int pixels_per_row; - - void do_request (Push2Request*); - int stop (); - int open (); - int close (); - bool redraw (); - int bitblt_to_device_frame_buffer (); - bool vblank (); - + public: enum ButtonID { TapTempo, Metronome, @@ -155,7 +132,7 @@ class Push2 : public ARDOUR::ControlProtocol struct LED { enum State { - Off, + NoTransition, OneShot24th, OneShot16th, OneShot8th, @@ -174,6 +151,7 @@ class Push2 : public ARDOUR::ControlProtocol }; enum Colors { + Black = 0, Red = 127, Green = 126, Blue = 125, @@ -182,7 +160,7 @@ class Push2 : public ARDOUR::ControlProtocol White = 122 }; - LED (uint8_t e) : _extra (e), _color_index (0), _state (Off) {} + LED (uint8_t e) : _extra (e), _color_index (Black), _state (NoTransition) {} virtual ~LED() {} uint8_t extra () const { return _extra; } @@ -201,18 +179,31 @@ class Push2 : public ARDOUR::ControlProtocol }; struct Pad : public LED { + enum WhenPressed { + Nothing, + FlashOn, + FlashOff, + }; + Pad (int xx, int yy, uint8_t ex) : LED (ex) , x (xx) - , y (yy) {} + , y (yy) + , do_when_pressed (FlashOn) + , filtered (ex) + , perma_color (LED::Black) + {} - MidiByteArray state_msg () const { return MidiByteArray (3, 0x90|_state, _extra, (_state == Off) ? 0 : _color_index); } + MidiByteArray state_msg () const { return MidiByteArray (3, 0x90|_state, _extra, _color_index); } int coord () const { return (y * 8) + x; } int note_number() const { return extra(); } int x; int y; + int do_when_pressed; + int filtered; + int perma_color; }; struct Button : public LED { @@ -221,6 +212,7 @@ class Push2 : public ARDOUR::ControlProtocol , id (bb) , press_method (&Push2::relax) , release_method (&Push2::relax) + , long_press_method (&Push2::relax) {} Button (ButtonID bb, uint8_t ex, void (Push2::*press)()) @@ -228,6 +220,7 @@ class Push2 : public ARDOUR::ControlProtocol , id (bb) , press_method (press) , release_method (&Push2::relax) + , long_press_method (&Push2::relax) {} Button (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)()) @@ -235,14 +228,25 @@ class Push2 : public ARDOUR::ControlProtocol , id (bb) , press_method (press) , release_method (release) + , long_press_method (&Push2::relax) {} - MidiByteArray state_msg () const { return MidiByteArray (3, 0xb0|_state, _extra, (_state == Off) ? 0 : _color_index); } + Button (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)(), void (Push2::*long_press)()) + : LED (ex) + , id (bb) + , press_method (press) + , release_method (release) + , long_press_method (long_press) + {} + + MidiByteArray state_msg () const { return MidiByteArray (3, 0xb0|_state, _extra, _color_index); } int controller_number() const { return extra(); } ButtonID id; void (Push2::*press_method)(); void (Push2::*release_method)(); + void (Push2::*long_press_method)(); + sigc::connection timeout_connection; }; struct ColorButton : public Button { @@ -255,6 +259,9 @@ class Push2 : public ARDOUR::ControlProtocol ColorButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)()) : Button (bb, ex, press, release) {} + + ColorButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)(), void (Push2::*long_press)()) + : Button (bb, ex, press, release, long_press) {} }; struct WhiteButton : public Button { @@ -266,8 +273,117 @@ class Push2 : public ARDOUR::ControlProtocol WhiteButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)()) : Button (bb, ex, press, release) {} + + WhiteButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)(), void (Push2::*long_press)()) + : Button (bb, ex, press, release, long_press) {} + }; + + enum ColorName { + DarkBackground, + LightBackground, + + ParameterName, + StripableName, + ClockText, + + KnobArcBackground, + KnobArcStart, + KnobArcEnd, + + KnobLine, + KnobLineShadow, + + KnobForeground, + KnobBackground, + KnobShadow, + KnobBorder, + }; + + enum PressureMode { + AfterTouch, + PolyPressure, + }; + + public: + Push2 (ARDOUR::Session&); + ~Push2 (); + + static bool probe (); + static void* request_factory (uint32_t); + + std::list > bundles (); + + bool has_editor () const { return true; } + void* get_gui () const; + void tear_down_gui (); + + int set_active (bool yn); + XMLNode& get_state(); + int set_state (const XMLNode & node, int version); + + PBD::Signal0 ConnectionChange; + + boost::shared_ptr input_port(); + boost::shared_ptr output_port(); + + int pad_note (int row, int col) const; + PBD::Signal0 PadChange; + + void update_selection_color (); + + void set_pad_scale (int root, int octave, MusicalMode::Type mode, bool inkey); + PBD::Signal0 ScaleChange; + + MusicalMode::Type mode() const { return _mode; } + int scale_root() const { return _scale_root; } + int root_octave() const { return _root_octave; } + bool in_key() const { return _in_key; } + + Push2Layout* current_layout() const; + void use_previous_layout (); + + Push2Canvas* canvas() const { return _canvas; } + + enum ModifierState { + None = 0, + ModShift = 0x1, + ModSelect = 0x2, }; + ModifierState modifier_state() const { return _modifier_state; } + + Button* button_by_id (ButtonID); + static std::string button_name_by_id (ButtonID); + + void strip_buttons_off (); + + void write (const MidiByteArray&); + + uint8_t get_color_index (ArdourCanvas::Color rgba); + ArdourCanvas::Color get_color (ColorName); + + PressureMode pressure_mode () const { return _pressure_mode; } + void set_pressure_mode (PressureMode); + PBD::Signal1 PressureModeChange; + + libusb_device_handle* usb_handle() const { return handle; } + + private: + libusb_device_handle *handle; + bool in_use; + ModifierState _modifier_state; + + void do_request (Push2Request*); + + int begin_using_device (); + int stop_using_device (); + int device_acquire (); + void device_release (); + int ports_acquire (); + void ports_release (); + void run_event_loop (); + void stop_event_loop (); + void relax () {} /* map of Buttons by CC */ @@ -276,18 +392,25 @@ class Push2 : public ARDOUR::ControlProtocol /* map of Buttons by ButtonID */ typedef std::map IDButtonMap; IDButtonMap id_button_map; + std::set buttons_down; + std::set consumed; + + bool button_long_press_timeout (ButtonID id); + void start_press_timeout (Button&, ButtonID); + + void init_buttons (bool startup); + void init_touch_strip (); - /* map of Pads by note number */ + /* map of Pads by note number (the "fixed" note number sent by the + * hardware, not the note number generated if the pad is touched) + */ typedef std::map NNPadMap; NNPadMap nn_pad_map; - /* map of Pads by coordinate - * - * coord = row * 64 + column; - * - * rows start at top left + + /* map of Pads by note number they generate (their "filtered" value) */ - typedef std::map CoordPadMap; - CoordPadMap coord_pad_map; + typedef std::multimap FNPadMap; + FNPadMap fn_pad_map; void set_button_color (ButtonID, uint8_t color_index); void set_button_state (ButtonID, LED::State); @@ -296,6 +419,11 @@ class Push2 : public ARDOUR::ControlProtocol void build_maps (); + // Bundle to represent our input ports + boost::shared_ptr _input_bundle; + // Bundle to represent our output ports + boost::shared_ptr _output_bundle; + MIDI::Port* _input_port; MIDI::Port* _output_port; boost::shared_ptr _async_in; @@ -308,9 +436,7 @@ class Push2 : public ARDOUR::ControlProtocol void handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes*); void handle_midi_sysex (MIDI::Parser&, MIDI::byte *, size_t count); - void write (const MidiByteArray&); bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port); - bool periodic (); void thread_init (); @@ -331,17 +457,155 @@ class Push2 : public ARDOUR::ControlProtocol void button_left (); void button_metronome (); void button_repeat (); + void button_mute (); + void button_solo (); + void button_solo_long_press (); + void button_fixed_length (); + void button_new (); + void button_browse (); + void button_clip (); + void button_undo (); + void button_fwd32t (); + void button_fwd32 (); + void button_fwd16t (); + void button_fwd16 (); + void button_fwd8t (); + void button_fwd8 (); + void button_fwd4t (); + void button_fwd4 (); + void button_add_track (); + void button_stop (); + void button_master (); + void button_quantize (); + void button_duplicate (); + void button_shift_press (); + void button_shift_release (); + void button_shift_long_press (); + void button_select_press (); + void button_select_release (); + void button_select_long_press (); + void button_page_left (); + void button_page_right (); + void button_octave_up (); + void button_octave_down (); + void button_layout_press (); + void button_scale_press (); + void button_mix_press (); + + void button_upper (uint32_t n); + void button_lower (uint32_t n); + + void button_upper_1 () { button_upper (0); } + void button_upper_2 () { button_upper (1); } + void button_upper_3 () { button_upper (2); } + void button_upper_4 () { button_upper (3); } + void button_upper_5 () { button_upper (4); } + void button_upper_6 () { button_upper (5); } + void button_upper_7 () { button_upper (6); } + void button_upper_8 () { button_upper (7); } + void button_lower_1 () { button_lower (0); } + void button_lower_2 () { button_lower (1); } + void button_lower_3 () { button_lower (2); } + void button_lower_4 () { button_lower (3); } + void button_lower_5 () { button_lower (4); } + void button_lower_6 () { button_lower (5); } + void button_lower_7 () { button_lower (6); } + void button_lower_8 () { button_lower (7); } + + void start_shift (); + void end_shift (); + + /* non-strip encoders */ + + void other_vpot (int, int); + void other_vpot_touch (int, bool); + + /* special Stripables */ + + boost::shared_ptr master; + boost::shared_ptr monitor; - /* widgets */ + sigc::connection vblank_connection; + bool vblank (); - Cairo::RefPtr context; - Glib::RefPtr tc_clock_layout; - Glib::RefPtr bbt_clock_layout; - Glib::RefPtr upper_layout[8]; - Glib::RefPtr mid_layout[8]; - Glib::RefPtr lower_layout[8]; -}; + void splash (); + ARDOUR::microseconds_t splash_start; + + /* the canvas */ + + Push2Canvas* _canvas; + + /* Layouts */ + + mutable Glib::Threads::Mutex layout_lock; + Push2Layout* _current_layout; + Push2Layout* _previous_layout; + Push2Layout* mix_layout; + Push2Layout* scale_layout; + Push2Layout* track_mix_layout; + Push2Layout* splash_layout; + void set_current_layout (Push2Layout*); + + bool pad_filter (ARDOUR::MidiBuffer& in, ARDOUR::MidiBuffer& out) const; + + boost::weak_ptr current_pad_target; + + PBD::ScopedConnection port_reg_connection; + void port_registration_handler (); + + enum ConnectionState { + InputConnected = 0x1, + OutputConnected = 0x2 + }; + + int connection_state; + bool connection_handler (boost::weak_ptr, std::string name1, boost::weak_ptr, std::string name2, bool yn); + PBD::ScopedConnection port_connection; + void connected (); + /* GUI */ + + mutable P2GUI* gui; + void build_gui (); + + /* pad mapping */ + + PBD::ScopedConnection selection_connection; + void stripable_selection_change (ARDOUR::StripableNotificationListPtr); + + MusicalMode::Type _mode; + int _scale_root; + int _root_octave; + bool _in_key; + + int octave_shift; + + bool percussion; + void set_percussive_mode (bool); + + /* color map (device side) */ + + typedef std::map ColorMap; + typedef std::stack ColorMapFreeList; + ColorMap color_map; + ColorMapFreeList color_map_free_list; + void build_color_map (); + + /* our own colors */ + + typedef std::map Colors; + Colors colors; + void fill_color_table (); + void reset_pad_colors (); + + PressureMode _pressure_mode; + void request_pressure_mode (); + + uint8_t selection_color; + uint8_t contrast_color; + + bool in_range_select; +}; } /* namespace */