move mode/scale/key definitions out of push2 code and into libardour; Aeolian is...
[ardour.git] / libs / surfaces / push2 / push2.h
index 1b8c948986e4debe8149a7961dea8e7810b27172..2d4f17417ef5f0f96b4ac8a8d40494121d00d487 100644 (file)
 
 #include <vector>
 #include <map>
+#include <stack>
 #include <list>
 #include <set>
 
 #include <libusb.h>
 
-#include <cairomm/refptr.h>
-#include <glibmm/threads.h>
-
 #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 "canvas/colors.h"
 
 #include "midi_byte_array.h"
 
-namespace Cairo {
-       class ImageSurface;
+namespace Pango {
+       class Layout;
 }
 
 namespace MIDI {
@@ -49,6 +54,8 @@ namespace MIDI {
 namespace ARDOUR {
        class AsyncMIDIPort;
        class Port;
+       class MidiBuffer;
+       class MidiTrack;
 }
 
 namespace ArdourSurface {
@@ -59,42 +66,73 @@ 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);
-
-   private:
-       libusb_device_handle *handle;
-       Glib::Threads::Mutex fb_lock;
-       uint8_t   frame_header[16];
-       uint16_t* device_frame_buffer[2];
-       int  device_buffer;
-       Cairo::RefPtr<Cairo::ImageSurface> frame_buffer;
-       sigc::connection vblank_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 ();
-       int render ();
-       bool vblank ();
+  public:
+       enum ButtonID {
+               TapTempo,
+               Metronome,
+               Upper1, Upper2, Upper3, Upper4, Upper5, Upper6, Upper7, Upper8,
+               Setup,
+               User,
+               Delete,
+               AddDevice,
+               Device,
+               Mix,
+               Undo,
+               AddTrack,
+               Browse,
+               Clip,
+               Mute,
+               Solo,
+               Stop,
+               Lower1, Lower2, Lower3, Lower4, Lower5, Lower6, Lower7, Lower8,
+               Master,
+               Convert,
+               DoubleLoop,
+               Quantize,
+               Duplicate,
+               New,
+               FixedLength,
+               Automate,
+               RecordEnable,
+               Play,
+               Fwd32ndT,
+               Fwd32nd,
+               Fwd16thT,
+               Fwd16th,
+               Fwd8thT,
+               Fwd8th,
+               Fwd4trT,
+               Fwd4tr,
+               Up,
+               Right,
+               Down,
+               Left,
+               Repeat,
+               Accent,
+               Scale,
+               Layout,
+               Note,
+               Session,
+               OctaveUp,
+               PageRight,
+               OctaveDown,
+               PageLeft,
+               Shift,
+               Select
+       };
 
        struct LED
        {
                enum State {
-                       Off,
+                       NoTransition,
                        OneShot24th,
                        OneShot16th,
                        OneShot8th,
@@ -112,43 +150,456 @@ class Push2 : public ARDOUR::ControlProtocol
                        Blinking2th
                };
 
-               enum Type {
-                       Pad,
-                       ColorButton,
-                       WhiteButton,
-                       TouchStrip,
+               enum Colors {
+                       Black = 0,
+                       Red = 127,
+                       Green = 126,
+                       Blue = 125,
+                       DarkGray = 124,
+                       LightGray = 123,
+                       White = 122
                };
 
+               LED (uint8_t e) : _extra (e), _color_index (Black), _state (NoTransition) {}
+               virtual ~LED() {}
 
+               uint8_t extra () const { return _extra; }
+               uint8_t color_index () const { return _color_index; }
+               State   state () const { return _state; }
 
-               uint8_t id;
-               Type    type;
-               uint8_t extra;
-               uint8_t color_index;
-               uint8_t state;
+               void set_color (uint8_t color_index);
+               void set_state (State state);
 
-               LED (uint8_t i, Type t, uint8_t e) : id (i), type (t), extra (e), color_index (0), state (Off) {}
-               LED () : id (0), type (Pad), extra (0), color_index (0), state (Off) {}
+               virtual MidiByteArray state_msg() const = 0;
 
-               MidiByteArray update ();
+            protected:
+               uint8_t _extra;
+               uint8_t _color_index;
+               State   _state;
+       };
 
-               void set_color (uint8_t color_index);
-               void set_state (State state);
+       struct Pad : public LED {
+               enum WhenPressed {
+                       Nothing,
+                       FlashOn,
+                       FlashOff,
+               };
+
+               Pad (int xx, int yy, uint8_t ex)
+                       : LED (ex)
+                       , x (xx)
+                       , y (yy)
+                       , do_when_pressed (FlashOn)
+                       , filtered (ex)
+                       , perma_color (LED::Black)
+               {}
+
+               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;
        };
 
-       std::map<int,LED> leds;
-       void set_led_color (uint32_t id, uint8_t color_index);
-       void set_led_state (uint32_t id, LED::State);
-       void build_led_map ();
+       struct Button : public LED {
+               Button (ButtonID bb, uint8_t ex)
+                       : LED (ex)
+                       , id (bb)
+                       , press_method (&Push2::relax)
+                       , release_method (&Push2::relax)
+                       , long_press_method (&Push2::relax)
+               {}
+
+               Button (ButtonID bb, uint8_t ex, void (Push2::*press)())
+                       : LED (ex)
+                       , 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)())
+                       : LED (ex)
+                       , 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); }
+               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;
+       };
 
-       MIDI::Port* _input_port[2];
-       MIDI::Port* _output_port[2];
-       boost::shared_ptr<ARDOUR::Port> _async_in[2];
-       boost::shared_ptr<ARDOUR::Port> _async_out[2];
+       struct ColorButton : public Button {
+               ColorButton (ButtonID bb, uint8_t ex)
+                       : Button (bb, ex) {}
 
-       void write (int port, const MidiByteArray&);
-};
 
+               ColorButton (ButtonID bb, uint8_t ex, void (Push2::*press)())
+                       : Button (bb, ex, press) {}
+
+               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 {
+               WhiteButton (ButtonID bb, uint8_t ex)
+                       : Button (bb, ex) {}
+
+               WhiteButton (ButtonID bb, uint8_t ex, void (Push2::*press)())
+                       : Button (bb, ex, press) {}
+
+               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 */
+       typedef std::map<int,Button*> CCButtonMap;
+       CCButtonMap cc_button_map;
+       /* 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 (bool startup);
+       void init_touch_strip ();
+
+       /* 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 note number they generate (their "filtered" value)
+        */
+       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);
+       void set_led_color (ButtonID, uint8_t color_index);
+       void set_led_state (ButtonID, LED::State);
+
+       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;
+       boost::shared_ptr<ARDOUR::Port> _async_out;
+
+       void connect_to_parser ();
+       void handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t);
+       void handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes*);
+       void handle_midi_note_on_message (MIDI::Parser&, MIDI::EventTwoBytes*);
+       void handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes*);
+       void handle_midi_sysex (MIDI::Parser&, MIDI::byte *, size_t count);
+
+       bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port);
+
+       sigc::connection periodic_connection;
+       bool periodic ();
+
+       void thread_init ();
+
+       PBD::ScopedConnectionList session_connections;
+       void connect_session_signals ();
+       void notify_record_state_changed ();
+       void notify_transport_state_changed ();
+       void notify_loop_state_changed ();
+       void notify_parameter_changed (std::string);
+       void notify_solo_active_changed (bool);
+
+       /* Button methods */
+       void button_play ();
+       void button_recenable ();
+       void button_up ();
+       void button_down ();
+       void button_right ();
+       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<ARDOUR::Stripable> master;
+       boost::shared_ptr<ARDOUR::Stripable> monitor;
+
+       sigc::connection vblank_connection;
+       bool vblank ();
+
+       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 */