changeset 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 114427cb39f0
children 18af05164894
files Builds/Linux/Makefile Builds/Linux32/Makefile Source/MainApplicationController.cpp Source/Mappings/KeyDivision/TouchkeyKeyDivisionMapping.cpp Source/Mappings/KeyDivision/TouchkeyKeyDivisionMapping.h Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingFactory.cpp Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingFactory.h Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingShortEditor.cpp Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingShortEditor.h Source/TouchKeys/MidiInputController.h Source/TouchKeys/MidiKeyboardSegment.cpp TouchKeys.jucer
diffstat 12 files changed, 462 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/Builds/Linux/Makefile	Mon Apr 13 20:51:17 2015 -0700
+++ b/Builds/Linux/Makefile	Wed Apr 22 21:37:51 2015 +0100
@@ -71,6 +71,7 @@
   $(OBJDIR)/TouchkeyMultiFingerTriggerMappingShortEditor_8604e029.o \
   $(OBJDIR)/TouchkeyMultiFingerTriggerMapping_f7bfe8a.o \
   $(OBJDIR)/TouchkeyMultiFingerTriggerMappingFactory_e811112a.o \
+  $(OBJDIR)/TouchkeyKeyDivisionMappingShortEditor_a9e1dc43.o \
   $(OBJDIR)/TouchkeyKeyDivisionMapping_cea38eb0.o \
   $(OBJDIR)/TouchkeyKeyDivisionMappingFactory_33b42a44.o \
   $(OBJDIR)/TouchkeyControlMappingExtendedEditor_bb11f4.o \
@@ -238,6 +239,11 @@
 	@echo "Compiling TouchkeyMultiFingerTriggerMappingFactory.cpp"
 	@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
 
+$(OBJDIR)/TouchkeyKeyDivisionMappingShortEditor_a9e1dc43.o: ../../Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingShortEditor.cpp
+	-@mkdir -p $(OBJDIR)
+	@echo "Compiling TouchkeyKeyDivisionMappingShortEditor.cpp"
+	@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+
 $(OBJDIR)/TouchkeyKeyDivisionMapping_cea38eb0.o: ../../Source/Mappings/KeyDivision/TouchkeyKeyDivisionMapping.cpp
 	-@mkdir -p $(OBJDIR)
 	@echo "Compiling TouchkeyKeyDivisionMapping.cpp"
--- a/Builds/Linux32/Makefile	Mon Apr 13 20:51:17 2015 -0700
+++ b/Builds/Linux32/Makefile	Wed Apr 22 21:37:51 2015 +0100
@@ -71,6 +71,7 @@
   $(OBJDIR)/TouchkeyMultiFingerTriggerMappingShortEditor_8604e029.o \
   $(OBJDIR)/TouchkeyMultiFingerTriggerMapping_f7bfe8a.o \
   $(OBJDIR)/TouchkeyMultiFingerTriggerMappingFactory_e811112a.o \
+  $(OBJDIR)/TouchkeyKeyDivisionMappingShortEditor_a9e1dc43.o \
   $(OBJDIR)/TouchkeyKeyDivisionMapping_cea38eb0.o \
   $(OBJDIR)/TouchkeyKeyDivisionMappingFactory_33b42a44.o \
   $(OBJDIR)/TouchkeyControlMappingExtendedEditor_bb11f4.o \
@@ -238,6 +239,11 @@
 	@echo "Compiling TouchkeyMultiFingerTriggerMappingFactory.cpp"
 	@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
 
+$(OBJDIR)/TouchkeyKeyDivisionMappingShortEditor_a9e1dc43.o: ../../Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingShortEditor.cpp
+	-@mkdir -p $(OBJDIR)
+	@echo "Compiling TouchkeyKeyDivisionMappingShortEditor.cpp"
+	@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+
 $(OBJDIR)/TouchkeyKeyDivisionMapping_cea38eb0.o: ../../Source/Mappings/KeyDivision/TouchkeyKeyDivisionMapping.cpp
 	-@mkdir -p $(OBJDIR)
 	@echo "Compiling TouchkeyKeyDivisionMapping.cpp"
--- a/Source/MainApplicationController.cpp	Mon Apr 13 20:51:17 2015 -0700
+++ b/Source/MainApplicationController.cpp	Wed Apr 22 21:37:51 2015 +0100
@@ -106,6 +106,7 @@
         touchkeySensorTestStop();
 #endif
     removeAllOscListeners();
+    midiInputController_.removeAllSegments();   // Remove segments now to avoid deletion-order problems
     delete mainOscController_;
 }
 
--- a/Source/Mappings/KeyDivision/TouchkeyKeyDivisionMapping.cpp	Mon Apr 13 20:51:17 2015 -0700
+++ b/Source/Mappings/KeyDivision/TouchkeyKeyDivisionMapping.cpp	Wed Apr 22 21:37:51 2015 +0100
@@ -25,7 +25,7 @@
 #include "TouchkeyKeyDivisionMapping.h"
 #include "TouchkeyKeyDivisionMappingFactory.h"
 
-#define DEBUG_KEY_DIVISION_MAPPING
+#undef DEBUG_KEY_DIVISION_MAPPING
 
 const int TouchkeyKeyDivisionMapping::kDefaultNumberOfSegments = 2;
 const timestamp_diff_type TouchkeyKeyDivisionMapping::kDefaultDetectionTimeout = milliseconds_to_timestamp(25.0);
--- a/Source/Mappings/KeyDivision/TouchkeyKeyDivisionMapping.h	Mon Apr 13 20:51:17 2015 -0700
+++ b/Source/Mappings/KeyDivision/TouchkeyKeyDivisionMapping.h	Wed Apr 22 21:37:51 2015 +0100
@@ -37,7 +37,8 @@
     enum {
         kDetectionParameterYPosition = 1,
         kDetectionParameterNumberOfTouches,
-        kDetectionParameterYPositionAndNumberOfTouches
+        kDetectionParameterYPositionAndNumberOfTouches,
+        kDetectionParameterMaxValue
     };
     
 private:
--- a/Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingFactory.cpp	Mon Apr 13 20:51:17 2015 -0700
+++ b/Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingFactory.cpp	Wed Apr 22 21:37:51 2015 +0100
@@ -23,89 +23,17 @@
 */
 
 #include "TouchkeyKeyDivisionMappingFactory.h"
+#include "TouchkeyKeyDivisionMappingShortEditor.h"
 #include "../../Display/KeyboardDisplay.h"
 
-// Yarman-24 Turkish microtonal tuning:
-/*      1/1	RAST		C
- 84.360	Nim Zengule	C#/Db
- 145.112	Zengule		Cᵻ/Dƀ
- 192.180	Dik Zengule	Dd
- 9/8	DUGAH		D
- 292.180	Kurdi		D#/Eb
- 60/49	Dik Kurdi	Dᵻ/Eƀ
- 364.735	Nerm Segah	Ed
- 5/4	SEGAH		E
- 415.677	Buselik		E‡
- 4/3	CHARGAH		F
- 584.359	Nim Hijaz	F#/Gb
- 635.300	Hijaz/Saba	Fᵻ/Gƀ
- 696.090	Dik Hijaz/Saba	Gd
- 3/2	NEVA		G
- 788.270	Nim Hisar	G#/Ab
- 854.924	Hisar		Gᵻ/Aƀ
- 888.270	Dik Hisar	Ad
- 27/16	HUSEYNI		A	440hz
- 16/9	Ajem		A#/Bb
- 11/6	Dik Ajem	Aᵻ/Bƀ
- 1074.547	Nerm Evdj	Bd
- 15/8	EVDJ		B
- 1125.488	Mahur		B‡
- 2/1	GERDANIYE	C */
-/*const float TouchkeyKeyDivisionMappingFactory::kDefaultTuningsCents[24] = {
-    0, 84.36, 145.112, 192.18, 203.9, 292.18, 350.62, 364.74, 386.31, 415.677, 498.04, 584.359,
-    635.3, 696.09, 701.95, 788.27, 854.92, 888.27, 905.87, 996.1, 1049.36, 1074.55, 1088.27, 1125.488
-};*/
-
-// Yarman-24c Turkish microtonal tuning:
-/*   0:          1/1           C    Dbb   unison, perfect prime    RAST ♥
- 1:         83.059 cents   C#   Db    				nim zengule
- 2:        143.623 cents					zengule
- 3:        191.771 cents   C##  Dd				dik zengule
- 4:          9/8           D    Ebb   major whole tone		DÜGAH ♥
- 5:        292.413 cents   D#   Eb				kürdi
- 6:        348.343 cents   D#|  Eb-				dik kürdi
- 7:        362.503 cents					nerm segah
- 8:        156/125 cents   E					SEGAH ♥
- 9:        415.305 cents   E| 					Buselik
- 10:          4/3           F    Gbb   perfect fourth		ÇARGAH ♥
- 11:        581.382 cents   F#   Gb				nim hicaz
- 12:        634.184 cents					hicaz
- 13:        695.885 cents   F##  Gd				dik hicaz
- 14:          3/2           G    Abb   perfect fifth		NEVA ♥
- 15:        788.736 cents   G#   Ab				nim hisar
- 16:        853.063 cents					hisar
- 17:        887.656 cents   G##  Ad				dik hisar
- 18:         27/16          A    Bbb   Pyth. major sixth	HÜSEYNİ ♥
- 19:         16/9           A#   Bb    Pyth. minor seventh	acem
- 20:       1043.623 cents   A#|  Bb-				dik acem
- 21:       1071.942 cents					nerm eviç
- 22:        234/125 cents   B					EVİÇ ♥
- 23:       1124.744 cents   B|					mahur
- 24:          2/1           C    Dbb   octave			GERDANİYE ♥
-*/
-
-/*const float TouchkeyKeyDivisionMappingFactory::kDefaultTuningsCents[24] = {
-    0, 83.059, 143.623, 191.771, 203.9, 292.413, 348.343, 362.503, 383.54, 415.305, 498.04, 581.382,
-    634.184, 695.885, 701.95, 788.736, 853.063, 887.656, 905.87, 996.1, 1043.623, 1071.942, 1085.49, 1124.744
-};*/
-
-/* Yarman-24c as above but arranged for performance */
-const float TouchkeyKeyDivisionMappingFactory::kDefaultTuningsCents[24] = {
+/* Yarman-24c microtonal tuning */
+const float TouchkeyKeyDivisionMappingFactory::kTuningsYarman24c[24] = {
     0, (1124.744 - 1200.0), 83.059, 143.623, 203.9, 191.771, 292.413, 348.343,
     383.54, 362.503, 498.04, 415.305, 581.382, 634.184, 695.885, 648.682,
     788.736, 853.063, 905.87, 887.656, 996.1, 1043.623, 1085.49, 1071.942,
 };
 
-/*const float TouchkeyKeyDivisionMappingFactory::kDefaultTuningsCents[24] = {
-    0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700,
-    750, 800, 850, 900, 950, 1000, 1050, 1100, 1150
-};*/
-
-/*const float TouchkeyKeyDivisionMappingFactory::kDefaultTuningsCents[36] = {
-    0, 33.3, 66.6, 100, 133.3, 166.6, 200, 233.3, 266.6, 300, 333.3, 366.6,
-    400, 433.3, 466.6, 500, 533.3, 566.6, 600, 633.3, 666.6, 700, 733.3, 766.6,
-    800, 833.3, 866.6, 900, 933.3, 966.6, 1000, 1033.3, 1066.6, 1100, 1133.3, 1166.6
-};*/
+const int TouchkeyKeyDivisionMappingFactory::kMaxSegmentsPerKey = 3;
 
 /* As arranged:
  *
@@ -115,6 +43,7 @@
 
 TouchkeyKeyDivisionMappingFactory::TouchkeyKeyDivisionMappingFactory(PianoKeyboard &keyboard, MidiKeyboardSegment& segment)
 : TouchkeyBaseMappingFactory<TouchkeyKeyDivisionMapping>(keyboard, segment),
+  tuningPreset_(-1), tunings_(0),
   numSegmentsPerKey_(TouchkeyKeyDivisionMapping::kDefaultNumberOfSegments),
   timeout_(TouchkeyKeyDivisionMapping::kDefaultDetectionTimeout),
   detectionParameter_(TouchkeyKeyDivisionMapping::kDefaultDetectionParameter),
@@ -125,6 +54,7 @@
 {
     //setName("/touchkeys/segmentpitch");
     setBendParameters();
+    setTuningPreset(kTuningPreset24TET);
     
     KeyboardDisplay *display = keyboard_.gui();
     if(display != 0) { 
@@ -137,6 +67,10 @@
     KeyboardDisplay *display = keyboard_.gui();
     if(display != 0)
         display->removeKeyDivision(this);
+    if(tunings_ != 0) {
+        delete tunings_;
+        tunings_ = 0;
+    }
 }
 
 void TouchkeyKeyDivisionMappingFactory::setName(const string& name) {
@@ -144,6 +78,76 @@
     setBendParameters();
 }
 
+void TouchkeyKeyDivisionMappingFactory::setTuningPreset(int preset) {
+    if(preset < 0 || preset >= kTuningPresetMaxValue)
+        return;
+    
+    ScopedLock sl(tuningMutex_);
+    
+    tuningPreset_ = preset;
+    if(tunings_ != 0) {
+        delete tunings_;
+        tunings_ = 0;
+    }
+    
+    if(tuningPreset_ == kTuningPreset19TET) {
+        numSegmentsPerKey_ = 2;
+        tunings_ = new float[24];
+        for(int i = 0; i < 24; i++) {
+            // Start with fraction of an octave, round to the nearest 19th of an octave
+            float original = (float)i / 24.0;
+            float rounded = floorf(original * 19.0 + 0.5);
+            
+            // Now convert the 19-tone index back to a fractional number of semitones
+            tunings_[i] = rounded * 1200.0 / 19.0;
+        }
+    }
+    else if(tuningPreset_ == kTuningPreset24TET) {
+        numSegmentsPerKey_ = 2;
+        tunings_ = new float[24];
+        for(int i = 0; i < 24; i++) {
+            tunings_[i] = (float)i * 50.0;
+        }
+    }
+    else if(tuningPreset_ == kTuningPreset31TET) {
+        numSegmentsPerKey_ = 3;
+        tunings_ = new float[36];
+        for(int i = 0; i < 36; i++) {
+            // Start with fraction of an octave, round to the nearest 31st of an octave
+            float original = (float)i / 36.0;
+            float rounded = floorf(original * 31.0 + 0.5);
+            
+            // Now convert the 31-tone index back to a fractional number of semitones
+            tunings_[i] = rounded * 1200.0 / 31.0;
+        }
+    }
+    else if(tuningPreset_ == kTuningPreset36TET) {
+        numSegmentsPerKey_ = 3;
+        tunings_ = new float[36];
+        for(int i = 0; i < 24; i++) {
+            tunings_[i] = (float)i * 100.0 / 3.0;
+        }
+    }
+    else if(tuningPreset_ == kTuningPresetYarman24c) {
+        numSegmentsPerKey_ = 2;
+        tunings_ = new float[24];
+        for(int i = 0; i < 24; i++)
+            tunings_[i] = kTuningsYarman24c[i];
+    }
+    
+    KeyboardDisplay *display = keyboard_.gui();
+    if(display != 0) {
+        display->removeKeyDivision(this);
+        display->addKeyDivision(this, keyboardSegment_.noteRange().first, keyboardSegment_.noteRange().second, numSegmentsPerKey_);
+    }
+}
+
+#ifndef TOUCHKEYS_NO_GUI
+// ***** GUI Support *****
+MappingEditorComponent* TouchkeyKeyDivisionMappingFactory::createBasicEditor() {
+    return new TouchkeyKeyDivisionMappingShortEditor(*this);
+}
+#endif
 
 // ****** Preset Save/Load ******
 XmlElement* TouchkeyKeyDivisionMappingFactory::getPreset() {
@@ -178,22 +182,18 @@
 
 // Set the initial parameters for a new mapping
 void TouchkeyKeyDivisionMappingFactory::initializeMappingParameters(int noteNumber, TouchkeyKeyDivisionMapping *mapping) {
-    // KLUDGE: testing Maqam tunings. Go from absolute tunings in cents to pitch bends in semitones
-    float tunings[2];
+    ScopedLock sl(tuningMutex_);
+    
+    // Convert absolute tunings into pitch bends in semitones
+    float tunings[kMaxSegmentsPerKey];
+    
     int index = (noteNumber + 12 - referenceNote_) % 12;
     float standardTuning = (float)index * 100.0;
-    tunings[0] = (kDefaultTuningsCents[index*2] - standardTuning + globalOffsetCents_) * .01;
-    tunings[1] = (kDefaultTuningsCents[index*2 + 1] - standardTuning + globalOffsetCents_) * .01;
-    mapping->setSegmentPitchBends(tunings, 2);
-    /*float tunings[3];
-    int index = (noteNumber + 12 - referenceNote_) % 12;
-    float standardTuning = (float)index * 100.0;
-    tunings[0] = (kDefaultTuningsCents[index*3] - standardTuning + globalOffsetCents_) * .01;
-    tunings[1] = (kDefaultTuningsCents[index*3 + 1] - standardTuning + globalOffsetCents_) * .01;
-    tunings[2] = (kDefaultTuningsCents[index*3 + 2] - standardTuning + globalOffsetCents_) * .01;
-    mapping->setSegmentPitchBends(tunings, 3);*/
-
     
+    for(int i = 0; i < numSegmentsPerKey_; i++) {
+        tunings[i] = (tunings_[index*numSegmentsPerKey_ + i] - standardTuning + globalOffsetCents_) * .01;
+    }
+    mapping->setSegmentPitchBends(tunings, numSegmentsPerKey_);
     mapping->setNumberOfSegments(numSegmentsPerKey_);
     mapping->setTimeout(timeout_);
     mapping->setDetectionParameter(detectionParameter_);
--- a/Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingFactory.h	Mon Apr 13 20:51:17 2015 -0700
+++ b/Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingFactory.h	Wed Apr 22 21:37:51 2015 +0100
@@ -30,9 +30,19 @@
 
 class TouchkeyKeyDivisionMappingFactory : public TouchkeyBaseMappingFactory<TouchkeyKeyDivisionMapping> {
 private:
-    static const float kDefaultTuningsCents[];
+    static const float kTuningsYarman24c[];
+    static const int kMaxSegmentsPerKey;
     
 public:
+    enum {
+        kTuningPreset19TET = 0,
+        kTuningPreset24TET,
+        kTuningPreset31TET,
+        kTuningPreset36TET,
+        kTuningPresetYarman24c,
+        kTuningPresetMaxValue
+    };
+    
     // ***** Constructor *****
     
 	// Default constructor, containing a reference to the PianoKeyboard class.
@@ -48,10 +58,20 @@
 
     void setName(const string& name);
     
-    // ***** Specific Methods *****
+    // ***** Split-Key Specific Methods *****
+    
+    int getNumberOfSegments() { return numSegmentsPerKey_; }
+    timestamp_diff_type getTimeout() { return timeout_; }
+    int getDetectionParameter() { return detectionParameter_; }
+    bool getRetriggerable() { return retriggerable_; }
+    int getRetriggerNumFrames() { return retriggerNumFrames_; }
+    bool getRetriggerKeepsVelocity() { return retriggerKeepsVelocity_; }
+    int getReferenceNote() { return referenceNote_; }
+    float getGlobalOffset() { return globalOffsetCents_; }
+    int getTuningPreset() { return tuningPreset_; }
     
     void setNumberOfSegments(int segments) {
-        if(segments > 0)
+        if(segments > 0 && segments <= kMaxSegmentsPerKey)
             numSegmentsPerKey_ = segments;
     }
     
@@ -62,17 +82,22 @@
     
     // Set the detection parameter for choosing a segment
     void setDetectionParameter(int detectionParameter) {
-        detectionParameter_ = detectionParameter;
+        if(detectionParameter >= 1 && detectionParameter < TouchkeyKeyDivisionMapping::kDetectionParameterMaxValue)
+            detectionParameter_ = detectionParameter;
     }
     
     // Set whether placing a second finger in the other segment triggers a
-    // new note with that segment.
+    // new note with that segment. Two forms of this...
     void setRetriggerable(bool retrigger, int numFrames, bool keepOriginalVelocity) {
         retriggerable_ = retrigger;
         retriggerNumFrames_ = numFrames;
         retriggerKeepsVelocity_ = keepOriginalVelocity;
     }
     
+    void setRetriggerable(bool retrigger) {
+        retriggerable_ = retrigger;
+    }
+    
     // Set the note that acts as the reference point in a microtonal scale
     void setReferenceNote(int note) {
         if(note >= 0)
@@ -83,6 +108,16 @@
         globalOffsetCents_ = offsetCents;
     }
     
+    void setTuningPreset(int preset);
+    
+#ifndef TOUCHKEYS_NO_GUI
+    // ***** GUI Support *****
+    bool hasBasicEditor() { return true; }
+    MappingEditorComponent* createBasicEditor();
+    bool hasExtendedEditor() { return false; }
+    MappingEditorComponent* createExtendedEditor() { return nullptr; }
+#endif
+    
     // ****** Preset Save/Load ******
     XmlElement* getPreset();
     bool loadPreset(XmlElement const* preset);
@@ -92,6 +127,8 @@
     void initializeMappingParameters(int noteNumber, TouchkeyKeyDivisionMapping *mapping);
     void setBendParameters();
     
+    int tuningPreset_;                                  // Number of the preset tuning, if active
+    float *tunings_;                                    // Array of tuning values, set by preset
     int numSegmentsPerKey_;                             // How many segments per key
     timestamp_diff_type timeout_;                       // How long before timeout activates default segment
     int detectionParameter_;                            // Which parameter separates it into segments
@@ -100,6 +137,8 @@
     bool retriggerKeepsVelocity_;                       // Whether a retriggered note keeps the original velocity or a default
     int referenceNote_;                                 // Which note acts as the reference point
     float globalOffsetCents_;                           // Offset of every note in cents
+    
+    CriticalSection tuningMutex_;                       // Mutex to avoid triggers during tuning changes
 };
 
 #endif /* defined(__TouchKeys__TouchkeyKeyDivisionMappingFactory__) */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingShortEditor.cpp	Wed Apr 22 21:37:51 2015 +0100
@@ -0,0 +1,225 @@
+/*
+  ==============================================================================
+
+  This is an automatically generated GUI class created by the Introjucer!
+
+  Be careful when adding custom code to these files, as only the code within
+  the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
+  and re-saved.
+
+  Created with Introjucer version: 3.1.1
+
+  ------------------------------------------------------------------------------
+
+  The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
+  Copyright 2004-13 by Raw Material Software Ltd.
+
+  ==============================================================================
+*/
+
+//[Headers] You can add your own extra header files here...
+#ifndef TOUCHKEYS_NO_GUI
+//[/Headers]
+
+#include "TouchkeyKeyDivisionMappingShortEditor.h"
+
+
+//[MiscUserDefs] You can add your own user definitions and misc code here...
+//[/MiscUserDefs]
+
+//==============================================================================
+TouchkeyKeyDivisionMappingShortEditor::TouchkeyKeyDivisionMappingShortEditor (TouchkeyKeyDivisionMappingFactory& factory)
+    : factory_(factory)
+{
+    addAndMakeVisible (tuningComboBox = new ComboBox ("tuning combo box"));
+    tuningComboBox->setEditableText (false);
+    tuningComboBox->setJustificationType (Justification::centredLeft);
+    tuningComboBox->setTextWhenNothingSelected (String::empty);
+    tuningComboBox->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
+    tuningComboBox->addListener (this);
+
+    addAndMakeVisible (tuningLabel = new Label ("tuning label",
+                                                TRANS("Tuning:")));
+    tuningLabel->setFont (Font (15.00f, Font::plain));
+    tuningLabel->setJustificationType (Justification::centredLeft);
+    tuningLabel->setEditable (false, false, false);
+    tuningLabel->setColour (TextEditor::textColourId, Colours::black);
+    tuningLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
+
+    addAndMakeVisible (controlLabel = new Label ("control label",
+                                                 TRANS("Control:")));
+    controlLabel->setFont (Font (15.00f, Font::plain));
+    controlLabel->setJustificationType (Justification::centredLeft);
+    controlLabel->setEditable (false, false, false);
+    controlLabel->setColour (TextEditor::textColourId, Colours::black);
+    controlLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
+
+    addAndMakeVisible (controlComboBox = new ComboBox ("control combo box"));
+    controlComboBox->setEditableText (false);
+    controlComboBox->setJustificationType (Justification::centredLeft);
+    controlComboBox->setTextWhenNothingSelected (String::empty);
+    controlComboBox->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
+    controlComboBox->addListener (this);
+
+    addAndMakeVisible (retriggerButton = new ToggleButton ("retrigger button"));
+    retriggerButton->setButtonText (TRANS("Retriggerable"));
+    retriggerButton->addListener (this);
+
+
+    //[UserPreSize]
+    controlComboBox->addItem("Position", TouchkeyKeyDivisionMapping::kDetectionParameterYPosition);
+    controlComboBox->addItem("Number of Touches", TouchkeyKeyDivisionMapping::kDetectionParameterNumberOfTouches);
+    controlComboBox->addItem("Both", TouchkeyKeyDivisionMapping::kDetectionParameterYPositionAndNumberOfTouches);
+    
+    tuningComboBox->addItem("19-tone Equal Temperament", TouchkeyKeyDivisionMappingFactory::kTuningPreset19TET + 1);
+    tuningComboBox->addItem("24-tone Equal Temperament", TouchkeyKeyDivisionMappingFactory::kTuningPreset24TET + 1);
+    tuningComboBox->addItem("31-tone Equal Temperament", TouchkeyKeyDivisionMappingFactory::kTuningPreset31TET + 1);
+    tuningComboBox->addItem("36-tone Equal Temperament", TouchkeyKeyDivisionMappingFactory::kTuningPreset36TET + 1);
+    tuningComboBox->addItem("Yarman-24c Maqam Tuning", TouchkeyKeyDivisionMappingFactory::kTuningPresetYarman24c + 1);
+    //[/UserPreSize]
+
+    setSize (328, 71);
+
+
+    //[Constructor] You can add your own custom stuff here..
+    //[/Constructor]
+}
+
+TouchkeyKeyDivisionMappingShortEditor::~TouchkeyKeyDivisionMappingShortEditor()
+{
+    //[Destructor_pre]. You can add your own custom destruction code here..
+    //[/Destructor_pre]
+
+    tuningComboBox = nullptr;
+    tuningLabel = nullptr;
+    controlLabel = nullptr;
+    controlComboBox = nullptr;
+    retriggerButton = nullptr;
+
+
+    //[Destructor]. You can add your own custom destruction code here..
+    //[/Destructor]
+}
+
+//==============================================================================
+void TouchkeyKeyDivisionMappingShortEditor::paint (Graphics& g)
+{
+    //[UserPrePaint] Add your own custom painting code here..
+    //[/UserPrePaint]
+
+    g.fillAll (Colours::white);
+
+    //[UserPaint] Add your own custom painting code here..
+    //[/UserPaint]
+}
+
+void TouchkeyKeyDivisionMappingShortEditor::resized()
+{
+    //[UserPreResize] Add your own custom resize code here..
+    //[/UserPreResize]
+
+    tuningComboBox->setBounds (72, 8, 248, 24);
+    tuningLabel->setBounds (8, 8, 72, 24);
+    controlLabel->setBounds (8, 40, 72, 24);
+    controlComboBox->setBounds (72, 40, 88, 24);
+    retriggerButton->setBounds (176, 40, 136, 24);
+    //[UserResized] Add your own custom resize handling here..
+    //[/UserResized]
+}
+
+void TouchkeyKeyDivisionMappingShortEditor::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
+{
+    //[UsercomboBoxChanged_Pre]
+    //[/UsercomboBoxChanged_Pre]
+
+    if (comboBoxThatHasChanged == tuningComboBox)
+    {
+        //[UserComboBoxCode_tuningComboBox] -- add your combo box handling code here..
+        // Offset the value by 1 since preset numbering starts from 0 but combo box IDs start from 1...
+        factory_.setTuningPreset(tuningComboBox->getSelectedId() - 1);
+        //[/UserComboBoxCode_tuningComboBox]
+    }
+    else if (comboBoxThatHasChanged == controlComboBox)
+    {
+        //[UserComboBoxCode_controlComboBox] -- add your combo box handling code here..
+        factory_.setDetectionParameter(controlComboBox->getSelectedId());
+        //[/UserComboBoxCode_controlComboBox]
+    }
+
+    //[UsercomboBoxChanged_Post]
+    //[/UsercomboBoxChanged_Post]
+}
+
+void TouchkeyKeyDivisionMappingShortEditor::buttonClicked (Button* buttonThatWasClicked)
+{
+    //[UserbuttonClicked_Pre]
+    //[/UserbuttonClicked_Pre]
+
+    if (buttonThatWasClicked == retriggerButton)
+    {
+        //[UserButtonCode_retriggerButton] -- add your button handler code here..
+        factory_.setRetriggerable(retriggerButton->getToggleState());
+        //[/UserButtonCode_retriggerButton]
+    }
+
+    //[UserbuttonClicked_Post]
+    //[/UserbuttonClicked_Post]
+}
+
+
+
+//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
+void TouchkeyKeyDivisionMappingShortEditor::synchronize()
+{
+    retriggerButton->setToggleState(factory_.getRetriggerable(), dontSendNotification);
+    controlComboBox->setSelectedId(factory_.getDetectionParameter());
+    tuningComboBox->setSelectedId(factory_.getTuningPreset() + 1);
+}
+//[/MiscUserCode]
+
+
+//==============================================================================
+#if 0
+/*  -- Introjucer information section --
+
+    This is where the Introjucer stores the metadata that describe this GUI layout, so
+    make changes in here at your peril!
+
+BEGIN_JUCER_METADATA
+
+<JUCER_COMPONENT documentType="Component" className="TouchkeyKeyDivisionMappingShortEditor"
+                 componentName="" parentClasses="public MappingEditorComponent, public TextEditor::Listener"
+                 constructorParams="TouchkeyKeyDivisionMappingFactory&amp; factory"
+                 variableInitialisers="factory_(factory)" snapPixels="8" snapActive="1"
+                 snapShown="1" overlayOpacity="0.330" fixedSize="1" initialWidth="328"
+                 initialHeight="71">
+  <BACKGROUND backgroundColour="ffffffff"/>
+  <COMBOBOX name="tuning combo box" id="11460b0e135fe122" memberName="tuningComboBox"
+            virtualName="" explicitFocusOrder="0" pos="72 8 248 24" editable="0"
+            layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/>
+  <LABEL name="tuning label" id="864de4f55b5481ee" memberName="tuningLabel"
+         virtualName="" explicitFocusOrder="0" pos="8 8 72 24" edTextCol="ff000000"
+         edBkgCol="0" labelText="Tuning:" editableSingleClick="0" editableDoubleClick="0"
+         focusDiscardsChanges="0" fontname="Default font" fontsize="15"
+         bold="0" italic="0" justification="33"/>
+  <LABEL name="control label" id="163b8236fad72f38" memberName="controlLabel"
+         virtualName="" explicitFocusOrder="0" pos="8 40 72 24" edTextCol="ff000000"
+         edBkgCol="0" labelText="Control:" editableSingleClick="0" editableDoubleClick="0"
+         focusDiscardsChanges="0" fontname="Default font" fontsize="15"
+         bold="0" italic="0" justification="33"/>
+  <COMBOBOX name="control combo box" id="597816425fbf42ce" memberName="controlComboBox"
+            virtualName="" explicitFocusOrder="0" pos="72 40 88 24" editable="0"
+            layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/>
+  <TOGGLEBUTTON name="retrigger button" id="1b86153e19e7aa57" memberName="retriggerButton"
+                virtualName="" explicitFocusOrder="0" pos="176 40 136 24" buttonText="Retriggerable"
+                connectedEdges="0" needsCallback="1" radioGroupId="0" state="0"/>
+</JUCER_COMPONENT>
+
+END_JUCER_METADATA
+*/
+#endif
+
+
+//[EndFile] You can add extra defines here...
+#endif      // TOUCHKEYS_NO_GUI
+//[/EndFile]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingShortEditor.h	Wed Apr 22 21:37:51 2015 +0100
@@ -0,0 +1,83 @@
+/*
+  ==============================================================================
+
+  This is an automatically generated GUI class created by the Introjucer!
+
+  Be careful when adding custom code to these files, as only the code within
+  the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
+  and re-saved.
+
+  Created with Introjucer version: 3.1.1
+
+  ------------------------------------------------------------------------------
+
+  The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
+  Copyright 2004-13 by Raw Material Software Ltd.
+
+  ==============================================================================
+*/
+
+#ifndef __JUCE_HEADER_3E71655728420A1E__
+#define __JUCE_HEADER_3E71655728420A1E__
+
+//[Headers]     -- You can add your own extra header files here --
+#ifndef TOUCHKEYS_NO_GUI
+
+#include "JuceHeader.h"
+#include "TouchkeyKeyDivisionMappingFactory.h"
+//[/Headers]
+
+
+
+//==============================================================================
+/**
+                                                                    //[Comments]
+    An auto-generated component, created by the Introjucer.
+
+    Describe your class and how it works here!
+                                                                    //[/Comments]
+*/
+class TouchkeyKeyDivisionMappingShortEditor  : public MappingEditorComponent,
+                                               public TextEditor::Listener,
+                                               public ComboBoxListener,
+                                               public ButtonListener
+{
+public:
+    //==============================================================================
+    TouchkeyKeyDivisionMappingShortEditor (TouchkeyKeyDivisionMappingFactory& factory);
+    ~TouchkeyKeyDivisionMappingShortEditor();
+
+    //==============================================================================
+    //[UserMethods]     -- You can add your own custom methods in this section.
+    void synchronize();
+    //[/UserMethods]
+
+    void paint (Graphics& g);
+    void resized();
+    void comboBoxChanged (ComboBox* comboBoxThatHasChanged);
+    void buttonClicked (Button* buttonThatWasClicked);
+
+
+
+private:
+    //[UserVariables]   -- You can add your own custom variables in this section.
+    TouchkeyKeyDivisionMappingFactory& factory_;
+    //[/UserVariables]
+
+    //==============================================================================
+    ScopedPointer<ComboBox> tuningComboBox;
+    ScopedPointer<Label> tuningLabel;
+    ScopedPointer<Label> controlLabel;
+    ScopedPointer<ComboBox> controlComboBox;
+    ScopedPointer<ToggleButton> retriggerButton;
+
+
+    //==============================================================================
+    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TouchkeyKeyDivisionMappingShortEditor)
+};
+
+//[EndFile] You can add extra defines here...
+#endif  // TOUCHKEYS_NO_GUI
+//[/EndFile]
+
+#endif   // __JUCE_HEADER_3E71655728420A1E__
--- a/Source/TouchKeys/MidiInputController.h	Mon Apr 13 20:51:17 2015 -0700
+++ b/Source/TouchKeys/MidiInputController.h	Wed Apr 22 21:37:51 2015 +0100
@@ -66,7 +66,6 @@
 public:
 	// Constructor
 	MidiInputController(PianoKeyboard& keyboard);
-
 	
 	// Query available devices
 	vector<pair<int, string> > availableMidiDevices();
--- a/Source/TouchKeys/MidiKeyboardSegment.cpp	Mon Apr 13 20:51:17 2015 -0700
+++ b/Source/TouchKeys/MidiKeyboardSegment.cpp	Wed Apr 22 21:37:51 2015 +0100
@@ -731,7 +731,7 @@
 
 // Return whethera  given mapping is experimental or not
 bool MidiKeyboardSegment::mappingIsExperimental(int index) {
-    if(index > 2 && index != 4)
+    if(index == 5)
         return true;
     return false;
 }
--- a/TouchKeys.jucer	Mon Apr 13 20:51:17 2015 -0700
+++ b/TouchKeys.jucer	Wed Apr 22 21:37:51 2015 +0100
@@ -108,6 +108,10 @@
                 compile="0" resource="0" file="Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingFactory.h"/>
         </GROUP>
         <GROUP id="{B7052E7F-7DB4-7699-AD97-74D46364BDA3}" name="KeyDivision">
+          <FILE id="EPa41J" name="TouchkeyKeyDivisionMappingShortEditor.cpp"
+                compile="1" resource="0" file="Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingShortEditor.cpp"/>
+          <FILE id="KtBp9r" name="TouchkeyKeyDivisionMappingShortEditor.h" compile="0"
+                resource="0" file="Source/Mappings/KeyDivision/TouchkeyKeyDivisionMappingShortEditor.h"/>
           <FILE id="eVkMwv" name="TouchkeyKeyDivisionMapping.cpp" compile="1"
                 resource="0" file="Source/Mappings/KeyDivision/TouchkeyKeyDivisionMapping.cpp"/>
           <FILE id="ooctzV" name="TouchkeyKeyDivisionMapping.h" compile="0" resource="0"