diff options
Diffstat (limited to 'libs/surfaces/maschine2/m2_pad.h')
-rw-r--r-- | libs/surfaces/maschine2/m2_pad.h | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/libs/surfaces/maschine2/m2_pad.h b/libs/surfaces/maschine2/m2_pad.h new file mode 100644 index 0000000000..97266f28c1 --- /dev/null +++ b/libs/surfaces/maschine2/m2_pad.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2016 Robin Gareus <robin@gareus.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _ardour_surfaces_m2pad_h_ +#define _ardour_surfaces_m2pad_h_ + +#include <stdint.h> +#include "pbd/signals.h" + +namespace ArdourSurface { + +class M2PadInterface +{ + public: + M2PadInterface () {} + virtual ~M2PadInterface () {} + + /* user API */ + PBD::Signal1<void, float> pressed; + PBD::Signal0<void> released; + PBD::Signal1<void, float> aftertouch; + PBD::Signal2<void, float, bool> event; + PBD::Signal1<void, float> changed; + + virtual uint16_t value () const { return 0; } + virtual float pressure () const { return 0.f; } + virtual void set_color (uint32_t rgba) {} + + /* internal API - called from device thread */ + virtual void set_value (uint16_t v) {} + + virtual void color (uint8_t& r, uint8_t& g, uint8_t& b) const { + r = g = b = 0; + } +}; + +class M2Pad : public M2PadInterface +{ + public: + M2Pad () + : M2PadInterface () + , _pressed (false) + , _pressure (0) + , _last (0) + , _cnt (0) + , _rgba (0) + { + for (int i = 0; i < 4; ++i) { + hist[i] = 0; + } + } + + uint16_t value () const { return _raw; } + float pressure () const { return _pressure; } + + void set_color (uint32_t rgba) { _rgba = rgba; } + + void color (uint8_t& r, uint8_t& g, uint8_t& b) const + { + r = ((_rgba >> 24) & 0xff) >> 1; + g = ((_rgba >> 16) & 0xff) >> 1; + b = ((_rgba >> 8) & 0xff) >> 1; + } + + void set_value (uint16_t v) + { + // bleed to neighboring pads... + static const uint16_t high = 159; + static const float low = 159 / 4095.f; + static const float mindelta = 32.f / 4096.f; + + if (_raw != v) { + changed (v / 4095.f); + _raw = v; + } + + // some pads never return to "0", and there's + // TODO map pressure from a min..max range, + // even hard hits rarely exceed 3400 or thereabouts. + // -> "pad sensitivity" config or "calibrate pads" + + hist[_cnt] = v; + _cnt = (_cnt + 1) & 3; + + if (_pressed) { + const float p = v / 4095.f; + _pressure += .1 * (p - _pressure); + if (_pressure < low) { + _pressure = 0; + _pressed = false; + released (); /* EMIT SIGNAL */ + event (_pressure, true); /* EMIT SIGNAL */ + } else { + if (fabsf (_last - _pressure) > mindelta) { + _last = _pressure; + aftertouch (_pressure); /* EMIT SIGNAL */ + event (_pressure, false); /* EMIT SIGNAL */ + } + } + } else { + bool above_thresh = true; + uint16_t max = 0; + for (int i = 0; i < 4; ++i) { + if (hist[i] < high) { + above_thresh = false; + break; + } + max = std::max (max, hist[i]); + } + if (above_thresh) { + _pressed = true; + _last = _pressure = max / 4095.f; + pressed (_pressure); + event (_pressure, true); /* EMIT SIGNAL */ + } + } + } + + protected: + bool _pressed; + float _pressure; + uint16_t _raw; + float _last; + uint16_t hist[4]; + unsigned int _cnt; + uint32_t _rgba; +}; + +} /* namespace */ +#endif /* _ardour_surfaces_m2pad_h_ */ + + + |