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 TouchkeyReleaseAngleMappingFactory.cpp: factory for the release angle
|
andrewm@0
|
21 mapping, which measures the speed of finger motion along the key at
|
andrewm@0
|
22 the time of MIDI note off.
|
andrewm@0
|
23 */
|
andrewm@0
|
24
|
andrewm@0
|
25 #include "TouchkeyReleaseAngleMappingFactory.h"
|
andrewm@46
|
26 #include "TouchkeyReleaseAngleMappingExtendedEditor.h"
|
andrewm@0
|
27
|
andrewm@0
|
28 // Class constants
|
andrewm@0
|
29 const timestamp_diff_type TouchkeyReleaseAngleMappingFactory::kDefaultMaxLookbackTime = milliseconds_to_timestamp(100);
|
andrewm@46
|
30 const int TouchkeyReleaseAngleMappingFactory::kNumConfigurations = 2;
|
andrewm@46
|
31 const std::string TouchkeyReleaseAngleMappingFactory::kConfigurationNames[] = {
|
andrewm@46
|
32 "Sample Modeling Trombone",
|
andrewm@46
|
33 "Sample Modeling Trumpet"
|
andrewm@46
|
34 };
|
andrewm@0
|
35
|
andrewm@0
|
36 TouchkeyReleaseAngleMappingFactory::TouchkeyReleaseAngleMappingFactory(PianoKeyboard &keyboard, MidiKeyboardSegment& segment)
|
andrewm@46
|
37 : TouchkeyBaseMappingFactory<TouchkeyReleaseAngleMapping>(keyboard, segment),
|
andrewm@46
|
38 currentConfiguration_(-1),
|
andrewm@46
|
39 upEnabled_(true), downEnabled_(true),
|
andrewm@46
|
40 upMinimumAngle_(TouchkeyReleaseAngleMapping::kDefaultUpMinimumAngle),
|
andrewm@46
|
41 downMinimumAngle_(TouchkeyReleaseAngleMapping::kDefaultDownMinimumAngle)
|
andrewm@46
|
42 {
|
andrewm@46
|
43 // Get default values from the first configuration
|
andrewm@46
|
44 setCurrentConfiguration(0);
|
andrewm@46
|
45 }
|
andrewm@46
|
46
|
andrewm@46
|
47 // Set a particular configuration; make sure the values here match the
|
andrewm@46
|
48 // defined names and indices above
|
andrewm@46
|
49 void TouchkeyReleaseAngleMappingFactory::setCurrentConfiguration(int index) {
|
andrewm@46
|
50 if(index == 0) {
|
andrewm@46
|
51 // Sample Modeling Trombone
|
andrewm@46
|
52 currentConfiguration_ = 0;
|
andrewm@46
|
53 upEnabled_ = downEnabled_ = true;
|
andrewm@46
|
54 upMinimumAngle_ = 1.0;
|
andrewm@46
|
55 downMinimumAngle_ = 1.5;
|
andrewm@46
|
56 windowSizeMilliseconds_ = 100.0;
|
andrewm@46
|
57
|
andrewm@46
|
58 clearNotes();
|
andrewm@46
|
59
|
andrewm@46
|
60 upNotes_[0] = 36;
|
andrewm@46
|
61 upVelocities_[0] = 64;
|
andrewm@46
|
62 upNotes_[1] = 31;
|
andrewm@46
|
63 upVelocities_[1] = 96;
|
andrewm@46
|
64
|
andrewm@46
|
65 downNotes_[0] = 36;
|
andrewm@46
|
66 downVelocities_[0] = 64;
|
andrewm@46
|
67 downNotes_[1] = 33;
|
andrewm@46
|
68 downVelocities_[1] = 80;
|
andrewm@46
|
69 }
|
andrewm@46
|
70 else if(index == 1) {
|
andrewm@46
|
71 // Sample Modeling Trumpet
|
andrewm@46
|
72 currentConfiguration_ = 1;
|
andrewm@46
|
73 upEnabled_ = downEnabled_ = true;
|
andrewm@46
|
74 upMinimumAngle_ = 1.0;
|
andrewm@46
|
75 downMinimumAngle_ = 1.5;
|
andrewm@46
|
76 windowSizeMilliseconds_ = 100.0;
|
andrewm@46
|
77
|
andrewm@46
|
78 clearNotes();
|
andrewm@46
|
79
|
andrewm@46
|
80 upNotes_[0] = 48;
|
andrewm@46
|
81 upVelocities_[0] = 64;
|
andrewm@46
|
82 upNotes_[1] = 42;
|
andrewm@46
|
83 upVelocities_[1] = 96;
|
andrewm@46
|
84
|
andrewm@46
|
85 downNotes_[0] = 48;
|
andrewm@46
|
86 downVelocities_[0] = 64;
|
andrewm@46
|
87 downNotes_[1] = 46;
|
andrewm@46
|
88 downVelocities_[1] = 96;
|
andrewm@46
|
89 }
|
andrewm@46
|
90 }
|
andrewm@46
|
91
|
andrewm@46
|
92 // Parameters for release angle algorithm
|
andrewm@46
|
93 int TouchkeyReleaseAngleMappingFactory::getUpNote(int sequence) {
|
andrewm@46
|
94 if(sequence < 0 || sequence >= RELEASE_ANGLE_MAX_SEQUENCE_LENGTH)
|
andrewm@46
|
95 return 0;
|
andrewm@46
|
96 return upNotes_[sequence];
|
andrewm@46
|
97 }
|
andrewm@46
|
98
|
andrewm@46
|
99 int TouchkeyReleaseAngleMappingFactory::getUpVelocity(int sequence) {
|
andrewm@46
|
100 if(sequence < 0 || sequence >= RELEASE_ANGLE_MAX_SEQUENCE_LENGTH)
|
andrewm@46
|
101 return 0;
|
andrewm@46
|
102 return upVelocities_[sequence];
|
andrewm@46
|
103 }
|
andrewm@46
|
104
|
andrewm@46
|
105 int TouchkeyReleaseAngleMappingFactory::getDownNote(int sequence) {
|
andrewm@46
|
106 if(sequence < 0 || sequence >= RELEASE_ANGLE_MAX_SEQUENCE_LENGTH)
|
andrewm@46
|
107 return 0;
|
andrewm@46
|
108 return downNotes_[sequence];
|
andrewm@46
|
109 }
|
andrewm@46
|
110
|
andrewm@46
|
111 int TouchkeyReleaseAngleMappingFactory::getDownVelocity(int sequence) {
|
andrewm@46
|
112 if(sequence < 0 || sequence >= RELEASE_ANGLE_MAX_SEQUENCE_LENGTH)
|
andrewm@46
|
113 return 0;
|
andrewm@46
|
114 return downVelocities_[sequence];
|
andrewm@46
|
115 }
|
andrewm@46
|
116
|
andrewm@46
|
117 void TouchkeyReleaseAngleMappingFactory::setWindowSize(float windowSize) {
|
andrewm@46
|
118 if(windowSizeMilliseconds_ != windowSize)
|
andrewm@46
|
119 currentConfiguration_ = -1;
|
andrewm@46
|
120 windowSizeMilliseconds_ = windowSize;
|
andrewm@46
|
121 }
|
andrewm@46
|
122
|
andrewm@46
|
123 void TouchkeyReleaseAngleMappingFactory::setUpMessagesEnabled(bool enable) {
|
andrewm@46
|
124 if(upEnabled_ != enable)
|
andrewm@46
|
125 currentConfiguration_ = -1;
|
andrewm@46
|
126 upEnabled_ = enable;
|
andrewm@46
|
127 }
|
andrewm@46
|
128
|
andrewm@46
|
129 void TouchkeyReleaseAngleMappingFactory::setDownMessagesEnabled(bool enable) {
|
andrewm@46
|
130 if(downEnabled_ != enable)
|
andrewm@46
|
131 currentConfiguration_ = -1;
|
andrewm@46
|
132 downEnabled_ = enable;
|
andrewm@46
|
133 }
|
andrewm@46
|
134
|
andrewm@46
|
135 void TouchkeyReleaseAngleMappingFactory::setUpMinimumAngle(float minAngle) {
|
andrewm@46
|
136 if(upMinimumAngle_ != minAngle)
|
andrewm@46
|
137 currentConfiguration_ = -1;
|
andrewm@46
|
138 upMinimumAngle_ = fabsf(minAngle);
|
andrewm@46
|
139 }
|
andrewm@46
|
140
|
andrewm@46
|
141 void TouchkeyReleaseAngleMappingFactory::setUpNote(int sequence, int note) {
|
andrewm@46
|
142 if(sequence < 0 || sequence >= RELEASE_ANGLE_MAX_SEQUENCE_LENGTH)
|
andrewm@46
|
143 return;
|
andrewm@46
|
144 if(note < 0 || note > 127)
|
andrewm@46
|
145 upNotes_[sequence] = 0;
|
andrewm@46
|
146 else {
|
andrewm@46
|
147 if(upNotes_[sequence] != note)
|
andrewm@46
|
148 currentConfiguration_ = -1;
|
andrewm@46
|
149 upNotes_[sequence] = note;
|
andrewm@46
|
150 }
|
andrewm@46
|
151 }
|
andrewm@46
|
152
|
andrewm@46
|
153 void TouchkeyReleaseAngleMappingFactory::setUpVelocity(int sequence, int velocity) {
|
andrewm@46
|
154 if(sequence < 0 || sequence >= RELEASE_ANGLE_MAX_SEQUENCE_LENGTH)
|
andrewm@46
|
155 return;
|
andrewm@46
|
156 if(velocity < 0 || velocity > 127)
|
andrewm@46
|
157 upVelocities_[sequence] = 0;
|
andrewm@46
|
158 else {
|
andrewm@46
|
159 if(upVelocities_[sequence] != velocity)
|
andrewm@46
|
160 currentConfiguration_ = -1;
|
andrewm@46
|
161 upVelocities_[sequence] = velocity;
|
andrewm@46
|
162 }
|
andrewm@46
|
163 }
|
andrewm@46
|
164
|
andrewm@46
|
165 void TouchkeyReleaseAngleMappingFactory::setDownMinimumAngle(float minAngle) {
|
andrewm@46
|
166 if(downMinimumAngle_ != minAngle)
|
andrewm@46
|
167 currentConfiguration_ = -1;
|
andrewm@46
|
168 downMinimumAngle_ = fabsf(minAngle);
|
andrewm@46
|
169 }
|
andrewm@46
|
170
|
andrewm@46
|
171 void TouchkeyReleaseAngleMappingFactory::setDownNote(int sequence, int note) {
|
andrewm@46
|
172 if(sequence < 0 || sequence >= RELEASE_ANGLE_MAX_SEQUENCE_LENGTH)
|
andrewm@46
|
173 return;
|
andrewm@46
|
174 if(note < 0 || note > 127)
|
andrewm@46
|
175 downNotes_[sequence] = 0;
|
andrewm@46
|
176 else {
|
andrewm@46
|
177 if(downNotes_[sequence] != note)
|
andrewm@46
|
178 currentConfiguration_ = -1;
|
andrewm@46
|
179 downNotes_[sequence] = note;
|
andrewm@46
|
180 }
|
andrewm@46
|
181 }
|
andrewm@46
|
182
|
andrewm@46
|
183 void TouchkeyReleaseAngleMappingFactory::setDownVelocity(int sequence, int velocity) {
|
andrewm@46
|
184 if(sequence < 0 || sequence >= RELEASE_ANGLE_MAX_SEQUENCE_LENGTH)
|
andrewm@46
|
185 return;
|
andrewm@46
|
186 if(velocity < 0 || velocity > 127)
|
andrewm@46
|
187 downVelocities_[sequence] = 0;
|
andrewm@46
|
188 else {
|
andrewm@46
|
189 if(downVelocities_[sequence] != velocity)
|
andrewm@46
|
190 currentConfiguration_ = -1;
|
andrewm@46
|
191 downVelocities_[sequence] = velocity;
|
andrewm@46
|
192 }
|
andrewm@46
|
193 }
|
andrewm@46
|
194
|
andrewm@49
|
195 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@46
|
196 // ***** GUI Support *****
|
andrewm@46
|
197
|
andrewm@46
|
198 MappingEditorComponent* TouchkeyReleaseAngleMappingFactory::createExtendedEditor() {
|
andrewm@46
|
199 return new TouchkeyReleaseAngleMappingExtendedEditor(*this);
|
andrewm@46
|
200 }
|
andrewm@49
|
201 #endif
|
andrewm@49
|
202
|
andrewm@0
|
203
|
andrewm@36
|
204 // ****** Preset Save/Load ******
|
andrewm@36
|
205 XmlElement* TouchkeyReleaseAngleMappingFactory::getPreset() {
|
andrewm@36
|
206 PropertySet properties;
|
andrewm@36
|
207
|
andrewm@36
|
208 storeCommonProperties(properties);
|
andrewm@36
|
209
|
andrewm@46
|
210 properties.setValue("currentConfiguration", currentConfiguration_);
|
andrewm@46
|
211 properties.setValue("upEnabled", upEnabled_);
|
andrewm@46
|
212 properties.setValue("downEnabled", downEnabled_);
|
andrewm@46
|
213 properties.setValue("upMinimumAngle", upMinimumAngle_);
|
andrewm@46
|
214 properties.setValue("downMinimumAngle", downMinimumAngle_);
|
andrewm@46
|
215 properties.setValue("windowSizeMilliseconds", windowSizeMilliseconds_);
|
andrewm@46
|
216
|
andrewm@46
|
217 // TODO: set arrays of notes and velocities
|
andrewm@36
|
218
|
andrewm@36
|
219 XmlElement* preset = properties.createXml("MappingFactory");
|
andrewm@36
|
220 preset->setAttribute("type", "ReleaseAngle");
|
andrewm@36
|
221
|
andrewm@36
|
222 return preset;
|
andrewm@36
|
223 }
|
andrewm@36
|
224
|
andrewm@36
|
225 bool TouchkeyReleaseAngleMappingFactory::loadPreset(XmlElement const* preset) {
|
andrewm@36
|
226 if(preset == 0)
|
andrewm@36
|
227 return false;
|
andrewm@36
|
228
|
andrewm@36
|
229 PropertySet properties;
|
andrewm@36
|
230 properties.restoreFromXml(*preset);
|
andrewm@36
|
231
|
andrewm@36
|
232 if(!loadCommonProperties(properties))
|
andrewm@36
|
233 return false;
|
andrewm@36
|
234
|
andrewm@46
|
235 // First check if there's a default configuration in use
|
andrewm@46
|
236 // We can get all other parameters from that regardless of the
|
andrewm@46
|
237 // remaining contents
|
andrewm@46
|
238 if(properties.containsKey("currentConfiguration")) {
|
andrewm@46
|
239 int config = properties.getIntValue("currentConfiguration");
|
andrewm@46
|
240 if(config >= 0 && config < kNumConfigurations)
|
andrewm@46
|
241 setCurrentConfiguration(config);
|
andrewm@46
|
242 }
|
andrewm@46
|
243 else {
|
andrewm@46
|
244 if(!properties.containsKey("upEnabled") ||
|
andrewm@46
|
245 !properties.containsKey("downEnabled") ||
|
andrewm@46
|
246 !properties.containsKey("upMinimumAngle") ||
|
andrewm@46
|
247 !properties.containsKey("downMinimumAngle") ||
|
andrewm@46
|
248 !properties.containsKey("windowSizeMilliseconds"))
|
andrewm@46
|
249 return false;
|
andrewm@46
|
250
|
andrewm@46
|
251 currentConfiguration_ = -1;
|
andrewm@46
|
252 upEnabled_ = properties.getBoolValue("upEnabled");
|
andrewm@46
|
253 downEnabled_ = properties.getBoolValue("downEnabled");
|
andrewm@46
|
254 upMinimumAngle_ = properties.getDoubleValue("upMinimumAngle");
|
andrewm@46
|
255 downMinimumAngle_ = properties.getDoubleValue("downMinimumAngle");
|
andrewm@46
|
256 windowSizeMilliseconds_ = properties.getDoubleValue("windowSizeMilliseconds");
|
andrewm@46
|
257
|
andrewm@46
|
258 // TODO: load arrays of notes and velocities
|
andrewm@46
|
259 }
|
andrewm@36
|
260
|
andrewm@36
|
261 return true;
|
andrewm@36
|
262 }
|
andrewm@36
|
263
|
andrewm@0
|
264 // MIDI note ended: see whether the mapping was suspended and if not, execute the angle calculation
|
andrewm@46
|
265 /*void TouchkeyReleaseAngleMappingFactory::midiNoteOff(int noteNumber, bool touchIsOn, bool keyMotionActive,
|
andrewm@0
|
266 Node<KeyTouchFrame>* touchBuffer,
|
andrewm@0
|
267 Node<key_position>* positionBuffer,
|
andrewm@0
|
268 KeyPositionTracker* positionTracker) {
|
andrewm@0
|
269 if(mappings_.count(noteNumber) != 0) {
|
andrewm@0
|
270 mappings_[noteNumber]->processRelease(keyboard_.schedulerCurrentTimestamp());
|
andrewm@0
|
271 }
|
andrewm@0
|
272
|
andrewm@0
|
273 // Call base class method
|
andrewm@0
|
274 TouchkeyBaseMappingFactory<TouchkeyReleaseAngleMapping>::midiNoteOff(noteNumber, touchIsOn, keyMotionActive, touchBuffer, positionBuffer, positionTracker);
|
andrewm@46
|
275 }*/
|
andrewm@46
|
276
|
andrewm@46
|
277 void TouchkeyReleaseAngleMappingFactory::initializeMappingParameters(int noteNumber,
|
andrewm@46
|
278 TouchkeyReleaseAngleMapping *mapping) {
|
andrewm@46
|
279 mapping->setWindowSize(windowSizeMilliseconds_);
|
andrewm@46
|
280 mapping->setUpMessagesEnabled(upEnabled_);
|
andrewm@46
|
281 mapping->setDownMessagesEnabled(downEnabled_);
|
andrewm@46
|
282 mapping->setUpMinimumAngle(upMinimumAngle_);
|
andrewm@46
|
283 mapping->setDownMinimumAngle(downMinimumAngle_);
|
andrewm@46
|
284
|
andrewm@46
|
285 for(int i = 0; i < RELEASE_ANGLE_MAX_SEQUENCE_LENGTH; i++) {
|
andrewm@46
|
286 mapping->setUpNote(i, upNotes_[i]);
|
andrewm@46
|
287 mapping->setUpVelocity(i, upVelocities_[i]);
|
andrewm@46
|
288 mapping->setDownNote(i, downNotes_[i]);
|
andrewm@46
|
289 mapping->setDownVelocity(i, downVelocities_[i]);
|
andrewm@46
|
290 }
|
andrewm@0
|
291 }
|
andrewm@46
|
292
|
andrewm@46
|
293 // Reset notes and velocities to defaults
|
andrewm@46
|
294 void TouchkeyReleaseAngleMappingFactory::clearNotes() {
|
andrewm@46
|
295 for(int i = 0; i < RELEASE_ANGLE_MAX_SEQUENCE_LENGTH; i++)
|
andrewm@46
|
296 upNotes_[i] = downNotes_[i] = upVelocities_[i] = downVelocities_[i] = 0;
|
andrewm@46
|
297 }
|