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 TouchkeyVibratoMapping.h: per-note mapping for the vibrato mapping class,
|
andrewm@0
|
21 which creates vibrato through side-to-side motion of the finger on the
|
andrewm@0
|
22 key surface.
|
andrewm@0
|
23 */
|
andrewm@0
|
24
|
andrewm@0
|
25 #ifndef __touchkeys__TouchkeyVibratoMapping__
|
andrewm@0
|
26 #define __touchkeys__TouchkeyVibratoMapping__
|
andrewm@0
|
27
|
andrewm@0
|
28
|
andrewm@0
|
29 #include <map>
|
andrewm@0
|
30 #include <boost/bind.hpp>
|
andrewm@0
|
31 #include "../../TouchKeys/KeyTouchFrame.h"
|
andrewm@0
|
32 #include "../../TouchKeys/KeyPositionTracker.h"
|
andrewm@0
|
33 #include "../../TouchKeys/PianoKeyboard.h"
|
andrewm@0
|
34 #include "../TouchkeyBaseMapping.h"
|
andrewm@0
|
35 #include "../../Utility/IIRFilter.h"
|
andrewm@0
|
36
|
andrewm@0
|
37 // This class handles the detection and mapping of vibrato gestures
|
andrewm@0
|
38 // based on Touchkey data. It outputs MIDI or OSC messages that
|
andrewm@0
|
39 // can be used to affect the pitch of the active note.
|
andrewm@0
|
40
|
andrewm@0
|
41 class TouchkeyVibratoMapping : public TouchkeyBaseMapping {
|
andrewm@0
|
42 friend class TouchkeyVibratoMappingFactory;
|
andrewm@0
|
43
|
andrewm@0
|
44 private:
|
andrewm@0
|
45 // Useful constants for mapping MRP messages
|
andrewm@0
|
46 /*constexpr static const int kDefaultMIDIChannel = 0;
|
andrewm@0
|
47 constexpr static const int kDefaultFilterBufferLength = 30;
|
andrewm@0
|
48
|
andrewm@0
|
49 constexpr static const float kDefaultVibratoThresholdX = 0.05;
|
andrewm@0
|
50 constexpr static const float kDefaultVibratoRatioX = 0.3;
|
andrewm@0
|
51 constexpr static const float kDefaultVibratoThresholdY = 0.02;
|
andrewm@0
|
52 constexpr static const float kDefaultVibratoRatioY = 0.8;
|
andrewm@0
|
53 constexpr static const timestamp_diff_type kDefaultVibratoTimeout = microseconds_to_timestamp(400000); // 0.4s
|
andrewm@0
|
54 constexpr static const float kDefaultVibratoPrescaler = 2.0;
|
andrewm@0
|
55 constexpr static const float kDefaultVibratoRangeSemitones = 1.25;
|
andrewm@0
|
56
|
andrewm@0
|
57 constexpr static const timestamp_diff_type kZeroCrossingMinimumTime = microseconds_to_timestamp(50000); // 50ms
|
andrewm@0
|
58 constexpr static const timestamp_diff_type kMinimumOnsetTime = microseconds_to_timestamp(30000); // 30ms
|
andrewm@0
|
59 constexpr static const timestamp_diff_type kMaximumOnsetTime = microseconds_to_timestamp(300000); // 300ms
|
andrewm@0
|
60 constexpr static const timestamp_diff_type kMinimumReleaseTime = microseconds_to_timestamp(30000); // 30ms
|
andrewm@0
|
61 constexpr static const timestamp_diff_type kMaximumReleaseTime = microseconds_to_timestamp(300000); // 300ms*/
|
andrewm@0
|
62
|
andrewm@0
|
63 static const int kDefaultMIDIChannel;
|
andrewm@0
|
64 static const int kDefaultFilterBufferLength;
|
andrewm@0
|
65
|
andrewm@0
|
66 static const float kDefaultVibratoThresholdX;
|
andrewm@0
|
67 static const float kDefaultVibratoRatioX;
|
andrewm@0
|
68 static const float kDefaultVibratoThresholdY;
|
andrewm@0
|
69 static const float kDefaultVibratoRatioY;
|
andrewm@0
|
70 static const timestamp_diff_type kDefaultVibratoTimeout;
|
andrewm@0
|
71 static const float kDefaultVibratoPrescaler;
|
andrewm@0
|
72 static const float kDefaultVibratoRangeSemitones;
|
andrewm@0
|
73
|
andrewm@0
|
74 static const timestamp_diff_type kZeroCrossingMinimumTime;
|
andrewm@0
|
75 static const timestamp_diff_type kMinimumOnsetTime;
|
andrewm@0
|
76 static const timestamp_diff_type kMaximumOnsetTime;
|
andrewm@0
|
77 static const timestamp_diff_type kMinimumReleaseTime;
|
andrewm@0
|
78 static const timestamp_diff_type kMaximumReleaseTime;
|
andrewm@0
|
79
|
andrewm@0
|
80 static const float kWhiteKeySingleAxisThreshold;
|
andrewm@0
|
81
|
andrewm@0
|
82 enum {
|
andrewm@0
|
83 kStateInactive = 0,
|
andrewm@0
|
84 kStateSwitchingOn,
|
andrewm@0
|
85 kStateActive,
|
andrewm@0
|
86 kStateSwitchingOff
|
andrewm@0
|
87 };
|
andrewm@0
|
88
|
andrewm@0
|
89 public:
|
andrewm@0
|
90 // ***** Constructors *****
|
andrewm@0
|
91
|
andrewm@0
|
92 // Default constructor, passing the buffer on which to trigger
|
andrewm@0
|
93 TouchkeyVibratoMapping(PianoKeyboard &keyboard, MappingFactory *factory, int noteNumber, Node<KeyTouchFrame>* touchBuffer,
|
andrewm@0
|
94 Node<key_position>* positionBuffer, KeyPositionTracker* positionTracker);
|
andrewm@0
|
95
|
andrewm@0
|
96 // ***** Destructor *****
|
andrewm@0
|
97
|
andrewm@0
|
98 ~TouchkeyVibratoMapping();
|
andrewm@0
|
99
|
andrewm@0
|
100 // ***** Modifiers *****
|
andrewm@0
|
101
|
andrewm@0
|
102 // Disable mappings from being sent
|
andrewm@0
|
103 void disengage(bool shouldDelete = false);
|
andrewm@0
|
104
|
andrewm@0
|
105 // Reset the state back initial values
|
andrewm@0
|
106 void reset();
|
andrewm@0
|
107
|
andrewm@0
|
108 // Resend the current state of all parameters
|
andrewm@0
|
109 void resend();
|
andrewm@0
|
110
|
andrewm@0
|
111 // Parameters for vibrato algorithm
|
andrewm@0
|
112 //void setType(int vibratoType);
|
andrewm@0
|
113 void setRange(float rangeSemitones);
|
andrewm@0
|
114 void setPrescaler(float prescaler);
|
andrewm@0
|
115 void setThresholds(float thresholdX, float thresholdY, float ratioX, float ratioY);
|
andrewm@0
|
116 void setTimeout(timestamp_diff_type timeout);
|
andrewm@0
|
117
|
andrewm@0
|
118 // ***** Evaluators *****
|
andrewm@0
|
119
|
andrewm@0
|
120 // This method receives triggers whenever events occur in the touch data or the
|
andrewm@0
|
121 // continuous key position (state changes only). It alters the behavior and scheduling
|
andrewm@0
|
122 // of the mapping but does not itself send OSC messages
|
andrewm@0
|
123 void triggerReceived(TriggerSource* who, timestamp_type timestamp);
|
andrewm@0
|
124
|
andrewm@0
|
125 // This method handles the OSC message transmission. It should be run in the Scheduler
|
andrewm@0
|
126 // thread provided by PianoKeyboard.
|
andrewm@0
|
127 timestamp_type performMapping();
|
andrewm@0
|
128
|
andrewm@0
|
129 private:
|
andrewm@0
|
130 // ***** Private Methods *****
|
andrewm@0
|
131 void midiNoteOnReceived(int channel, int velocity);
|
andrewm@0
|
132 void midiNoteOffReceived(int channel);
|
andrewm@0
|
133
|
andrewm@0
|
134 void changeStateSwitchingOn(timestamp_type timestamp);
|
andrewm@0
|
135 void changeStateActive(timestamp_type timestamp);
|
andrewm@0
|
136 void changeStateSwitchingOff(timestamp_type timestamp);
|
andrewm@0
|
137 void changeStateInactive(timestamp_type timestamp);
|
andrewm@0
|
138
|
andrewm@0
|
139 void resetDetectionState();
|
andrewm@0
|
140 void clearBuffers();
|
andrewm@0
|
141
|
andrewm@0
|
142 bool keyIsWhite();
|
andrewm@0
|
143
|
andrewm@0
|
144 void sendVibratoMessage(float pitchBendSemitones, bool force = false);
|
andrewm@0
|
145
|
andrewm@0
|
146 // ***** Member Variables *****
|
andrewm@0
|
147
|
andrewm@0
|
148 int vibratoState_; // Whether a vibrato gesture is currently detected
|
andrewm@0
|
149
|
andrewm@0
|
150 timestamp_type rampBeginTime_; // If in a switching state, when does the transition begin?
|
andrewm@0
|
151 float rampScaleValue_; // If in a switching state, what is the end point of the ramp?
|
andrewm@0
|
152 timestamp_diff_type rampLength_; // If in a switching state, how long is the transition?
|
andrewm@0
|
153 float lastCalculatedRampValue_; // Value of the ramp that was last calculated
|
andrewm@0
|
154
|
andrewm@0
|
155 float onsetThresholdX_, onsetThresholdY_; // Thresholds for detecting vibrato (first extremum)
|
andrewm@0
|
156 float onsetRatioX_, onsetRatioY_; // Thresholds for detection vibrato (second extremum)
|
andrewm@0
|
157 timestamp_diff_type onsetTimeout_; // Timeout between first and second extrema
|
andrewm@0
|
158
|
andrewm@0
|
159 float onsetLocationX_, onsetLocationY_; // Where the touch began at MIDI note on
|
andrewm@0
|
160 float lastX_, lastY_; // Where the touch was at the last frame we received
|
andrewm@0
|
161 int idOfCurrentTouch_; // Which touch ID 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 timestamp_type lastZeroCrossingTimestamp_; // Timestamp of the last zero crossing
|
andrewm@0
|
166 timestamp_diff_type lastZeroCrossingInterval_; // Interval between the last two zero-crossings of filtered distance
|
andrewm@0
|
167 bool lastSampleWasPositive_; // Whether the last sample was > 0
|
andrewm@0
|
168
|
andrewm@0
|
169 bool foundFirstExtremum_; // Whether the first extremum has occurred
|
andrewm@0
|
170 float firstExtremumX_, firstExtremumY_; // Where the first extremum occurred
|
andrewm@0
|
171 timestamp_type firstExtremumTimestamp_; // Where the first extremum occurred
|
andrewm@0
|
172 timestamp_type lastExtremumTimestamp_; // When the most recent extremum occurred
|
andrewm@0
|
173
|
andrewm@0
|
174 float vibratoPrescaler_; // Parameter controlling prescaler before nonlinear scaling
|
andrewm@0
|
175 float vibratoRangeSemitones_; // Amount of pitch bend in one direction at maximum
|
andrewm@0
|
176
|
andrewm@0
|
177 float lastPitchBendSemitones_; // The last pitch bend value we sent out
|
andrewm@0
|
178
|
andrewm@0
|
179 Node<float> rawDistance_; // Distance from onset location
|
andrewm@0
|
180 IIRFilterNode<float> filteredDistance_; // Bandpass filtered finger motion
|
andrewm@0
|
181 CriticalSection distanceAccessMutex_; // Mutex that protects the access buffer from changes
|
andrewm@0
|
182 };
|
andrewm@0
|
183
|
andrewm@0
|
184 #endif /* defined(__touchkeys__TouchkeyVibratoMapping__) */
|