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 TouchkeyBaseMappingFactory.h: base factory class specifically for
|
andrewm@0
|
21 TouchKeys mappings. It provides a collection of useful methods for
|
andrewm@0
|
22 creating and destroying individual mappings on touch/MIDI onset and
|
andrewm@0
|
23 release, as well as parameter adjustment code and OSC to MIDI conversion.
|
andrewm@0
|
24 This is a template class that must be created with a specific Mapping
|
andrewm@0
|
25 subclass.
|
andrewm@0
|
26 */
|
andrewm@0
|
27
|
andrewm@0
|
28 #ifndef __TouchKeys__TouchkeyBaseMappingFactory__
|
andrewm@0
|
29 #define __TouchKeys__TouchkeyBaseMappingFactory__
|
andrewm@0
|
30
|
andrewm@0
|
31 #include <iostream>
|
andrewm@0
|
32 #include <map>
|
andrewm@0
|
33 #include <sstream>
|
andrewm@0
|
34 #include "MappingFactory.h"
|
andrewm@0
|
35 #include "../TouchKeys/OscMidiConverter.h"
|
andrewm@0
|
36 #include "../TouchKeys/MidiOutputController.h"
|
andrewm@0
|
37 #include "../TouchKeys/MidiKeyboardSegment.h"
|
andrewm@0
|
38 #include "MappingScheduler.h"
|
andrewm@0
|
39
|
andrewm@0
|
40 #undef DEBUG_TOUCHKEY_BASE_MAPPING_FACTORY
|
andrewm@0
|
41
|
andrewm@0
|
42 // Base class for mapping factories that meet the following criteria:
|
andrewm@0
|
43 // * MIDI and TouchKeys data (no continuous angle)
|
andrewm@0
|
44 // * Mappings begin when either or touch or MIDI starts and end when both finish
|
andrewm@0
|
45 // * Each mapping object affects a single note
|
andrewm@0
|
46
|
andrewm@0
|
47 template <class MappingType>
|
andrewm@0
|
48 class TouchkeyBaseMappingFactory : public MappingFactory {
|
andrewm@0
|
49
|
andrewm@0
|
50 public:
|
andrewm@0
|
51 // ***** Constructor *****
|
andrewm@0
|
52
|
andrewm@0
|
53 // Default constructor, containing a reference to the PianoKeyboard class.
|
andrewm@0
|
54 TouchkeyBaseMappingFactory(PianoKeyboard &keyboard, MidiKeyboardSegment& segment) :
|
andrewm@0
|
55 MappingFactory(keyboard), keyboardSegment_(segment), midiConverter_(0),
|
andrewm@0
|
56 controlName_(""),
|
andrewm@0
|
57 inputRangeMin_(0.0), inputRangeMax_(1.0), inputRangeCenter_(0.0),
|
andrewm@0
|
58 outOfRangeBehavior_(OscMidiConverter::kOutOfRangeClip),
|
andrewm@41
|
59 use14BitControl_(false),
|
andrewm@0
|
60 midiControllerNumber_(-1), bypassed_(false), activeNotes_(0x0FFF) {}
|
andrewm@0
|
61
|
andrewm@0
|
62 // ***** Destructor *****
|
andrewm@0
|
63
|
andrewm@0
|
64 virtual ~TouchkeyBaseMappingFactory() {
|
andrewm@0
|
65 removeAllMappings();
|
andrewm@0
|
66 if(midiConverter_ != 0 && controlName_ != "")
|
andrewm@0
|
67 midiConverter_->removeControl(controlName_.c_str());
|
andrewm@0
|
68 if(midiControllerNumber_ >= 0) {
|
andrewm@0
|
69 keyboardSegment_.releaseOscMidiConverter(midiControllerNumber_);
|
andrewm@0
|
70 }
|
andrewm@0
|
71 }
|
andrewm@0
|
72
|
andrewm@0
|
73 // ***** Accessors / Modifiers *****
|
andrewm@0
|
74
|
andrewm@0
|
75 // Return the keyboard segment associated with this factory
|
andrewm@0
|
76 MidiKeyboardSegment& segment() { return keyboardSegment_; }
|
andrewm@0
|
77
|
andrewm@0
|
78 // Look up a mapping with the given note number
|
andrewm@0
|
79 virtual MappingType* mapping(int noteNumber) {
|
andrewm@0
|
80 ScopedLock sl(mappingsMutex_);
|
andrewm@0
|
81 if(mappings_.count(noteNumber) == 0)
|
andrewm@0
|
82 return 0;
|
andrewm@0
|
83 return mappings_[noteNumber];
|
andrewm@0
|
84 }
|
andrewm@0
|
85
|
andrewm@0
|
86 // Return a list of all active notes
|
andrewm@0
|
87 virtual std::vector<int> activeMappings() {
|
andrewm@0
|
88 ScopedLock sl(mappingsMutex_);
|
andrewm@0
|
89 std::vector<int> keys;
|
andrewm@0
|
90 typename std::map<int, MappingType*>::iterator it = mappings_.begin();
|
andrewm@0
|
91 while(it != mappings_.end()) {
|
andrewm@0
|
92 int nextKey = (it++)->first;
|
andrewm@0
|
93 keys.push_back(nextKey);
|
andrewm@0
|
94 }
|
andrewm@0
|
95 return keys;
|
andrewm@0
|
96 }
|
andrewm@0
|
97
|
andrewm@0
|
98 // Remove all active mappings
|
andrewm@0
|
99 virtual void removeAllMappings() {
|
andrewm@0
|
100 ScopedLock sl(mappingsMutex_);
|
andrewm@0
|
101 typename std::map<int, MappingType*>::iterator it = mappings_.begin();
|
andrewm@0
|
102
|
andrewm@0
|
103 while(it != mappings_.end()) {
|
andrewm@0
|
104 // Delete everybody in the container
|
andrewm@0
|
105 MappingType *mapping = it->second;
|
andrewm@0
|
106 #ifdef NEW_MAPPING_SCHEDULER
|
andrewm@0
|
107 mapping->disengage(true);
|
andrewm@0
|
108 //keyboard_.mappingScheduler().unscheduleAndDelete(mapping);
|
andrewm@0
|
109 #else
|
andrewm@0
|
110 mapping->disengage();
|
andrewm@0
|
111 delete mapping;
|
andrewm@0
|
112 #endif
|
andrewm@0
|
113 it++;
|
andrewm@0
|
114 }
|
andrewm@0
|
115
|
andrewm@0
|
116 // Now clear the container
|
andrewm@0
|
117 mappings_.clear();
|
andrewm@0
|
118 }
|
andrewm@0
|
119
|
andrewm@0
|
120 // Callback from mapping to say it's finished
|
andrewm@0
|
121 virtual void mappingFinished(int noteNumber) {
|
andrewm@0
|
122 ScopedLock sl(mappingsMutex_);
|
andrewm@0
|
123 removeMapping(noteNumber);
|
andrewm@0
|
124 }
|
andrewm@0
|
125
|
andrewm@0
|
126 // Suspend messages from a particular note
|
andrewm@0
|
127 virtual void suspendMapping(int noteNumber) {
|
andrewm@0
|
128 ScopedLock sl(mappingsMutex_);
|
andrewm@0
|
129 if(mappings_.count(noteNumber) == 0)
|
andrewm@0
|
130 return;
|
andrewm@0
|
131 mappings_[noteNumber]->suspend();
|
andrewm@0
|
132 }
|
andrewm@0
|
133
|
andrewm@0
|
134 // Suspend messages from all notes
|
andrewm@0
|
135 virtual void suspendAllMappings() {
|
andrewm@0
|
136 ScopedLock sl(mappingsMutex_);
|
andrewm@0
|
137 typename std::map<int, MappingType*>::iterator it = mappings_.begin();
|
andrewm@0
|
138
|
andrewm@0
|
139 while(it != mappings_.end()) {
|
andrewm@0
|
140 //std::cout << "suspending mapping on note " << it->first << std::endl;
|
andrewm@0
|
141 it->second->suspend();
|
andrewm@0
|
142 it++;
|
andrewm@0
|
143 }
|
andrewm@0
|
144 }
|
andrewm@0
|
145
|
andrewm@0
|
146 // Resume messages from a particular note
|
andrewm@0
|
147 virtual void resumeMapping(int noteNumber, bool resend) {
|
andrewm@0
|
148 ScopedLock sl(mappingsMutex_);
|
andrewm@0
|
149 if(mappings_.count(noteNumber) == 0)
|
andrewm@0
|
150 return;
|
andrewm@0
|
151 //std::cout << "resuming mapping on note " << noteNumber << std::endl;
|
andrewm@0
|
152 mappings_[noteNumber]->resume(resend);
|
andrewm@0
|
153 }
|
andrewm@0
|
154
|
andrewm@0
|
155 // Resume messages on all notes
|
andrewm@0
|
156 virtual void resumeAllMappings(bool resend) {
|
andrewm@0
|
157 ScopedLock sl(mappingsMutex_);
|
andrewm@0
|
158 typename std::map<int, MappingType*>::iterator it = mappings_.begin();
|
andrewm@0
|
159
|
andrewm@0
|
160 while(it != mappings_.end()) {
|
andrewm@0
|
161 it->second->resume(resend);
|
andrewm@0
|
162 it++;
|
andrewm@0
|
163 }
|
andrewm@0
|
164 }
|
andrewm@0
|
165
|
andrewm@0
|
166 // Whether this mapping is bypassed
|
andrewm@0
|
167 virtual int bypassed() {
|
andrewm@0
|
168 return bypassed_ ? kBypassOn : kBypassOff;
|
andrewm@0
|
169 }
|
andrewm@0
|
170
|
andrewm@0
|
171 // Set whether the mapping is bypassed or not
|
andrewm@0
|
172 virtual void setBypassed(bool bypass) {
|
andrewm@0
|
173 bypassed_ = bypass;
|
andrewm@0
|
174 }
|
andrewm@0
|
175
|
andrewm@0
|
176 // ***** Class-Specific Methods *****
|
andrewm@0
|
177
|
andrewm@0
|
178 virtual void setMidiParameters(int controller, float inputMinValue, float inputMaxValue, float inputCenterValue,
|
andrewm@0
|
179 int outputDefaultValue = -1, int outputMinValue = -1, int outputMaxValue = -1,
|
andrewm@0
|
180 int outputCenterValue = -1, bool use14BitControl = false,
|
andrewm@0
|
181 int outOfRangeBehavior = OscMidiConverter::kOutOfRangeClip) {
|
andrewm@0
|
182 if(controller < 0)
|
andrewm@0
|
183 return;
|
andrewm@0
|
184
|
andrewm@0
|
185 inputRangeMin_ = inputMinValue;
|
andrewm@0
|
186 inputRangeMax_ = inputMaxValue;
|
andrewm@0
|
187 inputRangeCenter_ = inputCenterValue;
|
andrewm@0
|
188 outOfRangeBehavior_ = outOfRangeBehavior;
|
andrewm@41
|
189 use14BitControl_ = use14BitControl;
|
andrewm@0
|
190
|
andrewm@0
|
191 // Remove listener on previous name (if any)
|
andrewm@0
|
192 //midiConverter_.removeAllControls();
|
andrewm@0
|
193 if(midiControllerNumber_ >= 0 && controller != midiControllerNumber_) {
|
andrewm@0
|
194 keyboardSegment_.releaseOscMidiConverter(midiControllerNumber_);
|
andrewm@0
|
195 midiConverter_ = keyboardSegment_.acquireOscMidiConverter(controller);
|
andrewm@0
|
196 }
|
andrewm@0
|
197 else if(midiControllerNumber_ < 0 || midiConverter_ == 0) {
|
andrewm@0
|
198 midiConverter_ = keyboardSegment_.acquireOscMidiConverter(controller);
|
andrewm@0
|
199 }
|
andrewm@0
|
200 midiControllerNumber_ = controller;
|
andrewm@0
|
201
|
andrewm@0
|
202 midiConverter_->setMidiMessageType(outputDefaultValue, outputMinValue, outputMaxValue, outputCenterValue, use14BitControl);
|
andrewm@0
|
203
|
andrewm@0
|
204 // Add listener for new name
|
andrewm@0
|
205 if(controlName_ != "")
|
andrewm@0
|
206 midiConverter_->addControl(controlName_.c_str(), 1, inputRangeMin_, inputRangeMax_, inputRangeCenter_, outOfRangeBehavior_);
|
andrewm@0
|
207 }
|
andrewm@0
|
208
|
andrewm@0
|
209 virtual string const getName() { return controlName_; }
|
andrewm@0
|
210
|
andrewm@0
|
211 virtual void setName(const string& name) {
|
andrewm@0
|
212 if(name == "")
|
andrewm@0
|
213 return;
|
andrewm@0
|
214 std::stringstream ss;
|
andrewm@0
|
215
|
andrewm@0
|
216 // Remove listener on previous name (if any)
|
andrewm@0
|
217 if(midiConverter_ != 0 && controlName_ != "")
|
andrewm@0
|
218 midiConverter_->removeControl(controlName_.c_str());
|
andrewm@0
|
219
|
andrewm@0
|
220 ss << "/touchkeys/mapping/segment" << (int)keyboardSegment_.outputPort() << "/" << name;
|
andrewm@0
|
221 controlName_ = ss.str();
|
andrewm@0
|
222
|
andrewm@0
|
223 // Add listener for new name
|
andrewm@0
|
224 if(midiConverter_ != 0)
|
andrewm@0
|
225 midiConverter_->addControl(controlName_.c_str(), 1, inputRangeMin_, inputRangeMax_, inputRangeCenter_, outOfRangeBehavior_);
|
andrewm@0
|
226 }
|
andrewm@0
|
227
|
andrewm@0
|
228 // Set which keys should have this mapping enable
|
andrewm@0
|
229 virtual void setActiveNotes(unsigned int notes) {
|
andrewm@0
|
230 activeNotes_ = notes;
|
andrewm@0
|
231 }
|
andrewm@0
|
232
|
andrewm@33
|
233 // ****** Preset Save/Load ******
|
andrewm@33
|
234
|
andrewm@33
|
235 // These generate XML settings files and reload settings from them
|
andrewm@33
|
236
|
andrewm@33
|
237 virtual XmlElement* getPreset() {
|
andrewm@34
|
238 PropertySet properties;
|
andrewm@34
|
239 storeCommonProperties(properties);
|
andrewm@34
|
240
|
andrewm@34
|
241 XmlElement* presetElement = properties.createXml("MappingFactory");
|
andrewm@33
|
242 presetElement->setAttribute("type", "Unknown");
|
andrewm@33
|
243 return presetElement;
|
andrewm@33
|
244 }
|
andrewm@33
|
245
|
andrewm@34
|
246 virtual bool loadPreset(XmlElement const* preset) {
|
andrewm@34
|
247 if(preset == 0)
|
andrewm@34
|
248 return false;
|
andrewm@34
|
249
|
andrewm@34
|
250 PropertySet properties;
|
andrewm@34
|
251 properties.restoreFromXml(*preset);
|
andrewm@34
|
252
|
andrewm@34
|
253 if(!loadCommonProperties(properties))
|
andrewm@34
|
254 return false;
|
andrewm@34
|
255 return true;
|
andrewm@34
|
256 }
|
andrewm@33
|
257
|
andrewm@0
|
258 // ***** State Updaters *****
|
andrewm@0
|
259
|
andrewm@0
|
260 // These are called by PianoKey whenever certain events occur that might
|
andrewm@0
|
261 // merit the start and stop of a mapping. What is done with them depends on
|
andrewm@0
|
262 // the particular factory subclass.
|
andrewm@0
|
263
|
andrewm@0
|
264 // Touch becomes active on a key where it wasn't previously
|
andrewm@0
|
265 virtual void touchBegan(int noteNumber, bool midiNoteIsOn, bool keyMotionActive,
|
andrewm@0
|
266 Node<KeyTouchFrame>* touchBuffer,
|
andrewm@0
|
267 Node<key_position>* positionBuffer,
|
andrewm@0
|
268 KeyPositionTracker* positionTracker) {
|
andrewm@0
|
269 ScopedLock sl(mappingsMutex_);
|
andrewm@0
|
270 // Add a new mapping if one doesn't exist already
|
andrewm@0
|
271 if(mappings_.count(noteNumber) == 0) {
|
andrewm@0
|
272 #ifdef DEBUG_TOUCHKEY_BASE_MAPPING_FACTORY
|
andrewm@0
|
273 std::cout << "Note " << noteNumber << ": adding mapping (touch)\n";
|
andrewm@0
|
274 #endif
|
andrewm@0
|
275 int moduloNoteNumber = noteNumber % 12;
|
andrewm@0
|
276 if((activeNotes_ & (1 << moduloNoteNumber)) && !bypassed_)
|
andrewm@0
|
277 addMapping(noteNumber, touchBuffer, positionBuffer, positionTracker);
|
andrewm@0
|
278 }
|
andrewm@0
|
279 }
|
andrewm@0
|
280
|
andrewm@0
|
281 // Touch ends on a key where it wasn't previously
|
andrewm@0
|
282 virtual void touchEnded(int noteNumber, bool midiNoteIsOn, bool keyMotionActive,
|
andrewm@0
|
283 Node<KeyTouchFrame>* touchBuffer,
|
andrewm@0
|
284 Node<key_position>* positionBuffer,
|
andrewm@0
|
285 KeyPositionTracker* positionTracker) {
|
andrewm@0
|
286 ScopedLock sl(mappingsMutex_);
|
andrewm@0
|
287 // If a mapping exists but the MIDI note is off, remove the mapping
|
andrewm@0
|
288 if(mappings_.count(noteNumber) != 0 && !midiNoteIsOn) {
|
andrewm@0
|
289 #ifdef DEBUG_TOUCHKEY_BASE_MAPPING_FACTORY
|
andrewm@0
|
290 std::cout << "Note " << noteNumber << ": removing mapping (touch)\n";
|
andrewm@0
|
291 #endif
|
andrewm@0
|
292 if(mappings_[noteNumber]->requestFinish())
|
andrewm@0
|
293 removeMapping(noteNumber);
|
andrewm@0
|
294 }
|
andrewm@0
|
295 }
|
andrewm@0
|
296
|
andrewm@0
|
297 // MIDI note on for a key
|
andrewm@0
|
298 virtual void midiNoteOn(int noteNumber, bool touchIsOn, bool keyMotionActive,
|
andrewm@0
|
299 Node<KeyTouchFrame>* touchBuffer,
|
andrewm@0
|
300 Node<key_position>* positionBuffer,
|
andrewm@0
|
301 KeyPositionTracker* positionTracker) {
|
andrewm@0
|
302 ScopedLock sl(mappingsMutex_);
|
andrewm@0
|
303 // Add a new mapping if one doesn't exist already
|
andrewm@0
|
304 if(mappings_.count(noteNumber) == 0) {
|
andrewm@0
|
305 #ifdef DEBUG_TOUCHKEY_BASE_MAPPING_FACTORY
|
andrewm@0
|
306 std::cout << "Note " << noteNumber << ": adding mapping (MIDI)\n";
|
andrewm@0
|
307 #endif
|
andrewm@0
|
308 int moduloNoteNumber = noteNumber % 12;
|
andrewm@0
|
309 if((activeNotes_ & (1 << moduloNoteNumber)) && !bypassed_)
|
andrewm@0
|
310 addMapping(noteNumber, touchBuffer, positionBuffer, positionTracker);
|
andrewm@0
|
311 }
|
andrewm@0
|
312 }
|
andrewm@0
|
313
|
andrewm@0
|
314 // MIDI note off for a key
|
andrewm@0
|
315 virtual void midiNoteOff(int noteNumber, bool touchIsOn, bool keyMotionActive,
|
andrewm@0
|
316 Node<KeyTouchFrame>* touchBuffer,
|
andrewm@0
|
317 Node<key_position>* positionBuffer,
|
andrewm@0
|
318 KeyPositionTracker* positionTracker) {
|
andrewm@0
|
319 ScopedLock sl(mappingsMutex_);
|
andrewm@0
|
320 // If a mapping exists but the touch is off, remove the mapping
|
andrewm@0
|
321 if(mappings_.count(noteNumber) != 0 && !touchIsOn) {
|
andrewm@0
|
322 #ifdef DEBUG_TOUCHKEY_BASE_MAPPING_FACTORY
|
andrewm@0
|
323 std::cout << "Note " << noteNumber << ": removing mapping (MIDI)\n";
|
andrewm@0
|
324 #endif
|
andrewm@0
|
325 if(mappings_[noteNumber]->requestFinish())
|
andrewm@0
|
326 removeMapping(noteNumber);
|
andrewm@0
|
327 }
|
andrewm@0
|
328 }
|
andrewm@0
|
329
|
andrewm@0
|
330 // Subclasses of this one won't care about these two methods:
|
andrewm@0
|
331
|
andrewm@0
|
332 // Key goes active from continuous key position
|
andrewm@0
|
333 virtual void keyMotionActive(int noteNumber, bool midiNoteIsOn, bool touchIsOn,
|
andrewm@0
|
334 Node<KeyTouchFrame>* touchBuffer,
|
andrewm@0
|
335 Node<key_position>* positionBuffer,
|
andrewm@0
|
336 KeyPositionTracker* positionTracker) {}
|
andrewm@0
|
337 // Key goes idle from continuous key position
|
andrewm@0
|
338 virtual void keyMotionIdle(int noteNumber, bool midiNoteIsOn, bool touchIsOn,
|
andrewm@0
|
339 Node<KeyTouchFrame>* touchBuffer,
|
andrewm@0
|
340 Node<key_position>* positionBuffer,
|
andrewm@0
|
341 KeyPositionTracker* positionTracker) {}
|
andrewm@0
|
342
|
andrewm@0
|
343 // But we do use this one to send out default values:
|
andrewm@0
|
344 virtual void noteWillBegin(int noteNumber, int midiChannel, int midiVelocity) {
|
andrewm@0
|
345 if(midiConverter_ == 0)
|
andrewm@0
|
346 return;
|
andrewm@0
|
347 midiConverter_->clearLastValues(midiChannel, true);
|
andrewm@0
|
348 //midiConverter_->sendDefaultValue(midiChannel);
|
andrewm@0
|
349 }
|
andrewm@0
|
350
|
andrewm@0
|
351
|
andrewm@0
|
352 protected:
|
andrewm@0
|
353 // ***** Protected Methods *****
|
andrewm@0
|
354
|
andrewm@0
|
355 // This method should be set by the subclass to initialize the parameters of
|
andrewm@0
|
356 // a new mapping.
|
andrewm@0
|
357 virtual void initializeMappingParameters(int noteNumber, MappingType *mapping) {}
|
andrewm@0
|
358
|
andrewm@34
|
359 // This method adds the common mapping properties to the given PropertySet
|
andrewm@34
|
360 void storeCommonProperties(PropertySet& properties) {
|
andrewm@34
|
361 properties.setValue("controlName", String(controlName_));
|
andrewm@34
|
362 properties.setValue("inputRangeMin", inputRangeMin_);
|
andrewm@34
|
363 properties.setValue("inputRangeMax", inputRangeMax_);
|
andrewm@34
|
364 properties.setValue("inputRangeCenter", inputRangeCenter_);
|
andrewm@34
|
365 properties.setValue("outOfRangeBehavior", outOfRangeBehavior_);
|
andrewm@34
|
366 properties.setValue("midiControllerNumber", midiControllerNumber_);
|
andrewm@34
|
367 properties.setValue("bypassed", bypassed_);
|
andrewm@34
|
368 properties.setValue("activeNotes", (int)activeNotes_);
|
andrewm@34
|
369 }
|
andrewm@34
|
370
|
andrewm@34
|
371 // This method loads the common mapping properties from the given PropertySet
|
andrewm@34
|
372 bool loadCommonProperties(PropertySet const& properties) {
|
andrewm@34
|
373 if(!properties.containsKey("controlName") ||
|
andrewm@34
|
374 !properties.containsKey("inputRangeMin") ||
|
andrewm@34
|
375 !properties.containsKey("inputRangeMax") ||
|
andrewm@34
|
376 !properties.containsKey("inputRangeCenter") ||
|
andrewm@34
|
377 !properties.containsKey("outOfRangeBehavior") ||
|
andrewm@34
|
378 !properties.containsKey("midiControllerNumber") ||
|
andrewm@34
|
379 !properties.containsKey("bypassed") ||
|
andrewm@34
|
380 !properties.containsKey("activeNotes")) {
|
andrewm@34
|
381 return false;
|
andrewm@34
|
382 }
|
andrewm@34
|
383
|
andrewm@34
|
384 // Setting the MIDI controller number needs to be done with
|
andrewm@34
|
385 // the setMidiParameters() method which will update midiControllerNumber_
|
andrewm@34
|
386 int tempMidiController = 1;
|
andrewm@34
|
387
|
andrewm@34
|
388 controlName_ = properties.getValue("controlName").toUTF8();
|
andrewm@34
|
389 inputRangeMin_ = properties.getDoubleValue("inputRangeMin");
|
andrewm@34
|
390 inputRangeMax_ = properties.getDoubleValue("inputRangeMax");
|
andrewm@34
|
391 inputRangeCenter_ = properties.getDoubleValue("inputRangeCenter");
|
andrewm@34
|
392 outOfRangeBehavior_ = properties.getIntValue("outOfRangeBehavior");
|
andrewm@34
|
393 tempMidiController = properties.getIntValue("midiControllerNumber");
|
andrewm@34
|
394 bypassed_ = properties.getBoolValue("bypassed");
|
andrewm@34
|
395 activeNotes_ = properties.getIntValue("activeNotes");
|
andrewm@34
|
396
|
andrewm@34
|
397 setMidiParameters(tempMidiController, inputRangeMin_, inputRangeMax_, inputRangeCenter_);
|
andrewm@34
|
398
|
andrewm@34
|
399 return true;
|
andrewm@34
|
400 }
|
andrewm@34
|
401
|
andrewm@0
|
402 private:
|
andrewm@0
|
403 // ***** Private Methods *****
|
andrewm@0
|
404
|
andrewm@0
|
405 // Add a new mapping
|
andrewm@0
|
406 void addMapping(int noteNumber,
|
andrewm@0
|
407 Node<KeyTouchFrame>* touchBuffer,
|
andrewm@0
|
408 Node<key_position>* positionBuffer,
|
andrewm@0
|
409 KeyPositionTracker* positionTracker) {
|
andrewm@0
|
410 // TODO: mutex
|
andrewm@0
|
411 removeMapping(noteNumber); // Free any mapping that's already present on this note
|
andrewm@0
|
412
|
andrewm@0
|
413 MappingType *mapping = new MappingType(keyboard_, this, noteNumber, touchBuffer,
|
andrewm@0
|
414 positionBuffer, positionTracker);
|
andrewm@0
|
415
|
andrewm@0
|
416 // Set parameters
|
andrewm@0
|
417 mapping->setName(controlName_);
|
andrewm@0
|
418 initializeMappingParameters(noteNumber, mapping);
|
andrewm@0
|
419
|
andrewm@0
|
420 // Save the mapping
|
andrewm@0
|
421 mappings_[noteNumber] = mapping;
|
andrewm@0
|
422
|
andrewm@0
|
423 // Finally, engage the new mapping
|
andrewm@0
|
424 mapping->engage();
|
andrewm@0
|
425 }
|
andrewm@0
|
426
|
andrewm@0
|
427 void removeMapping(int noteNumber) {
|
andrewm@0
|
428 // TODO: mutex
|
andrewm@0
|
429 if(mappings_.count(noteNumber) == 0)
|
andrewm@0
|
430 return;
|
andrewm@0
|
431 MappingType* mapping = mappings_[noteNumber];
|
andrewm@0
|
432 #ifdef NEW_MAPPING_SCHEDULER
|
andrewm@0
|
433 mapping->disengage(true);
|
andrewm@0
|
434 //keyboard_.mappingScheduler().unscheduleAndDelete(mapping);
|
andrewm@0
|
435 #else
|
andrewm@0
|
436 mapping->disengage();
|
andrewm@0
|
437 delete mapping;
|
andrewm@0
|
438 #endif
|
andrewm@0
|
439 mappings_.erase(noteNumber);
|
andrewm@0
|
440 }
|
andrewm@0
|
441
|
andrewm@0
|
442 protected:
|
andrewm@0
|
443 // State variables
|
andrewm@0
|
444 MidiKeyboardSegment& keyboardSegment_; // Segment of the keyboard that this mapping addresses
|
andrewm@0
|
445 OscMidiConverter *midiConverter_; // Object to convert OSC messages to MIDI
|
andrewm@0
|
446 std::map<int, MappingType*> mappings_; // Collection of active mappings
|
andrewm@0
|
447 CriticalSection mappingsMutex_; // Mutex protecting mappings from changes
|
andrewm@0
|
448
|
andrewm@0
|
449 std::string controlName_; // Name of the mapping
|
andrewm@0
|
450 float inputRangeMin_, inputRangeMax_; // Input ranges
|
andrewm@0
|
451 float inputRangeCenter_;
|
andrewm@0
|
452 int outOfRangeBehavior_; // What happens to out of range inputs
|
andrewm@41
|
453 bool use14BitControl_; // Whether to use a 14-bit control
|
andrewm@0
|
454
|
andrewm@0
|
455 int midiControllerNumber_; // Which controller to use
|
andrewm@0
|
456 bool bypassed_; // Whether the mapping has been bypassed by UI
|
andrewm@0
|
457 unsigned int activeNotes_; // Indication of which notes out of the 12 to use
|
andrewm@0
|
458 };
|
andrewm@0
|
459
|
andrewm@0
|
460 #endif /* defined(__TouchKeys__TouchkeyBaseMappingFactory__) */ |