Skeleton for NI Maschine2 Surface
[ardour.git] / libs / surfaces / maschine2 / m2_pad.h
1 /*
2  * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
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, or (at your option)
7  * 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 Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #ifndef _ardour_surfaces_m2pad_h_
20 #define _ardour_surfaces_m2pad_h_
21
22 #include <stdint.h>
23 #include "pbd/signals.h"
24
25 namespace ArdourSurface {
26
27 class M2PadInterface
28 {
29         public:
30                 M2PadInterface () {}
31                 virtual ~M2PadInterface () {}
32
33                 /* user API */
34                 PBD::Signal1<void, float> pressed;
35                 PBD::Signal0<void> released;
36                 PBD::Signal1<void, float> aftertouch;
37                 PBD::Signal2<void, float, bool> event;
38                 PBD::Signal1<void, float> changed;
39
40                 virtual uint16_t value () const { return 0; }
41                 virtual float pressure () const { return 0.f; }
42                 virtual void set_color (uint32_t rgba) {}
43
44                 /* internal API - called from device thread */
45                 virtual void set_value (uint16_t v) {}
46
47                 virtual void color (uint8_t& r, uint8_t& g, uint8_t& b) const {
48                         r = g = b = 0;
49                 }
50 };
51
52 class M2Pad : public M2PadInterface
53 {
54         public:
55                 M2Pad ()
56                         : M2PadInterface ()
57                         , _pressed (false)
58                         , _pressure (0)
59                         , _last (0)
60                         , _cnt (0)
61                         , _rgba (0)
62                 {
63                         for (int i = 0; i < 4; ++i) {
64                                 hist[i] = 0;
65                         }
66                 }
67
68                 uint16_t value () const { return _raw; }
69                 float pressure () const { return _pressure; }
70
71                 void set_color (uint32_t rgba) { _rgba = rgba; }
72
73                 void color (uint8_t& r, uint8_t& g, uint8_t& b) const
74                 {
75                         r = ((_rgba >> 24) & 0xff) >> 1;
76                         g = ((_rgba >> 16) & 0xff) >> 1;
77                         b = ((_rgba >>  8) & 0xff) >> 1;
78                 }
79
80                 void set_value (uint16_t v)
81                 {
82                         // bleed to neighboring pads...
83                         static const uint16_t high  = 159;
84                         static const float    low   = 159 / 4095.f;
85                         static const float mindelta = 32.f / 4096.f;
86
87                         if (_raw != v) {
88                                 changed (v / 4095.f);
89                                 _raw = v;
90                         }
91
92                         // some pads never return to "0", and there's
93                         // TODO map pressure from a min..max range,
94                         // even hard hits rarely exceed 3400 or thereabouts.
95                         // -> "pad sensitivity" config or "calibrate pads"
96
97                         hist[_cnt] = v;
98                         _cnt = (_cnt + 1) & 3;
99
100                         if (_pressed) {
101                                 const float p = v / 4095.f;
102                                 _pressure += .1 * (p - _pressure);
103                                 if (_pressure < low) {
104                                         _pressure = 0;
105                                         _pressed = false;
106                                         released (); /* EMIT SIGNAL */
107                                         event (_pressure, true); /* EMIT SIGNAL */
108                                 } else {
109                                         if (fabsf (_last - _pressure) > mindelta) {
110                                                 _last = _pressure;
111                                                 aftertouch (_pressure); /* EMIT SIGNAL */
112                                                 event (_pressure, false); /* EMIT SIGNAL */
113                                         }
114                                 }
115                         } else {
116                                 bool above_thresh = true;
117                                 uint16_t max = 0;
118                                 for (int i = 0; i < 4; ++i) {
119                                         if (hist[i] < high) {
120                                                 above_thresh = false;
121                                                 break;
122                                         }
123                                         max = std::max (max, hist[i]);
124                                 }
125                                 if (above_thresh) {
126                                         _pressed = true;
127                                         _last = _pressure = max / 4095.f;
128                                         pressed (_pressure);
129                                         event (_pressure, true); /* EMIT SIGNAL */
130                                 }
131                         }
132                 }
133
134         protected:
135                 bool  _pressed;
136                 float _pressure;
137                 uint16_t _raw;
138                 float _last;
139                 uint16_t hist[4];
140                 unsigned int _cnt;
141                 uint32_t _rgba;
142 };
143
144 } /* namespace */
145 #endif /* _ardour_surfaces_m2pad_h_ */
146
147
148