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