update pad colors when selected track colors chane
[ardour.git] / libs / surfaces / push2 / push2.h
index 6c5b38fd9fdd75ff0c5e451f8ea90fbd9b356496..30422775d45751e18908656ae4bd1794421d5080 100644 (file)
 
 #include <vector>
 #include <map>
+#include <stack>
 #include <list>
 #include <set>
 
 #include <libusb.h>
 
-#include <cairomm/refptr.h>
-
 #define ABSTRACT_UI_EXPORTS
 #include "pbd/abstract_ui.h"
+
 #include "midi++/types.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"
+#include "mode.h"
 
 namespace Pango {
        class Layout;
@@ -53,6 +54,8 @@ namespace MIDI {
 namespace ARDOUR {
        class AsyncMIDIPort;
        class Port;
+       class MidiBuffer;
+       class MidiTrack;
 }
 
 namespace ArdourSurface {
@@ -63,48 +66,15 @@ public:
        ~Push2Request () {}
 };
 
+class P2GUI;
+class Push2Menu;
+class Push2Layout;
+class Push2Canvas;
+
 class Push2 : public ARDOUR::ControlProtocol
             , public AbstractUI<Push2Request>
 {
-   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<Cairo::ImageSurface> frame_buffer;
-       sigc::connection vblank_connection;
-       sigc::connection periodic_connection;
-
-       enum ModifierState {
-               None = 0,
-               ModShift = 0x1,
-       };
-
-       ModifierState modifier_state;
-
-       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,
@@ -190,7 +160,7 @@ class Push2 : public ARDOUR::ControlProtocol
                        White = 122
                };
 
-               LED (uint8_t e) : _extra (e), _color_index (0), _state (NoTransition) {}
+               LED (uint8_t e) : _extra (e), _color_index (Black), _state (NoTransition) {}
                virtual ~LED() {}
 
                uint8_t extra () const { return _extra; }
@@ -209,10 +179,20 @@ 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, _color_index); }
 
@@ -221,6 +201,9 @@ class Push2 : public ARDOUR::ControlProtocol
 
                int x;
                int y;
+               int do_when_pressed;
+               int filtered;
+               int perma_color;
        };
 
        struct Button : public LED {
@@ -229,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)())
@@ -236,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)())
@@ -243,6 +228,15 @@ class Push2 : public ARDOUR::ControlProtocol
                        , id (bb)
                        , press_method (press)
                        , release_method (release)
+                       , long_press_method (&Push2::relax)
+               {}
+
+               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); }
@@ -251,6 +245,8 @@ class Push2 : public ARDOUR::ControlProtocol
                ButtonID id;
                void (Push2::*press_method)();
                void (Push2::*release_method)();
+               void (Push2::*long_press_method)();
+               sigc::connection timeout_connection;
        };
 
        struct ColorButton : public Button {
@@ -263,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 {
@@ -274,8 +273,110 @@ 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<boost::shared_ptr<ARDOUR::Bundle> > 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<void> ConnectionChange;
+
+       boost::shared_ptr<ARDOUR::Port> input_port();
+       boost::shared_ptr<ARDOUR::Port> output_port();
+
+       int pad_note (int row, int col) const;
+       PBD::Signal0<void> PadChange;
+
+       void update_selection_color ();
+
+       void set_pad_scale (int root, int octave, MusicalMode::Type mode, bool inkey);
+       PBD::Signal0<void> 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<void,PressureMode> PressureModeChange;
+
+       libusb_device_handle* usb_handle() const { return handle; }
+
+  private:
+       libusb_device_handle *handle;
+       ModifierState _modifier_state;
+
+       void do_request (Push2Request*);
+       int stop ();
+       int open ();
+       int close ();
+
        void relax () {}
 
        /* map of Buttons by CC */
@@ -284,20 +385,25 @@ class Push2 : public ARDOUR::ControlProtocol
        /* map of Buttons by ButtonID */
        typedef std::map<ButtonID,Button*> IDButtonMap;
        IDButtonMap id_button_map;
+       std::set<ButtonID> buttons_down;
+       std::set<ButtonID> consumed;
+
+       bool button_long_press_timeout (ButtonID id);
+       void start_press_timeout (Button&, ButtonID);
 
-       void init_buttons ();
+       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<int,Pad*> 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<int,Pad*> CoordPadMap;
-       CoordPadMap coord_pad_map;
+       typedef std::multimap<int,Pad*> FNPadMap;
+       FNPadMap fn_pad_map;
 
        void set_button_color (ButtonID, uint8_t color_index);
        void set_button_state (ButtonID, LED::State);
@@ -306,6 +412,11 @@ class Push2 : public ARDOUR::ControlProtocol
 
        void build_maps ();
 
+       // Bundle to represent our input ports
+       boost::shared_ptr<ARDOUR::Bundle> _input_bundle;
+       // Bundle to represent our output ports
+       boost::shared_ptr<ARDOUR::Bundle> _output_bundle;
+
        MIDI::Port* _input_port;
        MIDI::Port* _output_port;
        boost::shared_ptr<ARDOUR::Port> _async_in;
@@ -318,8 +429,9 @@ 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);
+
+       sigc::connection periodic_connection;
        bool periodic ();
 
        void thread_init ();
@@ -341,15 +453,44 @@ 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_shift_press ();
-       void button_shift_release ();
        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); }
@@ -366,46 +507,99 @@ class Push2 : public ARDOUR::ControlProtocol
        void button_lower_6 () { button_lower (5); }
        void button_lower_7 () { button_lower (6); }
        void button_lower_8 () { button_lower (7); }
-       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 ();
 
-       /* encoders */
+       void start_shift ();
+       void end_shift ();
+
+       /* non-strip encoders */
 
-       void strip_vpot (int, int);
        void other_vpot (int, int);
-       void strip_vpot_touch (int, bool);
        void other_vpot_touch (int, bool);
 
-       /* widgets */
+       /* special Stripables */
 
-       Cairo::RefPtr<Cairo::Context> context;
-       Glib::RefPtr<Pango::Layout> tc_clock_layout;
-       Glib::RefPtr<Pango::Layout> bbt_clock_layout;
-       Glib::RefPtr<Pango::Layout> upper_layout[8];
-       Glib::RefPtr<Pango::Layout> mid_layout[8];
-       Glib::RefPtr<Pango::Layout> lower_layout[8];
-
-       /* stripables */
-
-       int32_t bank_start;
-       PBD::ScopedConnectionList stripable_connections;
-       boost::shared_ptr<ARDOUR::Stripable> stripable[8];
        boost::shared_ptr<ARDOUR::Stripable> master;
        boost::shared_ptr<ARDOUR::Stripable> monitor;
 
-       void solo_change (int);
-       void mute_change (int);
+       sigc::connection vblank_connection;
+       bool vblank ();
 
-       void switch_bank (uint32_t base);
-};
+       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<ARDOUR::MidiTrack> 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<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, 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<ArdourCanvas::Color,uint8_t> ColorMap;
+       typedef std::stack<uint8_t> ColorMapFreeList;
+       ColorMap color_map;
+       ColorMapFreeList color_map_free_list;
+       void build_color_map ();
+
+       /* our own colors */
+
+       typedef std::map<ColorName,ArdourCanvas::Color> 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;
+};
 
 } /* namespace */