push2: expose page right/left buttons for scrolling; use right/left for banking;...
[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 <list>
25 #include <set>
26
27 #include <libusb.h>
28
29 #include <cairomm/refptr.h>
30
31 #define ABSTRACT_UI_EXPORTS
32 #include "pbd/abstract_ui.h"
33 #include "midi++/types.h"
34 #include "ardour/types.h"
35 #include "control_protocol/control_protocol.h"
36
37 #include "midi_byte_array.h"
38
39 namespace Cairo {
40         class ImageSurface;
41         class Context;
42 }
43
44 namespace Pango {
45         class Layout;
46 }
47
48 namespace MIDI {
49         class Parser;
50         class Port;
51 }
52
53 namespace ARDOUR {
54         class AsyncMIDIPort;
55         class Port;
56 }
57
58 namespace ArdourSurface {
59
60 struct Push2Request : public BaseUI::BaseRequestObject {
61 public:
62         Push2Request () {}
63         ~Push2Request () {}
64 };
65
66 class Push2 : public ARDOUR::ControlProtocol
67             , public AbstractUI<Push2Request>
68 {
69    public:
70         Push2 (ARDOUR::Session&);
71         ~Push2 ();
72
73         static bool probe ();
74         static void* request_factory (uint32_t);
75
76         int set_active (bool yn);
77         XMLNode& get_state();
78         int set_state (const XMLNode & node, int version);
79
80    private:
81         libusb_device_handle *handle;
82         uint8_t   frame_header[16];
83         uint16_t* device_frame_buffer;
84         int  device_buffer;
85         Cairo::RefPtr<Cairo::ImageSurface> frame_buffer;
86         sigc::connection vblank_connection;
87         sigc::connection periodic_connection;
88
89         enum ModifierState {
90                 None = 0,
91                 ModShift = 0x1,
92                 ModSelect = 0x2,
93         };
94
95         ModifierState modifier_state;
96
97         static const int cols;
98         static const int rows;
99         static const int pixels_per_row;
100
101         void do_request (Push2Request*);
102         int stop ();
103         int open ();
104         int close ();
105         bool redraw ();
106         int blit_to_device_frame_buffer ();
107         bool vblank ();
108
109         enum ButtonID {
110                 TapTempo,
111                 Metronome,
112                 Upper1, Upper2, Upper3, Upper4, Upper5, Upper6, Upper7, Upper8,
113                 Setup,
114                 User,
115                 Delete,
116                 AddDevice,
117                 Device,
118                 Mix,
119                 Undo,
120                 AddTrack,
121                 Browse,
122                 Clip,
123                 Mute,
124                 Solo,
125                 Stop,
126                 Lower1, Lower2, Lower3, Lower4, Lower5, Lower6, Lower7, Lower8,
127                 Master,
128                 Convert,
129                 DoubleLoop,
130                 Quantize,
131                 Duplicate,
132                 New,
133                 FixedLength,
134                 Automate,
135                 RecordEnable,
136                 Play,
137                 Fwd32ndT,
138                 Fwd32nd,
139                 Fwd16thT,
140                 Fwd16th,
141                 Fwd8thT,
142                 Fwd8th,
143                 Fwd4trT,
144                 Fwd4tr,
145                 Up,
146                 Right,
147                 Down,
148                 Left,
149                 Repeat,
150                 Accent,
151                 Scale,
152                 Layout,
153                 Note,
154                 Session,
155                 OctaveUp,
156                 PageRight,
157                 OctaveDown,
158                 PageLeft,
159                 Shift,
160                 Select
161         };
162
163         struct LED
164         {
165                 enum State {
166                         NoTransition,
167                         OneShot24th,
168                         OneShot16th,
169                         OneShot8th,
170                         OneShot4th,
171                         OneShot2th,
172                         Pulsing24th,
173                         Pulsing16th,
174                         Pulsing8th,
175                         Pulsing4th,
176                         Pulsing2th,
177                         Blinking24th,
178                         Blinking16th,
179                         Blinking8th,
180                         Blinking4th,
181                         Blinking2th
182                 };
183
184                 enum Colors {
185                         Black = 0,
186                         Red = 127,
187                         Green = 126,
188                         Blue = 125,
189                         DarkGray = 124,
190                         LightGray = 123,
191                         White = 122
192                 };
193
194                 LED (uint8_t e) : _extra (e), _color_index (0), _state (NoTransition) {}
195                 virtual ~LED() {}
196
197                 uint8_t extra () const { return _extra; }
198                 uint8_t color_index () const { return _color_index; }
199                 State   state () const { return _state; }
200
201                 void set_color (uint8_t color_index);
202                 void set_state (State state);
203
204                 virtual MidiByteArray state_msg() const = 0;
205
206              protected:
207                 uint8_t _extra;
208                 uint8_t _color_index;
209                 State   _state;
210         };
211
212         struct Pad : public LED {
213                 Pad (int xx, int yy, uint8_t ex)
214                         : LED (ex)
215                         , x (xx)
216                         , y (yy) {}
217
218                 MidiByteArray state_msg () const { return MidiByteArray (3, 0x90|_state, _extra, _color_index); }
219
220                 int coord () const { return (y * 8) + x; }
221                 int note_number() const { return extra(); }
222
223                 int x;
224                 int y;
225         };
226
227         struct Button : public LED {
228                 Button (ButtonID bb, uint8_t ex)
229                         : LED (ex)
230                         , id (bb)
231                         , press_method (&Push2::relax)
232                         , release_method (&Push2::relax)
233                         , long_press_method (&Push2::relax)
234                 {}
235
236                 Button (ButtonID bb, uint8_t ex, void (Push2::*press)())
237                         : LED (ex)
238                         , id (bb)
239                         , press_method (press)
240                         , release_method (&Push2::relax)
241                         , long_press_method (&Push2::relax)
242                 {}
243
244                 Button (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)())
245                         : LED (ex)
246                         , id (bb)
247                         , press_method (press)
248                         , release_method (release)
249                         , long_press_method (&Push2::relax)
250                 {}
251
252                 Button (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)(), void (Push2::*long_press)())
253                         : LED (ex)
254                         , id (bb)
255                         , press_method (press)
256                         , release_method (release)
257                         , long_press_method (long_press)
258                 {}
259
260                 MidiByteArray state_msg () const { return MidiByteArray (3, 0xb0|_state, _extra, _color_index); }
261                 int controller_number() const { return extra(); }
262
263                 ButtonID id;
264                 void (Push2::*press_method)();
265                 void (Push2::*release_method)();
266                 void (Push2::*long_press_method)();
267                 sigc::connection timeout_connection;
268         };
269
270         struct ColorButton : public Button {
271                 ColorButton (ButtonID bb, uint8_t ex)
272                         : Button (bb, ex) {}
273
274
275                 ColorButton (ButtonID bb, uint8_t ex, void (Push2::*press)())
276                         : Button (bb, ex, press) {}
277
278                 ColorButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)())
279                         : Button (bb, ex, press, release) {}
280
281                 ColorButton (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         struct WhiteButton : public Button {
286                 WhiteButton (ButtonID bb, uint8_t ex)
287                         : Button (bb, ex) {}
288
289                 WhiteButton (ButtonID bb, uint8_t ex, void (Push2::*press)())
290                         : Button (bb, ex, press) {}
291
292                 WhiteButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)())
293                         : Button (bb, ex, press, release) {}
294
295                 WhiteButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)(), void (Push2::*long_press)())
296                         : Button (bb, ex, press, release, long_press) {}
297         };
298
299         void relax () {}
300
301         /* map of Buttons by CC */
302         typedef std::map<int,Button*> CCButtonMap;
303         CCButtonMap cc_button_map;
304         /* map of Buttons by ButtonID */
305         typedef std::map<ButtonID,Button*> IDButtonMap;
306         IDButtonMap id_button_map;
307         std::set<ButtonID> buttons_down;
308         std::set<ButtonID> consumed;
309
310         bool button_long_press_timeout (ButtonID id);
311         void start_press_timeout (Button&, ButtonID);
312
313         void init_buttons (bool startup);
314         void init_touch_strip ();
315
316         /* map of Pads by note number */
317         typedef std::map<int,Pad*> NNPadMap;
318         NNPadMap nn_pad_map;
319         /* map of Pads by coordinate
320          *
321          * coord = row * 64 + column;
322          *
323          * rows start at top left
324          */
325         typedef std::map<int,Pad*> CoordPadMap;
326         CoordPadMap coord_pad_map;
327
328         void set_button_color (ButtonID, uint8_t color_index);
329         void set_button_state (ButtonID, LED::State);
330         void set_led_color (ButtonID, uint8_t color_index);
331         void set_led_state (ButtonID, LED::State);
332
333         void build_maps ();
334
335         MIDI::Port* _input_port;
336         MIDI::Port* _output_port;
337         boost::shared_ptr<ARDOUR::Port> _async_in;
338         boost::shared_ptr<ARDOUR::Port> _async_out;
339
340         void connect_to_parser ();
341         void handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t);
342         void handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes*);
343         void handle_midi_note_on_message (MIDI::Parser&, MIDI::EventTwoBytes*);
344         void handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes*);
345         void handle_midi_sysex (MIDI::Parser&, MIDI::byte *, size_t count);
346
347         void write (const MidiByteArray&);
348         bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port);
349         bool periodic ();
350
351         void thread_init ();
352
353         PBD::ScopedConnectionList session_connections;
354         void connect_session_signals ();
355         void notify_record_state_changed ();
356         void notify_transport_state_changed ();
357         void notify_loop_state_changed ();
358         void notify_parameter_changed (std::string);
359         void notify_solo_active_changed (bool);
360
361         /* Button methods */
362         void button_play ();
363         void button_recenable ();
364         void button_up ();
365         void button_down ();
366         void button_right ();
367         void button_left ();
368         void button_metronome ();
369         void button_repeat ();
370         void button_solo ();
371         void button_fixed_length ();
372         void button_new ();
373         void button_browse ();
374         void button_clip ();
375         void button_upper (uint32_t n);
376         void button_lower (uint32_t n);
377         void button_upper_1 () { button_upper (0); }
378         void button_upper_2 () { button_upper (1); }
379         void button_upper_3 () { button_upper (2); }
380         void button_upper_4 () { button_upper (3); }
381         void button_upper_5 () { button_upper (4); }
382         void button_upper_6 () { button_upper (5); }
383         void button_upper_7 () { button_upper (6); }
384         void button_upper_8 () { button_upper (7); }
385         void button_lower_1 () { button_lower (0); }
386         void button_lower_2 () { button_lower (1); }
387         void button_lower_3 () { button_lower (2); }
388         void button_lower_4 () { button_lower (3); }
389         void button_lower_5 () { button_lower (4); }
390         void button_lower_6 () { button_lower (5); }
391         void button_lower_7 () { button_lower (6); }
392         void button_lower_8 () { button_lower (7); }
393         void button_undo ();
394         void button_fwd32t ();
395         void button_fwd32 ();
396         void button_fwd16t ();
397         void button_fwd16 ();
398         void button_fwd8t ();
399         void button_fwd8 ();
400         void button_fwd4t ();
401         void button_fwd4 ();
402         void button_add_track ();
403         void button_stop ();
404         void button_shift_press ();
405         void button_shift_release ();
406         void button_shift_long_press ();
407         void button_select_press ();
408         void button_select_release ();
409         void button_select_long_press ();
410         void button_page_left ();
411         void button_page_right ();
412
413         void start_shift ();
414         void end_shift ();
415         void start_select ();
416         void end_select ();
417
418         /* encoders */
419
420         void strip_vpot (int, int);
421         void other_vpot (int, int);
422         void strip_vpot_touch (int, bool);
423         void other_vpot_touch (int, bool);
424
425         /* widgets */
426
427         Cairo::RefPtr<Cairo::Context> context;
428         Glib::RefPtr<Pango::Layout> tc_clock_layout;
429         Glib::RefPtr<Pango::Layout> bbt_clock_layout;
430         Glib::RefPtr<Pango::Layout> upper_layout[8];
431         Glib::RefPtr<Pango::Layout> mid_layout[8];
432         Glib::RefPtr<Pango::Layout> lower_layout[8];
433
434         /* stripables */
435
436         int32_t bank_start;
437         PBD::ScopedConnectionList stripable_connections;
438         boost::shared_ptr<ARDOUR::Stripable> stripable[8];
439         boost::shared_ptr<ARDOUR::Stripable> master;
440         boost::shared_ptr<ARDOUR::Stripable> monitor;
441
442         void solo_change (int);
443         void mute_change (int);
444         void stripable_property_change (PBD::PropertyChange const& what_changed, int which);
445
446         void switch_bank (uint32_t base);
447 };
448
449
450 } /* namespace */
451
452 #endif /* __ardour_push2_h__ */