andrewm@0
|
1 /*
|
andrewm@0
|
2 TouchKeys: multi-touch musical keyboard control software
|
andrewm@0
|
3 Copyright (c) 2013 Andrew McPherson
|
andrewm@0
|
4
|
andrewm@0
|
5 This program is free software: you can redistribute it and/or modify
|
andrewm@0
|
6 it under the terms of the GNU General Public License as published by
|
andrewm@0
|
7 the Free Software Foundation, either version 3 of the License, or
|
andrewm@0
|
8 (at your option) any later version.
|
andrewm@0
|
9
|
andrewm@0
|
10 This program is distributed in the hope that it will be useful,
|
andrewm@0
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
andrewm@0
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
andrewm@0
|
13 GNU General Public License for more details.
|
andrewm@0
|
14
|
andrewm@0
|
15 You should have received a copy of the GNU General Public License
|
andrewm@0
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
andrewm@0
|
17
|
andrewm@0
|
18 =====================================================================
|
andrewm@0
|
19
|
andrewm@0
|
20 TouchkeyControlMapping.h: per-note mapping for the TouchKeys control
|
andrewm@0
|
21 mapping, which converts an arbitrary touch parameter into a MIDI or
|
andrewm@0
|
22 OSC control message.
|
andrewm@0
|
23 */
|
andrewm@0
|
24
|
andrewm@0
|
25 #ifndef __touchkeys__TouchkeyControlMapping__
|
andrewm@0
|
26 #define __touchkeys__TouchkeyControlMapping__
|
andrewm@0
|
27
|
andrewm@0
|
28 #include <iostream>
|
andrewm@0
|
29 #include <map>
|
andrewm@0
|
30 #include <boost/bind.hpp>
|
andrewm@0
|
31 #include "../TouchkeyBaseMapping.h"
|
andrewm@0
|
32 #include "../../Utility/IIRFilter.h"
|
andrewm@0
|
33
|
andrewm@0
|
34 // This class handles the implementation of a basic MIDI/OSC control message
|
andrewm@0
|
35 // based on touch data. It can use absolute or relative position in the X
|
andrewm@0
|
36 // or Y axis.
|
andrewm@0
|
37
|
andrewm@0
|
38 class TouchkeyControlMapping : public TouchkeyBaseMapping /*public Mapping, public OscHandler*/ {
|
andrewm@0
|
39 friend class TouchkeyControlMappingFactory;
|
andrewm@0
|
40
|
andrewm@0
|
41 public:
|
andrewm@0
|
42 enum {
|
andrewm@0
|
43 kInputParameterXPosition = 1,
|
andrewm@0
|
44 kInputParameterYPosition,
|
andrewm@0
|
45 kInputParameterTouchSize,
|
andrewm@0
|
46 kInputParameter2FingerMean,
|
andrewm@0
|
47 kInputParameter2FingerDistance,
|
andrewm@0
|
48 kInputParameterMaxValue
|
andrewm@0
|
49 };
|
andrewm@0
|
50
|
andrewm@0
|
51 enum {
|
andrewm@0
|
52 kTypeAbsolute = 1,
|
andrewm@0
|
53 kTypeFirstTouchRelative,
|
andrewm@0
|
54 kTypeNoteOnsetRelative,
|
andrewm@0
|
55 kTypeMaxValue
|
andrewm@0
|
56 };
|
andrewm@0
|
57
|
andrewm@0
|
58 enum {
|
andrewm@0
|
59 kDirectionPositive = 1,
|
andrewm@0
|
60 kDirectionNegative,
|
andrewm@0
|
61 kDirectionBoth,
|
andrewm@0
|
62 kDirectionMaxValue
|
andrewm@0
|
63 };
|
andrewm@0
|
64
|
andrewm@0
|
65 private:
|
andrewm@0
|
66 // Useful constants for mapping MRP messages
|
andrewm@0
|
67 static const int kDefaultMIDIChannel;
|
andrewm@0
|
68 static const int kDefaultFilterBufferLength;
|
andrewm@0
|
69
|
andrewm@0
|
70 static const bool kDefaultIgnoresTwoFingers;
|
andrewm@0
|
71 static const bool kDefaultIgnoresThreeFingers;
|
andrewm@0
|
72 static const int kDefaultDirection;
|
andrewm@0
|
73
|
andrewm@0
|
74 public:
|
andrewm@0
|
75 // ***** Constructors *****
|
andrewm@0
|
76
|
andrewm@0
|
77 // Default constructor, passing the buffer on which to trigger
|
andrewm@0
|
78 TouchkeyControlMapping(PianoKeyboard &keyboard, MappingFactory *factory, int noteNumber, Node<KeyTouchFrame>* touchBuffer,
|
andrewm@0
|
79 Node<key_position>* positionBuffer, KeyPositionTracker* positionTracker);
|
andrewm@0
|
80
|
andrewm@0
|
81 // ***** Destructor *****
|
andrewm@0
|
82
|
andrewm@0
|
83 ~TouchkeyControlMapping();
|
andrewm@0
|
84
|
andrewm@0
|
85 // ***** Modifiers *****
|
andrewm@0
|
86
|
andrewm@0
|
87 // Enable mappings to be sent
|
andrewm@0
|
88 //void engage();
|
andrewm@0
|
89
|
andrewm@0
|
90 // Disable mappings from being sent
|
andrewm@0
|
91 //void disengage(bool shouldDelete = false);
|
andrewm@0
|
92
|
andrewm@0
|
93 // Reset the state back initial values
|
andrewm@0
|
94 void reset();
|
andrewm@0
|
95
|
andrewm@0
|
96 // Resend the current state of all parameters
|
andrewm@0
|
97 void resend();
|
andrewm@0
|
98
|
andrewm@0
|
99 // Name for this control, used in the OSC path
|
andrewm@0
|
100 //void setName(const std::string& name);
|
andrewm@0
|
101
|
andrewm@0
|
102 // Parameters for the controller handling
|
andrewm@0
|
103 // Input parameter to use for this control mapping and whether it is absolute or relative
|
andrewm@0
|
104 void setInputParameter(int parameter, int type);
|
andrewm@0
|
105
|
andrewm@0
|
106 // Input/output range for this parameter
|
andrewm@0
|
107 void setRange(float inputMin, float inputMax, float outputMin, float outputMax, float outputDefault);
|
andrewm@0
|
108
|
andrewm@0
|
109 // Threshold which must be exceeded for the control to engage (for relative position), or 0 if not used
|
andrewm@0
|
110 void setThreshold(float threshold);
|
andrewm@0
|
111
|
andrewm@0
|
112 // Set whether the mapping should ignore multiple touches
|
andrewm@0
|
113 void setIgnoresMultipleFingers(bool ignoresTwo, bool ignoresThree);
|
andrewm@0
|
114
|
andrewm@0
|
115 // Set whether the mapping should use the absolute value of a relative position
|
andrewm@0
|
116 void setDirection(int direction);
|
andrewm@0
|
117
|
andrewm@0
|
118 // ***** Evaluators *****
|
andrewm@0
|
119
|
andrewm@0
|
120 // OSC Handler Method: called by PianoKeyboard (or other OSC source)
|
andrewm@0
|
121 //bool oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data);
|
andrewm@0
|
122
|
andrewm@0
|
123 // This method receives triggers whenever events occur in the touch data or the
|
andrewm@0
|
124 // continuous key position (state changes only). It alters the behavior and scheduling
|
andrewm@0
|
125 // of the mapping but does not itself send OSC messages
|
andrewm@0
|
126 void triggerReceived(TriggerSource* who, timestamp_type timestamp);
|
andrewm@0
|
127
|
andrewm@0
|
128 // This method handles the OSC message transmission. It should be run in the Scheduler
|
andrewm@0
|
129 // thread provided by PianoKeyboard.
|
andrewm@0
|
130 timestamp_type performMapping();
|
andrewm@0
|
131
|
andrewm@0
|
132 private:
|
andrewm@0
|
133 // ***** Private Methods *****
|
andrewm@0
|
134 void midiNoteOnReceived(int channel, int velocity);
|
andrewm@0
|
135 void midiNoteOffReceived(int channel);
|
andrewm@0
|
136
|
andrewm@0
|
137 void resetDetectionState();
|
andrewm@0
|
138 void clearBuffers();
|
andrewm@0
|
139
|
andrewm@0
|
140 float getValue(const KeyTouchFrame& frame);
|
andrewm@0
|
141 int locateTouchId(KeyTouchFrame const& frame, int index);
|
andrewm@0
|
142 int lowestUnassignedTouch(KeyTouchFrame const& frame, int *indexWithinFrame);
|
andrewm@0
|
143 void sendControlMessage(float value, bool force = false);
|
andrewm@0
|
144
|
andrewm@0
|
145 // ***** Member Variables *****
|
andrewm@0
|
146
|
andrewm@0
|
147 bool controlIsEngaged_; // Whether the control has
|
andrewm@0
|
148
|
andrewm@0
|
149 float inputMin_, inputMax_; // Input ranges
|
andrewm@0
|
150 float outputMin_, outputMax_; // Output ranges
|
andrewm@0
|
151 float outputDefault_; // Default value to send in absence of any input
|
andrewm@0
|
152 int inputParameter_; // Parameter to be used for mapping
|
andrewm@0
|
153 int inputType_; // Type of mapping (absolute, relative, etc.)
|
andrewm@0
|
154 float threshold_; // Threshold that must be exceeded before mapping engages
|
andrewm@0
|
155 bool ignoresTwoFingers_; // Whether this mapping supresses all messages when two
|
andrewm@0
|
156 bool ignoresThreeFingers_; // or three fingers are present
|
andrewm@0
|
157 int direction_; // Whether the mapping goes up, down or both directions (for relative motion)
|
andrewm@0
|
158
|
andrewm@0
|
159 float touchOnsetValue_, midiOnsetValue_; // Where the touch began initially and at MIDI note on
|
andrewm@0
|
160 float lastValue_; // Where the touch was at the last frame we received
|
andrewm@0
|
161 int idsOfCurrentTouches_[3]; // Which touch ID(s) we're currently following
|
andrewm@0
|
162 timestamp_type lastTimestamp_; // When the last data point arrived
|
andrewm@0
|
163 Node<float>::size_type lastProcessedIndex_; // Index of the last filtered position sample we've handled
|
andrewm@0
|
164
|
andrewm@0
|
165 float controlEngageLocation_; // Where the controller was engaged (i.e. where the threshold was crossed, if relative)
|
andrewm@0
|
166 float controlScalerPositive_, controlScalerNegative_; // Translation between position and control values for upward and downward motions
|
andrewm@0
|
167
|
andrewm@0
|
168 float lastControlValue_; // The last value we sent out
|
andrewm@0
|
169
|
andrewm@0
|
170 Node<float> rawValues_; // Most recent values
|
andrewm@0
|
171 //CriticalSection rawValueAccessMutex_; // Mutex protecting access to raw values buffer
|
andrewm@0
|
172 };
|
andrewm@0
|
173
|
andrewm@0
|
174
|
andrewm@0
|
175
|
andrewm@0
|
176 #endif /* defined(__touchkeys__TouchkeyControlMapping__) */
|