Skeleton for NI Maschine2 Surface
[ardour.git] / libs / surfaces / maschine2 / m2_dev_mk2.cc
1 #include <math.h>
2
3 #include "pbd/compose.h"
4
5 #include "maschine2.h"
6 #include "m2controls.h"
7 #include "m2_dev_mk2.h"
8
9 #include <pangomm/fontdescription.h>
10
11 #include "images.h"
12
13 static size_t maschine_png_readoff = 0;
14
15 static Cairo::ErrorStatus maschine_png_read (unsigned char* d, unsigned int s) {
16         if (s + maschine_png_readoff > sizeof (maschine_png)) {
17                 return CAIRO_STATUS_READ_ERROR;
18         }
19         memcpy (d, &maschine_png[maschine_png_readoff], s);
20         maschine_png_readoff += s;
21         return CAIRO_STATUS_SUCCESS;
22 }
23
24 using namespace ArdourSurface;
25
26 Maschine2Mk2::Maschine2Mk2 () : M2Device ()
27 {
28         _surface = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, 512, 64);
29         clear (true);
30 }
31
32 void
33 Maschine2Mk2::clear (bool splash)
34 {
35         M2Device::clear (splash);
36
37         memset (&ctrl_in, 0, sizeof (ctrl_in));
38         memset (pad, 0, sizeof (pad));
39
40         ctrl80[0] = 0xff;
41         ctrl81[0] = 0xff;
42         ctrl82[0] = 0xff;
43
44         for (int d = 0; d < 2; ++d) {
45                 for (int l = 0; l < 8; ++l) {
46                         _img[d][l][0] = 0xff;
47                 }
48         }
49
50 #if 0
51         Cairo::RefPtr<Cairo::Context> c = Cairo::Context::create (_surface);
52         c->set_operator (Cairo::OPERATOR_CLEAR);
53         c->paint ();
54         return;
55 #endif
56
57         maschine_png_readoff = 0;
58         Cairo::RefPtr<Cairo::ImageSurface> sf = Cairo::ImageSurface::create_from_png_stream (sigc::ptr_fun (maschine_png_read));
59         Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create (_surface);
60         cr->set_source(sf, 0, 0);
61         cr->paint ();
62
63         Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create (cr);
64         Pango::FontDescription fd ("Sans Bold 18px");
65         layout->set_font_description (fd);
66         layout->set_alignment (Pango::ALIGN_CENTER);
67
68         int cx;
69         if (splash) {
70                 layout->set_text (string_compose ("%1\n%2", PROGRAM_NAME, VERSIONSTRING));
71                 cx = 384;
72         } else {
73                 cr->rectangle (326, 0, 186, 64);
74                 cr->set_source_rgb (0, 0, 0);
75                 cr->fill ();
76                 layout->set_text ("Keep Groovin'");
77                 cx = 421;
78         }
79
80         int tw, th;
81         layout->get_pixel_size (tw, th);
82         cr->move_to (cx - tw * 0.5, 32 - th * 0.5);
83         cr->set_source_rgb (1, 1, 1);
84         layout->show_in_cairo_context(cr);
85         //_surface->write_to_png ("/tmp/amaschine.png");
86 }
87
88 void
89 Maschine2Mk2::read (hid_device* handle, M2Contols* ctrl)
90 {
91         assert (ctrl);
92         while (true) {
93                 uint8_t buf[256];
94                 int res = hid_read (handle, buf, 256);
95                 if (res < 1) {
96                         return;
97                 }
98
99                 // TODO parse incrementally if chunked at 64
100
101                 if (res > 24 && buf[0] == 0x01) {
102                         memcpy (&ctrl_in, &buf[1], sizeof (ctrl_in));
103                         assign_controls (ctrl);
104                 }
105                 else if (res > 32 && buf[0] == 0x20) {
106                         for (unsigned int i = 0; i < 16; ++i) {
107                                 uint8_t v0 = buf[1 + 2 * i];
108                                 uint8_t v1 = buf[2 + 2 * i];
109                                 uint8_t p = (v1 & 0xf0) >> 4;
110                                 pad[p] = ((v1 & 0xf) << 8) | v0;
111                                 unsigned int pid = 15 - ((i & 0xc) + (3 - (i & 0x3)));
112                                 ctrl->pad (pid)->set_value (pad[p]);
113                         }
114                         // TODO read complete 65 byte msg, expect buf[33] == 0x00
115                 }
116         }
117 }
118
119 void
120 Maschine2Mk2::write (hid_device* handle, M2Contols* ctrl)
121 {
122         bump_blink ();
123         uint8_t buf[265];
124
125         //TODO double-buffer, send changes only if needed
126
127         /* 31 control buttons: 8 mst + 8 top + 8 pads + 7 mst
128          * 8-bit brightness
129          */
130         buf[0] = 0x82;
131         set_colors82 (ctrl, &buf[1]);
132         if (memcmp (ctrl82, buf, 32)) {
133                         hid_write (handle, buf, 32);
134                         memcpy (ctrl82, buf, 32);
135         }
136
137         /* 8 group rgb|rgb + 8 on/off transport buttons */
138         buf[0] = 0x81;
139         set_colors81 (ctrl, &buf[1]);
140         if (memcmp (ctrl81, buf, 57)) {
141                         hid_write (handle, buf, 57);
142                         memcpy (ctrl81, buf, 57);
143         }
144
145         /* 16 RGB grid pads */
146         buf[0] = 0x80;
147         set_colors80 (ctrl, &buf[1]);
148         if (memcmp (ctrl80, buf, 49)) {
149                         hid_write (handle, buf, 49);
150                         memcpy (ctrl80, buf, 49);
151         }
152
153         if (_splashcnt < _splashtime) {
154                 ++_splashcnt;
155         }
156         else if (! vblank () /* EMIT SIGNAL*/) {
157                 /* check clear/initial draw */
158                 if (_img[0][0][0] != 0xff) {
159                         return;
160                 }
161         }
162
163         /* display */
164         _surface->flush ();
165         const unsigned char* img = _surface->get_data ();
166         const int stride = _surface->get_stride ();
167         for (int d = 0; d < 2; ++d) {
168                 memset (buf, 0, 9);
169                 buf[0] = 0xe0 | d;
170                 for (int l = 0; l < 8; ++l) {
171                         buf[3] = 8 * l;
172                         buf[5] = 0x20;
173                         buf[7] = 0x08;
174
175                         int y0 = l * 8;
176                         int x0 = d * 256;
177
178                         for (int p = 0; p < 256; ++p) {
179                                 uint8_t v = 0;
180                                 const int y = y0 + p / 32;
181                                 for (int b = 0; b < 8; ++b) {
182                                         const int x = x0 + (p % 32) * 8 + b;
183                                         int off = y * stride + x * 4 /* ARGB32 */;
184                                         /* off + 0 == blue
185                                          * off + 1 == green
186                                          * off + 2 == red
187                                          * off + 3 == alpha
188                                          */
189                                         /* calculate lightness */
190                                         uint8_t l = std::max (img[off + 0], std::max (img[off + 1], img[off + 2]));
191                                         if (l > 0x7e) { // TODO: take alpha channel into account?!
192                                                 v |= 1 << (7 - b);
193                                         }
194                                 }
195                                 buf[9 + p] = v;
196                         }
197                         if (memcmp (_img[d][l], buf, 265)) {
198                                 hid_write (handle, buf, 265);
199                                 memcpy (_img[d][l], buf, 265);
200                         }
201                 }
202         }
203 }
204
205 void
206 Maschine2Mk2::assign_controls (M2Contols* ctrl) const
207 {
208         ctrl->button (M2Contols::BtnShift, M2Contols::ModNone)->set_active (ctrl_in.trs_shift ? true : false);
209         M2Contols::Modifier mod = ctrl->button (M2Contols::BtnShift, M2Contols::ModNone)->active () ? M2Contols::ModShift : M2Contols::ModNone;
210
211         bool change = false;
212 #define ASSIGN(BTN, VAR) \
213         change |= ctrl->button (M2Contols:: BTN, mod)->set_active (ctrl_in. VAR ? true : false)
214
215         ASSIGN (BtnRestart,   trs_restart);
216         ASSIGN (BtnStepLeft,  trs_left);
217         ASSIGN (BtnStepRight, trs_right);
218         ASSIGN (BtnGrid,      trs_grid);
219         ASSIGN (BtnPlay,      trs_play);
220         ASSIGN (BtnRec,       trs_rec);
221         ASSIGN (BtnErase,     trs_erase);
222
223         ASSIGN (BtnScene,     pads_scene);
224         ASSIGN (BtnPattern,   pads_pattern);
225         ASSIGN (BtnPadMode,   pads_mode);
226         ASSIGN (BtnNavigate,  pads_navigate);
227         ASSIGN (BtnDuplicate, pads_duplicate);
228         ASSIGN (BtnSelect,    pads_select);
229         ASSIGN (BtnSolo,      pads_solo);
230         ASSIGN (BtnMute,      pads_mute);
231
232         ASSIGN (BtnControl,  top_control);
233         ASSIGN (BtnStep,     top_step);
234         ASSIGN (BtnBrowse,   top_browse);
235         ASSIGN (BtnSampling, top_sampling);
236         ASSIGN (BtnSelLeft,  top_left);
237         ASSIGN (BtnSelRight, top_right);
238         ASSIGN (BtnAll,      top_all);
239         ASSIGN (BtnAuto,     top_auto);
240
241         ASSIGN (BtnVolume,     mst_volume);
242         ASSIGN (BtnSwing,      mst_swing);
243         ASSIGN (BtnTempo,      mst_tempo);
244         ASSIGN (BtnNavLeft,    mst_left);
245         ASSIGN (BtnNavRight,   mst_right);
246         ASSIGN (BtnEnter,      mst_enter);
247         ASSIGN (BtnNoteRepeat, mst_note_repeat);
248         ASSIGN (BtnWheel,      mst_wheel);
249
250         ASSIGN (BtnGroupA, groups_a);
251         ASSIGN (BtnGroupB, groups_b);
252         ASSIGN (BtnGroupC, groups_c);
253         ASSIGN (BtnGroupD, groups_d);
254         ASSIGN (BtnGroupE, groups_e);
255         ASSIGN (BtnGroupF, groups_f);
256         ASSIGN (BtnGroupG, groups_g);
257         ASSIGN (BtnGroupH, groups_h);
258
259         ASSIGN (BtnTop0, top_0);
260         ASSIGN (BtnTop1, top_1);
261         ASSIGN (BtnTop2, top_2);
262         ASSIGN (BtnTop3, top_3);
263         ASSIGN (BtnTop4, top_4);
264         ASSIGN (BtnTop5, top_5);
265         ASSIGN (BtnTop6, top_6);
266         ASSIGN (BtnTop7, top_7);
267 #undef ASSIGN
268
269         change |= ctrl->encoder (0)->set_value (ctrl_in.mst_wheel_pos);
270         for (int i = 0; i < 8; ++i) {
271                 change |= ctrl->encoder (1 + i)->set_value (ctrl_in.top_knobs[i]);
272         }
273
274         if (change && mod == M2Contols::ModShift) {
275                 M2ToggleHoldButton* btn = dynamic_cast<M2ToggleHoldButton*> (ctrl->button (M2Contols::BtnShift, M2Contols::ModNone));
276                 if (btn) {
277                         btn->unset_active_on_release ();
278                 }
279         }
280 }
281
282 #define LIGHT(BIT, BTN) \
283         b[BIT] = ctrl->button (M2Contols:: BTN, mod)->lightness (_blink_shade)
284
285 #define COLOR(BIT, BTN) \
286 { \
287         const uint32_t rgb = ctrl->button (M2Contols:: BTN, mod)->color (_blink_shade); \
288                 b[0 + BIT ] = (rgb >>  0) & 0xff; \
289                 b[1 + BIT ] = (rgb >>  8) & 0xff; \
290                 b[2 + BIT ] = (rgb >> 16) & 0xff; \
291                 b[3 + BIT ] = (rgb >>  0) & 0xff; \
292                 b[4 + BIT ] = (rgb >>  8) & 0xff; \
293                 b[5 + BIT ] = (rgb >> 16) & 0xff; \
294 }
295
296 void
297 Maschine2Mk2::set_colors80 (M2Contols* ctrl, uint8_t* b) const
298 {
299         if (!ctrl) {
300                 memset (b, 0, 48);
301                 return;
302         }
303         for (unsigned int i = 0; i < 16; ++i) {
304                 unsigned int pid = 15 - ((i & 0xc) + (3 - (i & 0x3)));
305                 ctrl->pad (pid)->color (b[i * 3], b[1 + i * 3], b[2 + i * 3]);
306         }
307 }
308
309 void
310 Maschine2Mk2::set_colors81 (M2Contols* ctrl, uint8_t* b) const
311 {
312         if (!ctrl) {
313                 memset (b, 0, 56);
314                 return;
315         }
316         M2Contols::Modifier mod = ctrl->button (M2Contols::BtnShift, M2Contols::ModNone)->active () ? M2Contols::ModShift : M2Contols::ModNone;
317
318         COLOR ( 0, BtnGroupA);
319         COLOR ( 6, BtnGroupB);
320         COLOR (12, BtnGroupC);
321         COLOR (18, BtnGroupD);
322         COLOR (24, BtnGroupE);
323         COLOR (30, BtnGroupF);
324         COLOR (36, BtnGroupG);
325         COLOR (42, BtnGroupH);
326
327         LIGHT (48, BtnRestart);
328         LIGHT (49, BtnStepLeft);
329         LIGHT (50, BtnStepRight);
330         LIGHT (51, BtnGrid);
331         LIGHT (52, BtnPlay);
332         LIGHT (53, BtnRec);
333         LIGHT (54, BtnErase);
334         LIGHT (55, BtnShift);
335 }
336
337 void
338 Maschine2Mk2::set_colors82 (M2Contols* ctrl, uint8_t* b) const
339 {
340         if (!ctrl) {
341                 memset (b, 0, 31);
342                 return;
343         }
344         M2Contols::Modifier mod = ctrl->button (M2Contols::BtnShift, M2Contols::ModNone)->active () ? M2Contols::ModShift : M2Contols::ModNone;
345
346         LIGHT ( 0, BtnControl);
347         LIGHT ( 1, BtnStep);
348         LIGHT ( 2, BtnBrowse);
349         LIGHT ( 3, BtnSampling);
350         LIGHT ( 4, BtnSelLeft);
351         LIGHT ( 5, BtnSelRight);
352         LIGHT ( 6, BtnAll);
353         LIGHT ( 7, BtnAuto);
354
355         LIGHT ( 8, BtnTop0);
356         LIGHT ( 9, BtnTop1);
357         LIGHT (10, BtnTop2);
358         LIGHT (11, BtnTop3);
359         LIGHT (12, BtnTop4);
360         LIGHT (13, BtnTop5);
361         LIGHT (14, BtnTop6);
362         LIGHT (15, BtnTop7);
363
364         LIGHT (16, BtnScene);
365         LIGHT (17, BtnPattern);
366         LIGHT (18, BtnPadMode);
367         LIGHT (19, BtnNavigate);
368         LIGHT (20, BtnDuplicate);
369         LIGHT (21, BtnSelect);
370         LIGHT (22, BtnSolo);
371         LIGHT (23, BtnMute);
372
373         LIGHT (24, BtnVolume);
374         LIGHT (25, BtnSwing);
375         LIGHT (26, BtnTempo);
376         LIGHT (27, BtnNavLeft);
377         LIGHT (28, BtnNavRight);
378         LIGHT (29, BtnEnter);
379         LIGHT (30, BtnNoteRepeat);
380 }