comparison Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingFactory.cpp @ 51:003236a1e29b

Added GUI for key division mapping, plus more tuning options
author Andrew McPherson <andrewm@eecs.qmul.ac.uk>
date Wed, 22 Apr 2015 21:37:51 +0100
parents 73576f49ad1c
children
comparison
equal deleted inserted replaced
50:114427cb39f0 51:003236a1e29b
21 which triggers different actions or pitches depending on where the key 21 which triggers different actions or pitches depending on where the key
22 was struck. 22 was struck.
23 */ 23 */
24 24
25 #include "TouchkeyKeyDivisionMappingFactory.h" 25 #include "TouchkeyKeyDivisionMappingFactory.h"
26 #include "TouchkeyKeyDivisionMappingShortEditor.h"
26 #include "../../Display/KeyboardDisplay.h" 27 #include "../../Display/KeyboardDisplay.h"
27 28
28 // Yarman-24 Turkish microtonal tuning: 29 /* Yarman-24c microtonal tuning */
29 /* 1/1 RAST C 30 const float TouchkeyKeyDivisionMappingFactory::kTuningsYarman24c[24] = {
30 84.360 Nim Zengule C#/Db
31 145.112 Zengule Cᵻ/Dƀ
32 192.180 Dik Zengule Dd
33 9/8 DUGAH D
34 292.180 Kurdi D#/Eb
35 60/49 Dik Kurdi Dᵻ/Eƀ
36 364.735 Nerm Segah Ed
37 5/4 SEGAH E
38 415.677 Buselik E‡
39 4/3 CHARGAH F
40 584.359 Nim Hijaz F#/Gb
41 635.300 Hijaz/Saba Fᵻ/Gƀ
42 696.090 Dik Hijaz/Saba Gd
43 3/2 NEVA G
44 788.270 Nim Hisar G#/Ab
45 854.924 Hisar Gᵻ/Aƀ
46 888.270 Dik Hisar Ad
47 27/16 HUSEYNI A 440hz
48 16/9 Ajem A#/Bb
49 11/6 Dik Ajem Aᵻ/Bƀ
50 1074.547 Nerm Evdj Bd
51 15/8 EVDJ B
52 1125.488 Mahur B‡
53 2/1 GERDANIYE C */
54 /*const float TouchkeyKeyDivisionMappingFactory::kDefaultTuningsCents[24] = {
55 0, 84.36, 145.112, 192.18, 203.9, 292.18, 350.62, 364.74, 386.31, 415.677, 498.04, 584.359,
56 635.3, 696.09, 701.95, 788.27, 854.92, 888.27, 905.87, 996.1, 1049.36, 1074.55, 1088.27, 1125.488
57 };*/
58
59 // Yarman-24c Turkish microtonal tuning:
60 /* 0: 1/1 C Dbb unison, perfect prime RAST ♥
61 1: 83.059 cents C# Db nim zengule
62 2: 143.623 cents zengule
63 3: 191.771 cents C## Dd dik zengule
64 4: 9/8 D Ebb major whole tone DÜGAH ♥
65 5: 292.413 cents D# Eb kürdi
66 6: 348.343 cents D#| Eb- dik kürdi
67 7: 362.503 cents nerm segah
68 8: 156/125 cents E SEGAH ♥
69 9: 415.305 cents E| Buselik
70 10: 4/3 F Gbb perfect fourth ÇARGAH ♥
71 11: 581.382 cents F# Gb nim hicaz
72 12: 634.184 cents hicaz
73 13: 695.885 cents F## Gd dik hicaz
74 14: 3/2 G Abb perfect fifth NEVA ♥
75 15: 788.736 cents G# Ab nim hisar
76 16: 853.063 cents hisar
77 17: 887.656 cents G## Ad dik hisar
78 18: 27/16 A Bbb Pyth. major sixth HÜSEYNİ ♥
79 19: 16/9 A# Bb Pyth. minor seventh acem
80 20: 1043.623 cents A#| Bb- dik acem
81 21: 1071.942 cents nerm eviç
82 22: 234/125 cents B EVİÇ ♥
83 23: 1124.744 cents B| mahur
84 24: 2/1 C Dbb octave GERDANİYE ♥
85 */
86
87 /*const float TouchkeyKeyDivisionMappingFactory::kDefaultTuningsCents[24] = {
88 0, 83.059, 143.623, 191.771, 203.9, 292.413, 348.343, 362.503, 383.54, 415.305, 498.04, 581.382,
89 634.184, 695.885, 701.95, 788.736, 853.063, 887.656, 905.87, 996.1, 1043.623, 1071.942, 1085.49, 1124.744
90 };*/
91
92 /* Yarman-24c as above but arranged for performance */
93 const float TouchkeyKeyDivisionMappingFactory::kDefaultTuningsCents[24] = {
94 0, (1124.744 - 1200.0), 83.059, 143.623, 203.9, 191.771, 292.413, 348.343, 31 0, (1124.744 - 1200.0), 83.059, 143.623, 203.9, 191.771, 292.413, 348.343,
95 383.54, 362.503, 498.04, 415.305, 581.382, 634.184, 695.885, 648.682, 32 383.54, 362.503, 498.04, 415.305, 581.382, 634.184, 695.885, 648.682,
96 788.736, 853.063, 905.87, 887.656, 996.1, 1043.623, 1085.49, 1071.942, 33 788.736, 853.063, 905.87, 887.656, 996.1, 1043.623, 1085.49, 1071.942,
97 }; 34 };
98 35
99 /*const float TouchkeyKeyDivisionMappingFactory::kDefaultTuningsCents[24] = { 36 const int TouchkeyKeyDivisionMappingFactory::kMaxSegmentsPerKey = 3;
100 0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700,
101 750, 800, 850, 900, 950, 1000, 1050, 1100, 1150
102 };*/
103
104 /*const float TouchkeyKeyDivisionMappingFactory::kDefaultTuningsCents[36] = {
105 0, 33.3, 66.6, 100, 133.3, 166.6, 200, 233.3, 266.6, 300, 333.3, 366.6,
106 400, 433.3, 466.6, 500, 533.3, 566.6, 600, 633.3, 666.6, 700, 733.3, 766.6,
107 800, 833.3, 866.6, 900, 933.3, 966.6, 1000, 1033.3, 1066.6, 1100, 1133.3, 1166.6
108 };*/
109 37
110 /* As arranged: 38 /* As arranged:
111 * 39 *
112 * B| Db/ Dd Eb/ Ed E| Gb/ Gd Ab/ Ad Bb/ Bd 40 * B| Db/ Dd Eb/ Ed E| Gb/ Gd Ab/ Ad Bb/ Bd
113 * C C# D D# E F F# G G# A A# B 41 * C C# D D# E F F# G G# A A# B
114 */ 42 */
115 43
116 TouchkeyKeyDivisionMappingFactory::TouchkeyKeyDivisionMappingFactory(PianoKeyboard &keyboard, MidiKeyboardSegment& segment) 44 TouchkeyKeyDivisionMappingFactory::TouchkeyKeyDivisionMappingFactory(PianoKeyboard &keyboard, MidiKeyboardSegment& segment)
117 : TouchkeyBaseMappingFactory<TouchkeyKeyDivisionMapping>(keyboard, segment), 45 : TouchkeyBaseMappingFactory<TouchkeyKeyDivisionMapping>(keyboard, segment),
46 tuningPreset_(-1), tunings_(0),
118 numSegmentsPerKey_(TouchkeyKeyDivisionMapping::kDefaultNumberOfSegments), 47 numSegmentsPerKey_(TouchkeyKeyDivisionMapping::kDefaultNumberOfSegments),
119 timeout_(TouchkeyKeyDivisionMapping::kDefaultDetectionTimeout), 48 timeout_(TouchkeyKeyDivisionMapping::kDefaultDetectionTimeout),
120 detectionParameter_(TouchkeyKeyDivisionMapping::kDefaultDetectionParameter), 49 detectionParameter_(TouchkeyKeyDivisionMapping::kDefaultDetectionParameter),
121 retriggerable_(false), 50 retriggerable_(false),
122 retriggerNumFrames_(TouchkeyKeyDivisionMapping::kDefaultRetriggerNumFrames), 51 retriggerNumFrames_(TouchkeyKeyDivisionMapping::kDefaultRetriggerNumFrames),
123 retriggerKeepsVelocity_(true), 52 retriggerKeepsVelocity_(true),
124 referenceNote_(0), globalOffsetCents_(0) 53 referenceNote_(0), globalOffsetCents_(0)
125 { 54 {
126 //setName("/touchkeys/segmentpitch"); 55 //setName("/touchkeys/segmentpitch");
127 setBendParameters(); 56 setBendParameters();
57 setTuningPreset(kTuningPreset24TET);
128 58
129 KeyboardDisplay *display = keyboard_.gui(); 59 KeyboardDisplay *display = keyboard_.gui();
130 if(display != 0) { 60 if(display != 0) {
131 display->addKeyDivision(this, segment.noteRange().first, segment.noteRange().second, numSegmentsPerKey_); 61 display->addKeyDivision(this, segment.noteRange().first, segment.noteRange().second, numSegmentsPerKey_);
132 } 62 }
135 TouchkeyKeyDivisionMappingFactory::~TouchkeyKeyDivisionMappingFactory() { 65 TouchkeyKeyDivisionMappingFactory::~TouchkeyKeyDivisionMappingFactory() {
136 // Remove the divisions from the keys, if this mapping has added them 66 // Remove the divisions from the keys, if this mapping has added them
137 KeyboardDisplay *display = keyboard_.gui(); 67 KeyboardDisplay *display = keyboard_.gui();
138 if(display != 0) 68 if(display != 0)
139 display->removeKeyDivision(this); 69 display->removeKeyDivision(this);
70 if(tunings_ != 0) {
71 delete tunings_;
72 tunings_ = 0;
73 }
140 } 74 }
141 75
142 void TouchkeyKeyDivisionMappingFactory::setName(const string& name) { 76 void TouchkeyKeyDivisionMappingFactory::setName(const string& name) {
143 TouchkeyBaseMappingFactory<TouchkeyKeyDivisionMapping>::setName(name); 77 TouchkeyBaseMappingFactory<TouchkeyKeyDivisionMapping>::setName(name);
144 setBendParameters(); 78 setBendParameters();
145 } 79 }
146 80
81 void TouchkeyKeyDivisionMappingFactory::setTuningPreset(int preset) {
82 if(preset < 0 || preset >= kTuningPresetMaxValue)
83 return;
84
85 ScopedLock sl(tuningMutex_);
86
87 tuningPreset_ = preset;
88 if(tunings_ != 0) {
89 delete tunings_;
90 tunings_ = 0;
91 }
92
93 if(tuningPreset_ == kTuningPreset19TET) {
94 numSegmentsPerKey_ = 2;
95 tunings_ = new float[24];
96 for(int i = 0; i < 24; i++) {
97 // Start with fraction of an octave, round to the nearest 19th of an octave
98 float original = (float)i / 24.0;
99 float rounded = floorf(original * 19.0 + 0.5);
100
101 // Now convert the 19-tone index back to a fractional number of semitones
102 tunings_[i] = rounded * 1200.0 / 19.0;
103 }
104 }
105 else if(tuningPreset_ == kTuningPreset24TET) {
106 numSegmentsPerKey_ = 2;
107 tunings_ = new float[24];
108 for(int i = 0; i < 24; i++) {
109 tunings_[i] = (float)i * 50.0;
110 }
111 }
112 else if(tuningPreset_ == kTuningPreset31TET) {
113 numSegmentsPerKey_ = 3;
114 tunings_ = new float[36];
115 for(int i = 0; i < 36; i++) {
116 // Start with fraction of an octave, round to the nearest 31st of an octave
117 float original = (float)i / 36.0;
118 float rounded = floorf(original * 31.0 + 0.5);
119
120 // Now convert the 31-tone index back to a fractional number of semitones
121 tunings_[i] = rounded * 1200.0 / 31.0;
122 }
123 }
124 else if(tuningPreset_ == kTuningPreset36TET) {
125 numSegmentsPerKey_ = 3;
126 tunings_ = new float[36];
127 for(int i = 0; i < 24; i++) {
128 tunings_[i] = (float)i * 100.0 / 3.0;
129 }
130 }
131 else if(tuningPreset_ == kTuningPresetYarman24c) {
132 numSegmentsPerKey_ = 2;
133 tunings_ = new float[24];
134 for(int i = 0; i < 24; i++)
135 tunings_[i] = kTuningsYarman24c[i];
136 }
137
138 KeyboardDisplay *display = keyboard_.gui();
139 if(display != 0) {
140 display->removeKeyDivision(this);
141 display->addKeyDivision(this, keyboardSegment_.noteRange().first, keyboardSegment_.noteRange().second, numSegmentsPerKey_);
142 }
143 }
144
145 #ifndef TOUCHKEYS_NO_GUI
146 // ***** GUI Support *****
147 MappingEditorComponent* TouchkeyKeyDivisionMappingFactory::createBasicEditor() {
148 return new TouchkeyKeyDivisionMappingShortEditor(*this);
149 }
150 #endif
147 151
148 // ****** Preset Save/Load ****** 152 // ****** Preset Save/Load ******
149 XmlElement* TouchkeyKeyDivisionMappingFactory::getPreset() { 153 XmlElement* TouchkeyKeyDivisionMappingFactory::getPreset() {
150 PropertySet properties; 154 PropertySet properties;
151 155
176 180
177 // ***** Private Methods ***** 181 // ***** Private Methods *****
178 182
179 // Set the initial parameters for a new mapping 183 // Set the initial parameters for a new mapping
180 void TouchkeyKeyDivisionMappingFactory::initializeMappingParameters(int noteNumber, TouchkeyKeyDivisionMapping *mapping) { 184 void TouchkeyKeyDivisionMappingFactory::initializeMappingParameters(int noteNumber, TouchkeyKeyDivisionMapping *mapping) {
181 // KLUDGE: testing Maqam tunings. Go from absolute tunings in cents to pitch bends in semitones 185 ScopedLock sl(tuningMutex_);
182 float tunings[2]; 186
187 // Convert absolute tunings into pitch bends in semitones
188 float tunings[kMaxSegmentsPerKey];
189
183 int index = (noteNumber + 12 - referenceNote_) % 12; 190 int index = (noteNumber + 12 - referenceNote_) % 12;
184 float standardTuning = (float)index * 100.0; 191 float standardTuning = (float)index * 100.0;
185 tunings[0] = (kDefaultTuningsCents[index*2] - standardTuning + globalOffsetCents_) * .01; 192
186 tunings[1] = (kDefaultTuningsCents[index*2 + 1] - standardTuning + globalOffsetCents_) * .01; 193 for(int i = 0; i < numSegmentsPerKey_; i++) {
187 mapping->setSegmentPitchBends(tunings, 2); 194 tunings[i] = (tunings_[index*numSegmentsPerKey_ + i] - standardTuning + globalOffsetCents_) * .01;
188 /*float tunings[3]; 195 }
189 int index = (noteNumber + 12 - referenceNote_) % 12; 196 mapping->setSegmentPitchBends(tunings, numSegmentsPerKey_);
190 float standardTuning = (float)index * 100.0;
191 tunings[0] = (kDefaultTuningsCents[index*3] - standardTuning + globalOffsetCents_) * .01;
192 tunings[1] = (kDefaultTuningsCents[index*3 + 1] - standardTuning + globalOffsetCents_) * .01;
193 tunings[2] = (kDefaultTuningsCents[index*3 + 2] - standardTuning + globalOffsetCents_) * .01;
194 mapping->setSegmentPitchBends(tunings, 3);*/
195
196
197 mapping->setNumberOfSegments(numSegmentsPerKey_); 197 mapping->setNumberOfSegments(numSegmentsPerKey_);
198 mapping->setTimeout(timeout_); 198 mapping->setTimeout(timeout_);
199 mapping->setDetectionParameter(detectionParameter_); 199 mapping->setDetectionParameter(detectionParameter_);
200 mapping->setRetriggerable(retriggerable_, retriggerNumFrames_, retriggerKeepsVelocity_); 200 mapping->setRetriggerable(retriggerable_, retriggerNumFrames_, retriggerKeepsVelocity_);
201 } 201 }