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 TouchkeyVibratoMappingFactory.cpp: factory 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 #include "TouchkeyVibratoMappingFactory.h"
|
andrewm@0
|
26 #include "TouchkeyVibratoMappingShortEditor.h"
|
andrewm@0
|
27
|
andrewm@0
|
28 // Class constants
|
andrewm@0
|
29 const int TouchkeyVibratoMappingFactory::kDefaultVibratoControl = MidiKeyboardSegment::kControlPitchWheel;
|
andrewm@0
|
30
|
andrewm@0
|
31 // Default constructor, containing a reference to the PianoKeyboard class.
|
andrewm@0
|
32
|
andrewm@0
|
33 TouchkeyVibratoMappingFactory::TouchkeyVibratoMappingFactory(PianoKeyboard &keyboard, MidiKeyboardSegment& segment) :
|
andrewm@7
|
34 TouchkeyBaseMappingFactory<TouchkeyVibratoMapping>(keyboard, segment),
|
andrewm@0
|
35 vibratoControl_(kDefaultVibratoControl),
|
andrewm@0
|
36 vibratoRange_(TouchkeyVibratoMapping::kDefaultVibratoRangeSemitones),
|
andrewm@0
|
37 vibratoPrescaler_(TouchkeyVibratoMapping::kDefaultVibratoPrescaler),
|
andrewm@0
|
38 vibratoTimeout_(TouchkeyVibratoMapping::kDefaultVibratoTimeout),
|
andrewm@0
|
39 vibratoOnsetThresholdX_(TouchkeyVibratoMapping::kDefaultVibratoThresholdX),
|
andrewm@0
|
40 vibratoOnsetThresholdY_(TouchkeyVibratoMapping::kDefaultVibratoThresholdY),
|
andrewm@0
|
41 vibratoOnsetRatioX_(TouchkeyVibratoMapping::kDefaultVibratoRatioX),
|
andrewm@0
|
42 vibratoOnsetRatioY_(TouchkeyVibratoMapping::kDefaultVibratoRatioY)
|
andrewm@0
|
43 {
|
andrewm@0
|
44 // Set up the MIDI converter to use pitch wheel
|
andrewm@0
|
45 configurePitchWheelVibrato();
|
andrewm@0
|
46 }
|
andrewm@0
|
47
|
andrewm@0
|
48 // ***** Destructor *****
|
andrewm@0
|
49
|
andrewm@0
|
50 TouchkeyVibratoMappingFactory::~TouchkeyVibratoMappingFactory() {
|
andrewm@0
|
51
|
andrewm@0
|
52 }
|
andrewm@0
|
53
|
andrewm@0
|
54 // ***** Accessors / Modifiers *****
|
andrewm@0
|
55
|
andrewm@0
|
56 void TouchkeyVibratoMappingFactory::setName(const string& name) {
|
andrewm@0
|
57 TouchkeyBaseMappingFactory<TouchkeyVibratoMapping>::setName(name);
|
andrewm@0
|
58 setVibratoControl(vibratoControl_);
|
andrewm@0
|
59 }
|
andrewm@0
|
60
|
andrewm@0
|
61 // ***** Vibrato Methods *****
|
andrewm@0
|
62
|
andrewm@0
|
63 void TouchkeyVibratoMappingFactory::setVibratoControl(int vibratoControl) {
|
andrewm@0
|
64 if(vibratoControl < 0 || vibratoControl >= MidiKeyboardSegment::kControlMax)
|
andrewm@0
|
65 return;
|
andrewm@0
|
66
|
andrewm@0
|
67 // Update the variable which affects future mappings
|
andrewm@0
|
68 vibratoControl_ = vibratoControl;
|
andrewm@0
|
69
|
andrewm@0
|
70 if(vibratoControl_ == MidiKeyboardSegment::kControlPitchWheel)
|
andrewm@0
|
71 configurePitchWheelVibrato();
|
andrewm@0
|
72 else
|
andrewm@0
|
73 configureControlChangeVibrato();
|
andrewm@0
|
74 }
|
andrewm@0
|
75
|
andrewm@0
|
76 void TouchkeyVibratoMappingFactory::setVibratoRange(float range, bool updateCurrent) {
|
andrewm@0
|
77 /*if(updateCurrent) {
|
andrewm@0
|
78 // Send new range to all active mappings
|
andrewm@0
|
79 // TODO: mutex protect
|
andrewm@0
|
80 std::map<int, mapping_pair>::iterator it = mappings_.begin();
|
andrewm@0
|
81 while(it != mappings_.end()) {
|
andrewm@0
|
82 // Tell this mapping to update its range
|
andrewm@0
|
83 TouchkeyVibratoMapping *mapping = it->second.first;
|
andrewm@0
|
84 mapping->setRange(rangeSemitones);
|
andrewm@0
|
85 it++;
|
andrewm@0
|
86 }
|
andrewm@0
|
87 }*/
|
andrewm@0
|
88
|
andrewm@0
|
89 // Update the variable which affects future mappings
|
andrewm@0
|
90 vibratoRange_ = range;
|
andrewm@0
|
91 if(vibratoRange_ < 0.01)
|
andrewm@0
|
92 vibratoRange_ = 0.01;
|
andrewm@0
|
93 if(vibratoRange_ > 127.0)
|
andrewm@0
|
94 vibratoRange_ = 127.0;
|
andrewm@0
|
95 }
|
andrewm@0
|
96
|
andrewm@0
|
97 void TouchkeyVibratoMappingFactory::setVibratoPrescaler(float prescaler, bool updateCurrent) {
|
andrewm@0
|
98 /*if(updateCurrent) {
|
andrewm@0
|
99 // Send new range to all active mappings
|
andrewm@0
|
100 // TODO: mutex protect
|
andrewm@0
|
101 std::map<int, mapping_pair>::iterator it = mappings_.begin();
|
andrewm@0
|
102 while(it != mappings_.end()) {
|
andrewm@0
|
103 // Tell this mapping to update its range
|
andrewm@0
|
104 TouchkeyVibratoMapping *mapping = it->second.first;
|
andrewm@0
|
105 mapping->setPrescaler(prescaler);
|
andrewm@0
|
106 it++;
|
andrewm@0
|
107 }
|
andrewm@0
|
108 }*/
|
andrewm@0
|
109
|
andrewm@0
|
110 // Update the variable which affects future mappings
|
andrewm@0
|
111 vibratoPrescaler_ = prescaler;
|
andrewm@0
|
112 }
|
andrewm@0
|
113
|
andrewm@0
|
114 void TouchkeyVibratoMappingFactory::setVibratoThreshold(float threshold, bool updateCurrent) {
|
andrewm@0
|
115 vibratoOnsetThresholdX_ = threshold;
|
andrewm@0
|
116 if(vibratoOnsetThresholdX_ < 0)
|
andrewm@0
|
117 vibratoOnsetThresholdX_ = 0;
|
andrewm@0
|
118 if(vibratoOnsetThresholdX_ > 1.0)
|
andrewm@0
|
119 vibratoOnsetThresholdX_ = 1.0;
|
andrewm@0
|
120 }
|
andrewm@0
|
121
|
andrewm@0
|
122 void TouchkeyVibratoMappingFactory::setVibratoThresholds(float thresholdX, float thresholdY, float ratioX, float ratioY, bool updateCurrent) {
|
andrewm@0
|
123 /*if(updateCurrent) {
|
andrewm@0
|
124 // Send new range to all active mappings
|
andrewm@0
|
125 // TODO: mutex protect
|
andrewm@0
|
126 std::map<int, mapping_pair>::iterator it = mappings_.begin();
|
andrewm@0
|
127 while(it != mappings_.end()) {
|
andrewm@0
|
128 // Tell this mapping to update its range
|
andrewm@0
|
129 TouchkeyVibratoMapping *mapping = it->second.first;
|
andrewm@0
|
130 mapping->setThresholds(thresholdX, thresholdY, ratioX, ratioY);
|
andrewm@0
|
131 it++;
|
andrewm@0
|
132 }
|
andrewm@0
|
133 }*/
|
andrewm@0
|
134
|
andrewm@0
|
135 // Update the variables which affect future mappings
|
andrewm@0
|
136 vibratoOnsetThresholdX_ = thresholdX;
|
andrewm@0
|
137 vibratoOnsetThresholdY_ = thresholdY;
|
andrewm@0
|
138 vibratoOnsetRatioX_ = ratioX;
|
andrewm@0
|
139 vibratoOnsetRatioY_ = ratioY;
|
andrewm@0
|
140 }
|
andrewm@0
|
141
|
andrewm@0
|
142 void TouchkeyVibratoMappingFactory::setVibratoTimeout(timestamp_diff_type timeout, bool updateCurrent) {
|
andrewm@0
|
143 /*if(updateCurrent) {
|
andrewm@0
|
144 // Send new range to all active mappings
|
andrewm@0
|
145 // TODO: mutex protect
|
andrewm@0
|
146 std::map<int, mapping_pair>::iterator it = mappings_.begin();
|
andrewm@0
|
147 while(it != mappings_.end()) {
|
andrewm@0
|
148 // Tell this mapping to update its range
|
andrewm@0
|
149 TouchkeyVibratoMapping *mapping = it->second.first;
|
andrewm@0
|
150 mapping->setTimeout(timeout);
|
andrewm@0
|
151 it++;
|
andrewm@0
|
152 }
|
andrewm@0
|
153 }*/
|
andrewm@0
|
154
|
andrewm@0
|
155 // Update the variable which affects future mappings
|
andrewm@0
|
156 vibratoTimeout_ = timeout;
|
andrewm@0
|
157 }
|
andrewm@0
|
158
|
andrewm@49
|
159 #ifndef TOUCHKEYS_NO_GUI
|
andrewm@0
|
160 // ***** GUI Support *****
|
andrewm@0
|
161 MappingEditorComponent* TouchkeyVibratoMappingFactory::createBasicEditor() {
|
andrewm@0
|
162 return new TouchkeyVibratoMappingShortEditor(*this);
|
andrewm@0
|
163 }
|
andrewm@49
|
164 #endif
|
andrewm@49
|
165
|
andrewm@49
|
166 // ****** OSC Control Support ******
|
andrewm@49
|
167 OscMessage* TouchkeyVibratoMappingFactory::oscControlMethod(const char *path, const char *types,
|
andrewm@49
|
168 int numValues, lo_arg **values, void *data) {
|
andrewm@49
|
169 if(!strcmp(path, "/set-vibrato-control")) {
|
andrewm@49
|
170 // Change the vibrato control
|
andrewm@49
|
171 if(numValues > 0) {
|
andrewm@49
|
172 if(types[0] == 'i') {
|
andrewm@49
|
173 setVibratoControl(values[0]->i);
|
andrewm@49
|
174 return OscTransmitter::createSuccessMessage();
|
andrewm@49
|
175 }
|
andrewm@49
|
176 }
|
andrewm@49
|
177 }
|
andrewm@49
|
178 else if(!strcmp(path, "/set-vibrato-range")) {
|
andrewm@49
|
179 // Change the vibrato range in semitones
|
andrewm@49
|
180 if(numValues > 0) {
|
andrewm@49
|
181 if(types[0] == 'f') {
|
andrewm@49
|
182 setVibratoRange(values[0]->f);
|
andrewm@49
|
183 return OscTransmitter::createSuccessMessage();
|
andrewm@49
|
184 }
|
andrewm@49
|
185 }
|
andrewm@49
|
186 }
|
andrewm@49
|
187 else if(!strcmp(path, "/set-vibrato-prescaler")) {
|
andrewm@49
|
188 // Change the vibrato prescaler
|
andrewm@49
|
189 if(numValues > 0) {
|
andrewm@49
|
190 if(types[0] == 'f') {
|
andrewm@49
|
191 setVibratoPrescaler(values[0]->f);
|
andrewm@49
|
192 return OscTransmitter::createSuccessMessage();
|
andrewm@49
|
193 }
|
andrewm@49
|
194 }
|
andrewm@49
|
195 }
|
andrewm@49
|
196 else if(!strcmp(path, "/set-vibrato-timeout")) {
|
andrewm@49
|
197 // Change the vibrato timeout
|
andrewm@49
|
198 if(numValues > 0) {
|
andrewm@49
|
199 if(types[0] == 'f') {
|
andrewm@49
|
200 setVibratoTimeout(values[0]->f);
|
andrewm@49
|
201 return OscTransmitter::createSuccessMessage();
|
andrewm@49
|
202 }
|
andrewm@49
|
203 }
|
andrewm@49
|
204 }
|
andrewm@49
|
205 else if(!strcmp(path, "/set-vibrato-threshold")) {
|
andrewm@49
|
206 // Change the vibrato threshold
|
andrewm@49
|
207 if(numValues > 0) {
|
andrewm@49
|
208 if(types[0] == 'f') {
|
andrewm@49
|
209 setVibratoThreshold(values[0]->f);
|
andrewm@49
|
210 return OscTransmitter::createSuccessMessage();
|
andrewm@49
|
211 }
|
andrewm@49
|
212 }
|
andrewm@49
|
213 }
|
andrewm@49
|
214
|
andrewm@49
|
215 // If no match, check the base class
|
andrewm@49
|
216 return TouchkeyBaseMappingFactory<TouchkeyVibratoMapping>::oscControlMethod(path, types, numValues, values, data);
|
andrewm@49
|
217 }
|
andrewm@0
|
218
|
andrewm@35
|
219
|
andrewm@35
|
220 // ****** Preset Save/Load ******
|
andrewm@35
|
221 XmlElement* TouchkeyVibratoMappingFactory::getPreset() {
|
andrewm@35
|
222 PropertySet properties;
|
andrewm@35
|
223
|
andrewm@35
|
224 storeCommonProperties(properties);
|
andrewm@35
|
225 properties.setValue("vibratoControl", vibratoControl_);
|
andrewm@35
|
226 properties.setValue("vibratoRange", vibratoRange_);
|
andrewm@35
|
227 properties.setValue("vibratoPrescaler", vibratoPrescaler_);
|
andrewm@35
|
228 properties.setValue("vibratoTimeout", vibratoTimeout_);
|
andrewm@35
|
229 properties.setValue("vibratoOnsetThresholdX", vibratoOnsetThresholdX_);
|
andrewm@35
|
230 properties.setValue("vibratoOnsetThresholdY", vibratoOnsetThresholdY_);
|
andrewm@35
|
231 properties.setValue("vibratoOnsetRatioX", vibratoOnsetRatioX_);
|
andrewm@35
|
232 properties.setValue("vibratoOnsetRatioY", vibratoOnsetRatioY_);
|
andrewm@35
|
233
|
andrewm@35
|
234 XmlElement* preset = properties.createXml("MappingFactory");
|
andrewm@35
|
235 preset->setAttribute("type", "Vibrato");
|
andrewm@35
|
236
|
andrewm@35
|
237 return preset;
|
andrewm@35
|
238 }
|
andrewm@35
|
239
|
andrewm@35
|
240 bool TouchkeyVibratoMappingFactory::loadPreset(XmlElement const* preset) {
|
andrewm@35
|
241 if(preset == 0)
|
andrewm@35
|
242 return false;
|
andrewm@35
|
243
|
andrewm@35
|
244 PropertySet properties;
|
andrewm@35
|
245 properties.restoreFromXml(*preset);
|
andrewm@35
|
246
|
andrewm@35
|
247 if(!loadCommonProperties(properties))
|
andrewm@35
|
248 return false;
|
andrewm@35
|
249 if(!properties.containsKey("vibratoControl") ||
|
andrewm@35
|
250 !properties.containsKey("vibratoRange") ||
|
andrewm@35
|
251 !properties.containsKey("vibratoPrescaler") ||
|
andrewm@35
|
252 !properties.containsKey("vibratoTimeout") ||
|
andrewm@35
|
253 !properties.containsKey("vibratoOnsetThresholdX") ||
|
andrewm@35
|
254 !properties.containsKey("vibratoOnsetThresholdY") ||
|
andrewm@35
|
255 !properties.containsKey("vibratoOnsetRatioX") ||
|
andrewm@35
|
256 !properties.containsKey("vibratoOnsetRatioY"))
|
andrewm@35
|
257 return false;
|
andrewm@35
|
258
|
andrewm@35
|
259 vibratoControl_ = properties.getDoubleValue("vibratoControl");
|
andrewm@35
|
260 vibratoRange_ = properties.getDoubleValue("vibratoRange");
|
andrewm@35
|
261 vibratoPrescaler_ = properties.getDoubleValue("vibratoPrescaler");
|
andrewm@35
|
262 vibratoTimeout_ = properties.getDoubleValue("vibratoTimeout");
|
andrewm@35
|
263 vibratoOnsetThresholdX_ = properties.getDoubleValue("vibratoOnsetThresholdX");
|
andrewm@35
|
264 vibratoOnsetThresholdY_ = properties.getDoubleValue("vibratoOnsetThresholdY");
|
andrewm@35
|
265 vibratoOnsetRatioX_ = properties.getDoubleValue("vibratoOnsetRatioX");
|
andrewm@35
|
266 vibratoOnsetRatioY_ = properties.getDoubleValue("vibratoOnsetRatioY");
|
andrewm@35
|
267
|
andrewm@35
|
268 // Update MIDI information; this doesn't actually change the controller
|
andrewm@35
|
269 // (which is already set) but it adds a listener and updates the ranges
|
andrewm@35
|
270 setVibratoControl(vibratoControl_);
|
andrewm@35
|
271
|
andrewm@35
|
272 return true;
|
andrewm@35
|
273 }
|
andrewm@35
|
274
|
andrewm@35
|
275
|
andrewm@0
|
276 // ***** Private Methods *****
|
andrewm@0
|
277
|
andrewm@0
|
278 // Set the initial parameters for a new mapping
|
andrewm@0
|
279 void TouchkeyVibratoMappingFactory::initializeMappingParameters(int noteNumber, TouchkeyVibratoMapping *mapping) {
|
andrewm@0
|
280 mapping->setRange(vibratoRange_);
|
andrewm@0
|
281 mapping->setPrescaler(vibratoPrescaler_);
|
andrewm@0
|
282 mapping->setThresholds(vibratoOnsetThresholdX_, vibratoOnsetThresholdY_, vibratoOnsetRatioX_, vibratoOnsetRatioY_);
|
andrewm@0
|
283 mapping->setTimeout(vibratoTimeout_);
|
andrewm@0
|
284 }
|
andrewm@0
|
285
|
andrewm@0
|
286 // Configure the OSC-MIDI converter to handle pitchwheel vibrato
|
andrewm@0
|
287 void TouchkeyVibratoMappingFactory::configurePitchWheelVibrato() {
|
andrewm@7
|
288 // Range of 0 indicates special case of using global pitch wheel range
|
andrewm@7
|
289 setMidiParameters(MidiKeyboardSegment::kControlPitchWheel, 0.0, 0.0, 0.0);
|
andrewm@0
|
290
|
andrewm@0
|
291 if(midiConverter_ != 0) {
|
andrewm@0
|
292 midiConverter_->listenToIncomingControl(MidiKeyboardSegment::kControlPitchWheel);
|
andrewm@0
|
293 }
|
andrewm@0
|
294 }
|
andrewm@0
|
295
|
andrewm@0
|
296 // Configure the OSC-MIDI converter to handle vibrato based on a CC
|
andrewm@0
|
297 void TouchkeyVibratoMappingFactory::configureControlChangeVibrato() {
|
andrewm@0
|
298 setMidiParameters(vibratoControl_, 0.0, 127.0, 0.0, 0, 0, 127, 0, false, OscMidiConverter::kOutOfRangeExtrapolate);
|
andrewm@0
|
299
|
andrewm@0
|
300 if(midiConverter_ != 0) {
|
andrewm@0
|
301 midiConverter_->listenToIncomingControl(vibratoControl_);
|
andrewm@0
|
302 }
|
andrewm@0
|
303 }
|
andrewm@0
|
304
|
andrewm@0
|
305
|