3 #include "pbd/compose.h"
6 #include "m2controls.h"
7 #include "m2_dev_mk2.h"
9 #include <pangomm/fontdescription.h>
13 static size_t maschine_png_readoff = 0;
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;
19 memcpy (d, &maschine_png[maschine_png_readoff], s);
20 maschine_png_readoff += s;
21 return CAIRO_STATUS_SUCCESS;
24 using namespace ArdourSurface;
26 Maschine2Mk2::Maschine2Mk2 () : M2Device ()
28 _surface = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, 512, 64);
33 Maschine2Mk2::clear (bool splash)
35 M2Device::clear (splash);
37 memset (&ctrl_in, 0, sizeof (ctrl_in));
38 memset (pad, 0, sizeof (pad));
44 for (int d = 0; d < 2; ++d) {
45 for (int l = 0; l < 8; ++l) {
51 Cairo::RefPtr<Cairo::Context> c = Cairo::Context::create (_surface);
52 c->set_operator (Cairo::OPERATOR_CLEAR);
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);
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);
70 layout->set_text (string_compose ("%1\n%2", PROGRAM_NAME, VERSIONSTRING));
73 cr->rectangle (326, 0, 186, 64);
74 cr->set_source_rgb (0, 0, 0);
76 layout->set_text ("Keep Groovin'");
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");
89 Maschine2Mk2::read (hid_device* handle, M2Contols* ctrl)
94 int res = hid_read (handle, buf, 256);
99 // TODO parse incrementally if chunked at 64
101 if (res > 24 && buf[0] == 0x01) {
102 memcpy (&ctrl_in, &buf[1], sizeof (ctrl_in));
103 assign_controls (ctrl);
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]);
114 // TODO read complete 65 byte msg, expect buf[33] == 0x00
120 Maschine2Mk2::write (hid_device* handle, M2Contols* ctrl)
125 //TODO double-buffer, send changes only if needed
127 /* 31 control buttons: 8 mst + 8 top + 8 pads + 7 mst
131 set_colors82 (ctrl, &buf[1]);
132 if (memcmp (ctrl82, buf, 32)) {
133 hid_write (handle, buf, 32);
134 memcpy (ctrl82, buf, 32);
137 /* 8 group rgb|rgb + 8 on/off transport buttons */
139 set_colors81 (ctrl, &buf[1]);
140 if (memcmp (ctrl81, buf, 57)) {
141 hid_write (handle, buf, 57);
142 memcpy (ctrl81, buf, 57);
145 /* 16 RGB grid pads */
147 set_colors80 (ctrl, &buf[1]);
148 if (memcmp (ctrl80, buf, 49)) {
149 hid_write (handle, buf, 49);
150 memcpy (ctrl80, buf, 49);
153 if (_splashcnt < _splashtime) {
156 else if (! vblank () /* EMIT SIGNAL*/) {
157 /* check clear/initial draw */
158 if (_img[0][0][0] != 0xff) {
165 const unsigned char* img = _surface->get_data ();
166 const int stride = _surface->get_stride ();
167 for (int d = 0; d < 2; ++d) {
170 for (int l = 0; l < 8; ++l) {
178 for (int p = 0; p < 256; ++p) {
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 */;
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?!
197 if (memcmp (_img[d][l], buf, 265)) {
198 hid_write (handle, buf, 265);
199 memcpy (_img[d][l], buf, 265);
206 Maschine2Mk2::assign_controls (M2Contols* ctrl) const
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;
212 #define ASSIGN(BTN, VAR) \
213 change |= ctrl->button (M2Contols:: BTN, mod)->set_active (ctrl_in. VAR ? true : false)
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);
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);
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);
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);
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);
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);
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]);
274 if (change && mod == M2Contols::ModShift) {
275 M2ToggleHoldButton* btn = dynamic_cast<M2ToggleHoldButton*> (ctrl->button (M2Contols::BtnShift, M2Contols::ModNone));
277 btn->unset_active_on_release ();
282 #define LIGHT(BIT, BTN) \
283 b[BIT] = ctrl->button (M2Contols:: BTN, mod)->lightness (_blink_shade)
285 #define COLOR(BIT, BTN) \
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; \
297 Maschine2Mk2::set_colors80 (M2Contols* ctrl, uint8_t* b) const
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]);
310 Maschine2Mk2::set_colors81 (M2Contols* ctrl, uint8_t* b) const
316 M2Contols::Modifier mod = ctrl->button (M2Contols::BtnShift, M2Contols::ModNone)->active () ? M2Contols::ModShift : M2Contols::ModNone;
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);
327 LIGHT (48, BtnRestart);
328 LIGHT (49, BtnStepLeft);
329 LIGHT (50, BtnStepRight);
333 LIGHT (54, BtnErase);
334 LIGHT (55, BtnShift);
338 Maschine2Mk2::set_colors82 (M2Contols* ctrl, uint8_t* b) const
344 M2Contols::Modifier mod = ctrl->button (M2Contols::BtnShift, M2Contols::ModNone)->active () ? M2Contols::ModShift : M2Contols::ModNone;
346 LIGHT ( 0, BtnControl);
348 LIGHT ( 2, BtnBrowse);
349 LIGHT ( 3, BtnSampling);
350 LIGHT ( 4, BtnSelLeft);
351 LIGHT ( 5, BtnSelRight);
364 LIGHT (16, BtnScene);
365 LIGHT (17, BtnPattern);
366 LIGHT (18, BtnPadMode);
367 LIGHT (19, BtnNavigate);
368 LIGHT (20, BtnDuplicate);
369 LIGHT (21, BtnSelect);
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);