annotate Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingFactory.cpp @ 56:b4a2d2ae43cf tip

merge
author Andrew McPherson <andrewm@eecs.qmul.ac.uk>
date Fri, 23 Nov 2018 15:48:14 +0000
parents 003236a1e29b
children
rev   line source
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 TouchkeyKeyDivisionMappingFactory.cpp: factory for the split-key mapping
andrewm@0 21 which triggers different actions or pitches depending on where the key
andrewm@0 22 was struck.
andrewm@0 23 */
andrewm@0 24
andrewm@0 25 #include "TouchkeyKeyDivisionMappingFactory.h"
andrewm@51 26 #include "TouchkeyKeyDivisionMappingShortEditor.h"
andrewm@44 27 #include "../../Display/KeyboardDisplay.h"
andrewm@0 28
andrewm@51 29 /* Yarman-24c microtonal tuning */
andrewm@51 30 const float TouchkeyKeyDivisionMappingFactory::kTuningsYarman24c[24] = {
andrewm@0 31 0, (1124.744 - 1200.0), 83.059, 143.623, 203.9, 191.771, 292.413, 348.343,
andrewm@0 32 383.54, 362.503, 498.04, 415.305, 581.382, 634.184, 695.885, 648.682,
andrewm@0 33 788.736, 853.063, 905.87, 887.656, 996.1, 1043.623, 1085.49, 1071.942,
andrewm@0 34 };
andrewm@0 35
andrewm@51 36 const int TouchkeyKeyDivisionMappingFactory::kMaxSegmentsPerKey = 3;
andrewm@0 37
andrewm@0 38 /* As arranged:
andrewm@0 39 *
andrewm@0 40 * B| Db/ Dd Eb/ Ed E| Gb/ Gd Ab/ Ad Bb/ Bd
andrewm@0 41 * C C# D D# E F F# G G# A A# B
andrewm@0 42 */
andrewm@0 43
andrewm@0 44 TouchkeyKeyDivisionMappingFactory::TouchkeyKeyDivisionMappingFactory(PianoKeyboard &keyboard, MidiKeyboardSegment& segment)
andrewm@0 45 : TouchkeyBaseMappingFactory<TouchkeyKeyDivisionMapping>(keyboard, segment),
andrewm@51 46 tuningPreset_(-1), tunings_(0),
andrewm@0 47 numSegmentsPerKey_(TouchkeyKeyDivisionMapping::kDefaultNumberOfSegments),
andrewm@0 48 timeout_(TouchkeyKeyDivisionMapping::kDefaultDetectionTimeout),
andrewm@0 49 detectionParameter_(TouchkeyKeyDivisionMapping::kDefaultDetectionParameter),
andrewm@0 50 retriggerable_(false),
andrewm@0 51 retriggerNumFrames_(TouchkeyKeyDivisionMapping::kDefaultRetriggerNumFrames),
andrewm@0 52 retriggerKeepsVelocity_(true),
andrewm@0 53 referenceNote_(0), globalOffsetCents_(0)
andrewm@0 54 {
andrewm@0 55 //setName("/touchkeys/segmentpitch");
andrewm@0 56 setBendParameters();
andrewm@51 57 setTuningPreset(kTuningPreset24TET);
andrewm@44 58
andrewm@44 59 KeyboardDisplay *display = keyboard_.gui();
andrewm@44 60 if(display != 0) {
andrewm@44 61 display->addKeyDivision(this, segment.noteRange().first, segment.noteRange().second, numSegmentsPerKey_);
andrewm@44 62 }
andrewm@44 63 }
andrewm@44 64
andrewm@44 65 TouchkeyKeyDivisionMappingFactory::~TouchkeyKeyDivisionMappingFactory() {
andrewm@44 66 // Remove the divisions from the keys, if this mapping has added them
andrewm@44 67 KeyboardDisplay *display = keyboard_.gui();
andrewm@44 68 if(display != 0)
andrewm@44 69 display->removeKeyDivision(this);
andrewm@51 70 if(tunings_ != 0) {
andrewm@51 71 delete tunings_;
andrewm@51 72 tunings_ = 0;
andrewm@51 73 }
andrewm@0 74 }
andrewm@0 75
andrewm@0 76 void TouchkeyKeyDivisionMappingFactory::setName(const string& name) {
andrewm@0 77 TouchkeyBaseMappingFactory<TouchkeyKeyDivisionMapping>::setName(name);
andrewm@0 78 setBendParameters();
andrewm@0 79 }
andrewm@0 80
andrewm@51 81 void TouchkeyKeyDivisionMappingFactory::setTuningPreset(int preset) {
andrewm@51 82 if(preset < 0 || preset >= kTuningPresetMaxValue)
andrewm@51 83 return;
andrewm@51 84
andrewm@51 85 ScopedLock sl(tuningMutex_);
andrewm@51 86
andrewm@51 87 tuningPreset_ = preset;
andrewm@51 88 if(tunings_ != 0) {
andrewm@51 89 delete tunings_;
andrewm@51 90 tunings_ = 0;
andrewm@51 91 }
andrewm@51 92
andrewm@51 93 if(tuningPreset_ == kTuningPreset19TET) {
andrewm@51 94 numSegmentsPerKey_ = 2;
andrewm@51 95 tunings_ = new float[24];
andrewm@51 96 for(int i = 0; i < 24; i++) {
andrewm@51 97 // Start with fraction of an octave, round to the nearest 19th of an octave
andrewm@51 98 float original = (float)i / 24.0;
andrewm@51 99 float rounded = floorf(original * 19.0 + 0.5);
andrewm@51 100
andrewm@51 101 // Now convert the 19-tone index back to a fractional number of semitones
andrewm@51 102 tunings_[i] = rounded * 1200.0 / 19.0;
andrewm@51 103 }
andrewm@51 104 }
andrewm@51 105 else if(tuningPreset_ == kTuningPreset24TET) {
andrewm@51 106 numSegmentsPerKey_ = 2;
andrewm@51 107 tunings_ = new float[24];
andrewm@51 108 for(int i = 0; i < 24; i++) {
andrewm@51 109 tunings_[i] = (float)i * 50.0;
andrewm@51 110 }
andrewm@51 111 }
andrewm@51 112 else if(tuningPreset_ == kTuningPreset31TET) {
andrewm@51 113 numSegmentsPerKey_ = 3;
andrewm@51 114 tunings_ = new float[36];
andrewm@51 115 for(int i = 0; i < 36; i++) {
andrewm@51 116 // Start with fraction of an octave, round to the nearest 31st of an octave
andrewm@51 117 float original = (float)i / 36.0;
andrewm@51 118 float rounded = floorf(original * 31.0 + 0.5);
andrewm@51 119
andrewm@51 120 // Now convert the 31-tone index back to a fractional number of semitones
andrewm@51 121 tunings_[i] = rounded * 1200.0 / 31.0;
andrewm@51 122 }
andrewm@51 123 }
andrewm@51 124 else if(tuningPreset_ == kTuningPreset36TET) {
andrewm@51 125 numSegmentsPerKey_ = 3;
andrewm@51 126 tunings_ = new float[36];
andrewm@51 127 for(int i = 0; i < 24; i++) {
andrewm@51 128 tunings_[i] = (float)i * 100.0 / 3.0;
andrewm@51 129 }
andrewm@51 130 }
andrewm@51 131 else if(tuningPreset_ == kTuningPresetYarman24c) {
andrewm@51 132 numSegmentsPerKey_ = 2;
andrewm@51 133 tunings_ = new float[24];
andrewm@51 134 for(int i = 0; i < 24; i++)
andrewm@51 135 tunings_[i] = kTuningsYarman24c[i];
andrewm@51 136 }
andrewm@51 137
andrewm@51 138 KeyboardDisplay *display = keyboard_.gui();
andrewm@51 139 if(display != 0) {
andrewm@51 140 display->removeKeyDivision(this);
andrewm@51 141 display->addKeyDivision(this, keyboardSegment_.noteRange().first, keyboardSegment_.noteRange().second, numSegmentsPerKey_);
andrewm@51 142 }
andrewm@51 143 }
andrewm@51 144
andrewm@51 145 #ifndef TOUCHKEYS_NO_GUI
andrewm@51 146 // ***** GUI Support *****
andrewm@51 147 MappingEditorComponent* TouchkeyKeyDivisionMappingFactory::createBasicEditor() {
andrewm@51 148 return new TouchkeyKeyDivisionMappingShortEditor(*this);
andrewm@51 149 }
andrewm@51 150 #endif
andrewm@36 151
andrewm@36 152 // ****** Preset Save/Load ******
andrewm@36 153 XmlElement* TouchkeyKeyDivisionMappingFactory::getPreset() {
andrewm@36 154 PropertySet properties;
andrewm@36 155
andrewm@36 156 storeCommonProperties(properties);
andrewm@36 157
andrewm@36 158 // No properties for now
andrewm@36 159
andrewm@36 160 XmlElement* preset = properties.createXml("MappingFactory");
andrewm@36 161 preset->setAttribute("type", "KeyDivision");
andrewm@36 162
andrewm@36 163 return preset;
andrewm@36 164 }
andrewm@36 165
andrewm@36 166 bool TouchkeyKeyDivisionMappingFactory::loadPreset(XmlElement const* preset) {
andrewm@36 167 if(preset == 0)
andrewm@36 168 return false;
andrewm@36 169
andrewm@36 170 PropertySet properties;
andrewm@36 171 properties.restoreFromXml(*preset);
andrewm@36 172
andrewm@36 173 if(!loadCommonProperties(properties))
andrewm@36 174 return false;
andrewm@36 175
andrewm@36 176 // Nothing specific to do for now
andrewm@36 177
andrewm@36 178 return true;
andrewm@36 179 }
andrewm@36 180
andrewm@36 181 // ***** Private Methods *****
andrewm@36 182
andrewm@0 183 // Set the initial parameters for a new mapping
andrewm@0 184 void TouchkeyKeyDivisionMappingFactory::initializeMappingParameters(int noteNumber, TouchkeyKeyDivisionMapping *mapping) {
andrewm@51 185 ScopedLock sl(tuningMutex_);
andrewm@51 186
andrewm@51 187 // Convert absolute tunings into pitch bends in semitones
andrewm@51 188 float tunings[kMaxSegmentsPerKey];
andrewm@51 189
andrewm@0 190 int index = (noteNumber + 12 - referenceNote_) % 12;
andrewm@0 191 float standardTuning = (float)index * 100.0;
andrewm@0 192
andrewm@51 193 for(int i = 0; i < numSegmentsPerKey_; i++) {
andrewm@51 194 tunings[i] = (tunings_[index*numSegmentsPerKey_ + i] - standardTuning + globalOffsetCents_) * .01;
andrewm@51 195 }
andrewm@51 196 mapping->setSegmentPitchBends(tunings, numSegmentsPerKey_);
andrewm@0 197 mapping->setNumberOfSegments(numSegmentsPerKey_);
andrewm@0 198 mapping->setTimeout(timeout_);
andrewm@0 199 mapping->setDetectionParameter(detectionParameter_);
andrewm@0 200 mapping->setRetriggerable(retriggerable_, retriggerNumFrames_, retriggerKeepsVelocity_);
andrewm@0 201 }
andrewm@0 202
andrewm@0 203 void TouchkeyKeyDivisionMappingFactory::setBendParameters() {
andrewm@7 204 // Range of 0 indicates special case of using global pitch wheel range
andrewm@7 205 setMidiParameters(MidiKeyboardSegment::kControlPitchWheel, 0.0, 0.0, 0.0);
andrewm@0 206
andrewm@0 207 if(midiConverter_ != 0) {
andrewm@0 208 midiConverter_->listenToIncomingControl(MidiKeyboardSegment::kControlPitchWheel);
andrewm@0 209 }
andrewm@0 210 }