push2: color palette management, and responding to 2 track properties in TrackMix...
[ardour.git] / libs / surfaces / push2 / push2.h
1 /*
2     Copyright (C) 2016 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifndef __ardour_push2_h__
20 #define __ardour_push2_h__
21
22 #include <vector>
23 #include <map>
24 #include <stack>
25 #include <list>
26 #include <set>
27
28 #include <libusb.h>
29
30 #include <cairomm/refptr.h>
31
32 #define ABSTRACT_UI_EXPORTS
33 #include "pbd/abstract_ui.h"
34
35 #include "midi++/types.h"
36
37 #include "ardour/types.h"
38
39 #include "control_protocol/control_protocol.h"
40 #include "control_protocol/types.h"
41
42 #include "midi_byte_array.h"
43 #include "mode.h"
44
45 namespace Cairo {
46         class ImageSurface;
47         class Context;
48 }
49
50 namespace Pango {
51         class Layout;
52 }
53
54 namespace MIDI {
55         class Parser;
56         class Port;
57 }
58
59 namespace ARDOUR {
60         class AsyncMIDIPort;
61         class Port;
62         class MidiBuffer;
63         class MidiTrack;
64 }
65
66 namespace ArdourSurface {
67
68 struct Push2Request : public BaseUI::BaseRequestObject {
69 public:
70         Push2Request () {}
71         ~Push2Request () {}
72 };
73
74 class P2GUI;
75 class Push2Menu;
76 class Push2Layout;
77
78 class Push2 : public ARDOUR::ControlProtocol
79             , public AbstractUI<Push2Request>
80 {
81   public:
82         enum ButtonID {
83                 TapTempo,
84                 Metronome,
85                 Upper1, Upper2, Upper3, Upper4, Upper5, Upper6, Upper7, Upper8,
86                 Setup,
87                 User,
88                 Delete,
89                 AddDevice,
90                 Device,
91                 Mix,
92                 Undo,
93                 AddTrack,
94                 Browse,
95                 Clip,
96                 Mute,
97                 Solo,
98                 Stop,
99                 Lower1, Lower2, Lower3, Lower4, Lower5, Lower6, Lower7, Lower8,
100                 Master,
101                 Convert,
102                 DoubleLoop,
103                 Quantize,
104                 Duplicate,
105                 New,
106                 FixedLength,
107                 Automate,
108                 RecordEnable,
109                 Play,
110                 Fwd32ndT,
111                 Fwd32nd,
112                 Fwd16thT,
113                 Fwd16th,
114                 Fwd8thT,
115                 Fwd8th,
116                 Fwd4trT,
117                 Fwd4tr,
118                 Up,
119                 Right,
120                 Down,
121                 Left,
122                 Repeat,
123                 Accent,
124                 Scale,
125                 Layout,
126                 Note,
127                 Session,
128                 OctaveUp,
129                 PageRight,
130                 OctaveDown,
131                 PageLeft,
132                 Shift,
133                 Select
134         };
135
136         struct LED
137         {
138                 enum State {
139                         NoTransition,
140                         OneShot24th,
141                         OneShot16th,
142                         OneShot8th,
143                         OneShot4th,
144                         OneShot2th,
145                         Pulsing24th,
146                         Pulsing16th,
147                         Pulsing8th,
148                         Pulsing4th,
149                         Pulsing2th,
150                         Blinking24th,
151                         Blinking16th,
152                         Blinking8th,
153                         Blinking4th,
154                         Blinking2th
155                 };
156
157                 enum Colors {
158                         Black = 0,
159                         Red = 127,
160                         Green = 126,
161                         Blue = 125,
162                         DarkGray = 124,
163                         LightGray = 123,
164                         White = 122
165                 };
166
167                 LED (uint8_t e) : _extra (e), _color_index (Black), _state (NoTransition) {}
168                 virtual ~LED() {}
169
170                 uint8_t extra () const { return _extra; }
171                 uint8_t color_index () const { return _color_index; }
172                 State   state () const { return _state; }
173
174                 void set_color (uint8_t color_index);
175                 void set_state (State state);
176
177                 virtual MidiByteArray state_msg() const = 0;
178
179              protected:
180                 uint8_t _extra;
181                 uint8_t _color_index;
182                 State   _state;
183         };
184
185         struct Pad : public LED {
186                 enum WhenPressed {
187                         Nothing,
188                         FlashOn,
189                         FlashOff,
190                 };
191
192                 Pad (int xx, int yy, uint8_t ex)
193                         : LED (ex)
194                         , x (xx)
195                         , y (yy)
196                         , do_when_pressed (FlashOn)
197                         , filtered (ex)
198                         , perma_color (LED::Black)
199                 {}
200
201                 MidiByteArray state_msg () const { return MidiByteArray (3, 0x90|_state, _extra, _color_index); }
202
203                 int coord () const { return (y * 8) + x; }
204                 int note_number() const { return extra(); }
205
206                 int x;
207                 int y;
208                 int do_when_pressed;
209                 int filtered;
210                 int perma_color;
211         };
212
213         struct Button : public LED {
214                 Button (ButtonID bb, uint8_t ex)
215                         : LED (ex)
216                         , id (bb)
217                         , press_method (&Push2::relax)
218                         , release_method (&Push2::relax)
219                         , long_press_method (&Push2::relax)
220                 {}
221
222                 Button (ButtonID bb, uint8_t ex, void (Push2::*press)())
223                         : LED (ex)
224                         , id (bb)
225                         , press_method (press)
226                         , release_method (&Push2::relax)
227                         , long_press_method (&Push2::relax)
228                 {}
229
230                 Button (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)())
231                         : LED (ex)
232                         , id (bb)
233                         , press_method (press)
234                         , release_method (release)
235                         , long_press_method (&Push2::relax)
236                 {}
237
238                 Button (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)(), void (Push2::*long_press)())
239                         : LED (ex)
240                         , id (bb)
241                         , press_method (press)
242                         , release_method (release)
243                         , long_press_method (long_press)
244                 {}
245
246                 MidiByteArray state_msg () const { return MidiByteArray (3, 0xb0|_state, _extra, _color_index); }
247                 int controller_number() const { return extra(); }
248
249                 ButtonID id;
250                 void (Push2::*press_method)();
251                 void (Push2::*release_method)();
252                 void (Push2::*long_press_method)();
253                 sigc::connection timeout_connection;
254         };
255
256         struct ColorButton : public Button {
257                 ColorButton (ButtonID bb, uint8_t ex)
258                         : Button (bb, ex) {}
259
260
261                 ColorButton (ButtonID bb, uint8_t ex, void (Push2::*press)())
262                         : Button (bb, ex, press) {}
263
264                 ColorButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)())
265                         : Button (bb, ex, press, release) {}
266
267                 ColorButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)(), void (Push2::*long_press)())
268                         : Button (bb, ex, press, release, long_press) {}
269         };
270
271         struct WhiteButton : public Button {
272                 WhiteButton (ButtonID bb, uint8_t ex)
273                         : Button (bb, ex) {}
274
275                 WhiteButton (ButtonID bb, uint8_t ex, void (Push2::*press)())
276                         : Button (bb, ex, press) {}
277
278                 WhiteButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)())
279                         : Button (bb, ex, press, release) {}
280
281                 WhiteButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)(), void (Push2::*long_press)())
282                         : Button (bb, ex, press, release, long_press) {}
283         };
284
285   public:
286         Push2 (ARDOUR::Session&);
287         ~Push2 ();
288
289         static bool probe ();
290         static void* request_factory (uint32_t);
291
292         std::list<boost::shared_ptr<ARDOUR::Bundle> > bundles ();
293
294         bool has_editor () const { return true; }
295         void* get_gui () const;
296         void  tear_down_gui ();
297
298         int set_active (bool yn);
299         XMLNode& get_state();
300         int set_state (const XMLNode & node, int version);
301
302         PBD::Signal0<void> ConnectionChange;
303
304         boost::shared_ptr<ARDOUR::Port> input_port();
305         boost::shared_ptr<ARDOUR::Port> output_port();
306
307         int pad_note (int row, int col) const;
308         PBD::Signal0<void> PadChange;
309
310         void set_pad_scale (int root, int octave, MusicalMode::Type mode, bool inkey);
311
312         MusicalMode::Type mode() const { return  _mode; }
313         int scale_root() const { return _scale_root; }
314         int root_octave() const { return _root_octave; }
315         bool in_key() const { return _in_key; }
316
317         Push2Layout* current_layout() const;
318
319         enum ModifierState {
320                 None = 0,
321                 ModShift = 0x1,
322                 ModSelect = 0x2,
323         };
324
325         ModifierState modifier_state() const { return _modifier_state; }
326
327         Button* button_by_id (ButtonID);
328
329         void write (const MidiByteArray&);
330
331         uint8_t get_color_index (uint32_t rgb);
332
333         static const int cols;
334         static const int rows;
335
336   private:
337         libusb_device_handle *handle;
338         uint8_t   frame_header[16];
339         uint16_t* device_frame_buffer;
340         int  device_buffer;
341         Cairo::RefPtr<Cairo::ImageSurface> frame_buffer;
342         sigc::connection vblank_connection;
343         sigc::connection periodic_connection;
344
345         ModifierState _modifier_state;
346
347         static const int pixels_per_row;
348
349         void do_request (Push2Request*);
350         int stop ();
351         int open ();
352         int close ();
353         bool redraw ();
354         int blit_to_device_frame_buffer ();
355         bool vblank ();
356
357         void relax () {}
358
359         /* map of Buttons by CC */
360         typedef std::map<int,Button*> CCButtonMap;
361         CCButtonMap cc_button_map;
362         /* map of Buttons by ButtonID */
363         typedef std::map<ButtonID,Button*> IDButtonMap;
364         IDButtonMap id_button_map;
365         std::set<ButtonID> buttons_down;
366         std::set<ButtonID> consumed;
367
368         bool button_long_press_timeout (ButtonID id);
369         void start_press_timeout (Button&, ButtonID);
370
371         void init_buttons (bool startup);
372         void init_touch_strip ();
373
374         /* map of Pads by note number */
375         typedef std::map<int,Pad*> NNPadMap;
376         NNPadMap nn_pad_map;
377
378         void set_button_color (ButtonID, uint8_t color_index);
379         void set_button_state (ButtonID, LED::State);
380         void set_led_color (ButtonID, uint8_t color_index);
381         void set_led_state (ButtonID, LED::State);
382
383         void build_maps ();
384
385         // Bundle to represent our input ports
386         boost::shared_ptr<ARDOUR::Bundle> _input_bundle;
387         // Bundle to represent our output ports
388         boost::shared_ptr<ARDOUR::Bundle> _output_bundle;
389
390         MIDI::Port* _input_port;
391         MIDI::Port* _output_port;
392         boost::shared_ptr<ARDOUR::Port> _async_in;
393         boost::shared_ptr<ARDOUR::Port> _async_out;
394
395         void connect_to_parser ();
396         void handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t);
397         void handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes*);
398         void handle_midi_note_on_message (MIDI::Parser&, MIDI::EventTwoBytes*);
399         void handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes*);
400         void handle_midi_sysex (MIDI::Parser&, MIDI::byte *, size_t count);
401
402         bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port);
403         bool periodic ();
404
405         void thread_init ();
406
407         PBD::ScopedConnectionList session_connections;
408         void connect_session_signals ();
409         void notify_record_state_changed ();
410         void notify_transport_state_changed ();
411         void notify_loop_state_changed ();
412         void notify_parameter_changed (std::string);
413         void notify_solo_active_changed (bool);
414
415         /* Button methods */
416         void button_play ();
417         void button_recenable ();
418         void button_up ();
419         void button_down ();
420         void button_right ();
421         void button_left ();
422         void button_metronome ();
423         void button_repeat ();
424         void button_solo ();
425         void button_fixed_length ();
426         void button_new ();
427         void button_browse ();
428         void button_clip ();
429         void button_undo ();
430         void button_fwd32t ();
431         void button_fwd32 ();
432         void button_fwd16t ();
433         void button_fwd16 ();
434         void button_fwd8t ();
435         void button_fwd8 ();
436         void button_fwd4t ();
437         void button_fwd4 ();
438         void button_add_track ();
439         void button_stop ();
440         void button_shift_press ();
441         void button_shift_release ();
442         void button_shift_long_press ();
443         void button_select_press ();
444         void button_select_release ();
445         void button_select_long_press ();
446         void button_page_left ();
447         void button_page_right ();
448         void button_octave_up ();
449         void button_octave_down ();
450         void button_layout_press ();
451         void button_scale_press ();
452         void button_mix_press ();
453
454         void button_upper (uint32_t n);
455         void button_lower (uint32_t n);
456
457         void button_upper_1 () { button_upper (0); }
458         void button_upper_2 () { button_upper (1); }
459         void button_upper_3 () { button_upper (2); }
460         void button_upper_4 () { button_upper (3); }
461         void button_upper_5 () { button_upper (4); }
462         void button_upper_6 () { button_upper (5); }
463         void button_upper_7 () { button_upper (6); }
464         void button_upper_8 () { button_upper (7); }
465         void button_lower_1 () { button_lower (0); }
466         void button_lower_2 () { button_lower (1); }
467         void button_lower_3 () { button_lower (2); }
468         void button_lower_4 () { button_lower (3); }
469         void button_lower_5 () { button_lower (4); }
470         void button_lower_6 () { button_lower (5); }
471         void button_lower_7 () { button_lower (6); }
472         void button_lower_8 () { button_lower (7); }
473
474         void start_shift ();
475         void end_shift ();
476
477         /* non-strip encoders */
478
479         void other_vpot (int, int);
480         void other_vpot_touch (int, bool);
481
482         /* special Stripables */
483
484         boost::shared_ptr<ARDOUR::Stripable> master;
485         boost::shared_ptr<ARDOUR::Stripable> monitor;
486
487         /* Cairo graphics context */
488
489         Cairo::RefPtr<Cairo::Context> context;
490
491         void splash ();
492         ARDOUR::microseconds_t splash_start;
493
494         /* Layouts */
495
496         mutable Glib::Threads::Mutex layout_lock;
497         Push2Layout* _current_layout;
498         Push2Layout* drawn_layout;
499         Push2Layout* mix_layout;
500         Push2Layout* scale_layout;
501         Push2Layout* track_mix_layout;
502
503         bool pad_filter (ARDOUR::MidiBuffer& in, ARDOUR::MidiBuffer& out) const;
504
505         boost::weak_ptr<ARDOUR::MidiTrack> current_pad_target;
506
507         PBD::ScopedConnection port_reg_connection;
508         void port_registration_handler ();
509
510         enum ConnectionState {
511                 InputConnected = 0x1,
512                 OutputConnected = 0x2
513         };
514
515         int connection_state;
516         bool connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn);
517         PBD::ScopedConnection port_connection;
518
519         /* GUI */
520
521         mutable P2GUI* gui;
522         void build_gui ();
523
524         /* pad mapping */
525
526         PBD::ScopedConnection selection_connection;
527         void stripable_selection_change (ARDOUR::StripableNotificationListPtr);
528
529         MusicalMode::Type _mode;
530         int _scale_root;
531         int _root_octave;
532         bool _in_key;
533
534         int octave_shift;
535
536         bool percussion;
537         void set_percussive_mode (bool);
538
539         /* color map */
540
541         typedef std::map<uint32_t,uint8_t> ColorMap;
542         typedef std::stack<uint8_t> ColorMapFreeList;
543         ColorMap color_map;
544         ColorMapFreeList color_map_free_list;
545         void build_color_map ();
546 };
547
548 } /* namespace */
549
550 #endif /* __ardour_push2_h__ */