# HG changeset patch # User Andrew McPherson # Date 1408636959 -3600 # Node ID 1526d2fbe01e1ba6cdf1415a319c190c81790be6 # Parent 85577160a0d476f5ea44b979d744e05096ce3471 Updates to multi-finger trigger mapping, and a fix for control-change retransmission on loading presets. diff -r 85577160a0d4 -r 1526d2fbe01e Builds/Linux/Makefile --- a/Builds/Linux/Makefile Sat Jun 21 23:32:33 2014 +0100 +++ b/Builds/Linux/Makefile Thu Aug 21 17:02:39 2014 +0100 @@ -65,6 +65,7 @@ $(OBJDIR)/TouchkeyPitchBendMappingFactory_9fc4ef9e.o \ $(OBJDIR)/TouchkeyOnsetAngleMapping_a77ca3ca.o \ $(OBJDIR)/TouchkeyOnsetAngleMappingFactory_6a4803ea.o \ + $(OBJDIR)/TouchkeyMultiFingerTriggerMappingShortEditor_8604e029.o \ $(OBJDIR)/TouchkeyMultiFingerTriggerMapping_f7bfe8a.o \ $(OBJDIR)/TouchkeyMultiFingerTriggerMappingFactory_e811112a.o \ $(OBJDIR)/TouchkeyKeyDivisionMapping_cea38eb0.o \ @@ -216,6 +217,11 @@ @echo "Compiling TouchkeyOnsetAngleMappingFactory.cpp" @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" +$(OBJDIR)/TouchkeyMultiFingerTriggerMappingShortEditor_8604e029.o: ../../Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingShortEditor.cpp + -@mkdir -p $(OBJDIR) + @echo "Compiling TouchkeyMultiFingerTriggerMappingShortEditor.cpp" + @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" + $(OBJDIR)/TouchkeyMultiFingerTriggerMapping_f7bfe8a.o: ../../Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMapping.cpp -@mkdir -p $(OBJDIR) @echo "Compiling TouchkeyMultiFingerTriggerMapping.cpp" diff -r 85577160a0d4 -r 1526d2fbe01e Builds/Linux32/Makefile --- a/Builds/Linux32/Makefile Sat Jun 21 23:32:33 2014 +0100 +++ b/Builds/Linux32/Makefile Thu Aug 21 17:02:39 2014 +0100 @@ -65,6 +65,7 @@ $(OBJDIR)/TouchkeyPitchBendMappingFactory_9fc4ef9e.o \ $(OBJDIR)/TouchkeyOnsetAngleMapping_a77ca3ca.o \ $(OBJDIR)/TouchkeyOnsetAngleMappingFactory_6a4803ea.o \ + $(OBJDIR)/TouchkeyMultiFingerTriggerMappingShortEditor_8604e029.o \ $(OBJDIR)/TouchkeyMultiFingerTriggerMapping_f7bfe8a.o \ $(OBJDIR)/TouchkeyMultiFingerTriggerMappingFactory_e811112a.o \ $(OBJDIR)/TouchkeyKeyDivisionMapping_cea38eb0.o \ @@ -216,6 +217,11 @@ @echo "Compiling TouchkeyOnsetAngleMappingFactory.cpp" @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" +$(OBJDIR)/TouchkeyMultiFingerTriggerMappingShortEditor_8604e029.o: ../../Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingShortEditor.cpp + -@mkdir -p $(OBJDIR) + @echo "Compiling TouchkeyMultiFingerTriggerMappingShortEditor.cpp" + @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" + $(OBJDIR)/TouchkeyMultiFingerTriggerMapping_f7bfe8a.o: ../../Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMapping.cpp -@mkdir -p $(OBJDIR) @echo "Compiling TouchkeyMultiFingerTriggerMapping.cpp" diff -r 85577160a0d4 -r 1526d2fbe01e Source/MainApplicationController.cpp --- a/Source/MainApplicationController.cpp Sat Jun 21 23:32:33 2014 +0100 +++ b/Source/MainApplicationController.cpp Thu Aug 21 17:02:39 2014 +0100 @@ -102,6 +102,7 @@ if(touchkeySensorTestIsRunning()) touchkeySensorTestStop(); #endif + removeAllOscListeners(); } // Actions here run in the JUCE initialise() method once the application is loaded @@ -121,10 +122,10 @@ MappingFactory *factory = new TouchkeyVibratoMappingFactory(keyboardController_, *segment); if(factory != 0) - segment->addMappingFactory(factory); + segment->addMappingFactory(factory, true); factory = new TouchkeyPitchBendMappingFactory(keyboardController_, *segment); if(factory != 0) - segment->addMappingFactory(factory); + segment->addMappingFactory(factory, true); } } else if(!getPrefsStartupPresetNone()) { @@ -816,7 +817,7 @@ // Return whethera given mapping is experimental or not bool MainApplicationController::mappingIsExperimental(int index) { - if(index > 2) + if(index > 2 && index != 4) return true; return false; } @@ -1163,6 +1164,8 @@ return false; } + keyboardTesterWindow_->setVisible(true); + touchkeyErrorMessage_ = ""; touchkeyErrorOccurred_ = false; return true; diff -r 85577160a0d4 -r 1526d2fbe01e Source/Mappings/KeyDivision/TouchkeyKeyDivisionMapping.h --- a/Source/Mappings/KeyDivision/TouchkeyKeyDivisionMapping.h Sat Jun 21 23:32:33 2014 +0100 +++ b/Source/Mappings/KeyDivision/TouchkeyKeyDivisionMapping.h Thu Aug 21 17:02:39 2014 +0100 @@ -35,7 +35,7 @@ friend class TouchkeyKeyDivisionMappingFactory; public: enum { - kDetectionParameterYPosition, + kDetectionParameterYPosition = 1, kDetectionParameterNumberOfTouches, kDetectionParameterYPositionAndNumberOfTouches }; diff -r 85577160a0d4 -r 1526d2fbe01e Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMapping.cpp --- a/Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMapping.cpp Sat Jun 21 23:32:33 2014 +0100 +++ b/Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMapping.cpp Thu Aug 21 17:02:39 2014 +0100 @@ -23,6 +23,7 @@ */ #include "TouchkeyMultiFingerTriggerMapping.h" +#include "TouchkeyMultiFingerTriggerMappingFactory.h" #include "../../TouchKeys/MidiOutputController.h" // Class constants @@ -30,7 +31,13 @@ const int TouchkeyMultiFingerTriggerMapping::kDefaultNumTouchesForTrigger = 2; const int TouchkeyMultiFingerTriggerMapping::kDefaultNumFramesForTrigger = 2; const int TouchkeyMultiFingerTriggerMapping::kDefaultNumConsecutiveTapsForTrigger = 1; -const timestamp_diff_type TouchkeyMultiFingerTriggerMapping::kDefaultMaxTapSpacing = milliseconds_to_timestamp(500.0); +const timestamp_diff_type TouchkeyMultiFingerTriggerMapping::kDefaultMaxTapSpacing = milliseconds_to_timestamp(300.0); +const int TouchkeyMultiFingerTriggerMapping::kDefaultTriggerOnAction = TouchkeyMultiFingerTriggerMapping::kActionNoteOn; +const int TouchkeyMultiFingerTriggerMapping::kDefaultTriggerOffAction = TouchkeyMultiFingerTriggerMapping::kActionNone; +const int TouchkeyMultiFingerTriggerMapping::kDefaultTriggerOnNoteNum = -1; +const int TouchkeyMultiFingerTriggerMapping::kDefaultTriggerOffNoteNum = -1; +const int TouchkeyMultiFingerTriggerMapping::kDefaultTriggerOnNoteVel = -1; +const int TouchkeyMultiFingerTriggerMapping::kDefaultTriggerOffNoteVel = -1; // Main constructor takes references/pointers from objects which keep track // of touch location, continuous key position and the state detected from that @@ -42,11 +49,31 @@ : TouchkeyBaseMapping(keyboard, factory, noteNumber, touchBuffer, positionBuffer, positionTracker), numTouchesForTrigger_(kDefaultNumTouchesForTrigger), numFramesForTrigger_(kDefaultNumFramesForTrigger), numConsecutiveTapsForTrigger_(kDefaultNumConsecutiveTapsForTrigger), maxTapSpacing_(kDefaultMaxTapSpacing), -needsMidiNoteOn_(true), pastSamples_(kDefaultFilterBufferLength) +needsMidiNoteOn_(true), triggerOnAction_(kDefaultTriggerOnAction), triggerOffAction_(kDefaultTriggerOffAction), +triggerOnNoteNum_(kDefaultTriggerOnNoteNum), triggerOffNoteNum_(kDefaultTriggerOffNoteNum), +triggerOnNoteVel_(kDefaultTriggerOnNoteVel), triggerOffNoteVel_(kDefaultTriggerOffNoteVel), +pastSamples_(kDefaultFilterBufferLength) { reset(); } +// Turn off mapping of data. +void TouchkeyMultiFingerTriggerMapping::disengage(bool shouldDelete) { + // Send note off messages for anything currently on + std::set >::iterator it; + int port = static_cast(factory_)->segment().outputPort(); + + for(it = otherNotesOn_.begin(); it != otherNotesOn_.end(); ++it) { + int ch = it->first; + int note = it->second; + + keyboard_.midiOutputController()->sendNoteOn(port, ch, note, 0); + } + + otherNotesOn_.clear(); + TouchkeyBaseMapping::disengage(shouldDelete); +} + // Reset state back to defaults void TouchkeyMultiFingerTriggerMapping::reset() { ScopedLock sl(sampleBufferMutex_); @@ -68,6 +95,50 @@ // Message is only sent at release; resend may not apply here. } +void TouchkeyMultiFingerTriggerMapping::setTouchesForTrigger(int touches) { + numTouchesForTrigger_ = touches; +} + +void TouchkeyMultiFingerTriggerMapping::setFramesForTrigger(int frames) { + numFramesForTrigger_ = frames; +} + +void TouchkeyMultiFingerTriggerMapping::setConsecutiveTapsForTrigger(int taps) { + numConsecutiveTapsForTrigger_ = taps; +} + +void TouchkeyMultiFingerTriggerMapping::setMaxTimeBetweenTapsForTrigger(timestamp_diff_type timeDiff) { + maxTapSpacing_ = timeDiff; +} + +void TouchkeyMultiFingerTriggerMapping::setNeedsMidiNoteOn(bool needsMidi) { + needsMidiNoteOn_ = needsMidi; +} + +void TouchkeyMultiFingerTriggerMapping::setTriggerOnAction(int action) { + triggerOnAction_ = action; +} + +void TouchkeyMultiFingerTriggerMapping::setTriggerOffAction(int action) { + triggerOffAction_ = action; +} + +void TouchkeyMultiFingerTriggerMapping::setTriggerOnNoteNumber(int note) { + triggerOnNoteNum_ = note; +} + +void TouchkeyMultiFingerTriggerMapping::setTriggerOffNoteNumber(int note) { + triggerOffNoteNum_ = note; +} + +void TouchkeyMultiFingerTriggerMapping::setTriggerOnNoteVelocity(int velocity) { + triggerOnNoteVel_ = velocity; +} + +void TouchkeyMultiFingerTriggerMapping::setTriggerOffNoteVelocity(int velocity) { + triggerOffNoteVel_ = velocity; +} + // This method receives data from the touch buffer or possibly the continuous key angle (not used here) void TouchkeyMultiFingerTriggerMapping::triggerReceived(TriggerSource* who, timestamp_type timestamp) { if(needsMidiNoteOn_ && !noteIsOn_) { @@ -106,8 +177,6 @@ else tapsCount_ = 1; - std::cout << "Tap " << tapsCount_ << std::endl; - // Check if the right number of taps has elapsed if(tapsCount_ >= numConsecutiveTapsForTrigger_ && !hasTriggered_) { hasTriggered_ = true; @@ -173,54 +242,87 @@ } void TouchkeyMultiFingerTriggerMapping::generateTriggerOn(timestamp_type timestamp, timestamp_diff_type timeBetweenTaps, float distanceBetweenPoints) { - std::cout << "Trigger distance = " << distanceBetweenPoints << " timing = " << timeBetweenTaps << std::endl; - // KLUDGE if(!suspended_) { -#if 0 - if(distanceBetweenPoints > 0.35) { - //keyboard_.sendMessage("/touchkeys/pitchbend", "if", noteNumber_, 2.0, LO_ARGS_END); + if(triggerOnAction_ == kActionNoteOn || + triggerOnAction_ == kActionNoteOff) { + // Send a MIDI note on message with given note number and velocity + int port = static_cast(factory_)->segment().outputPort(); int ch = keyboard_.key(noteNumber_)->midiChannel(); - int vel = keyboard_.key(noteNumber_)->midiVelocity(); - keyboard_.midiOutputController()->sendNoteOn(0, ch, noteNumber_ + 14, vel); - //keyboard_.midiOutputController()->sendNoteOff(0, ch, noteNumber_ + 12, vel); + int vel = triggerOnNoteVel_; + int note = triggerOnNoteNum_; + if(note < 0) // note < 0 means current note + note = noteNumber_; + if(note < 128) { + if(triggerOnAction_ == kActionNoteOn) { + // Can't send notes above 127... + if(vel < 0) // vel < 0 means same as current + vel = keyboard_.key(noteNumber_)->midiVelocity(); + if(vel > 127) + vel = 127; + + // Register that this note has been turned on + if(note != noteNumber_) + otherNotesOn_.insert(std::pair(ch, note)); + } + else { + // Note off + vel = 0; + if(note != noteNumber_) { + // Unregister this note if we are turning it off + if(otherNotesOn_.count(std::pair(ch, note)) > 0) { + otherNotesOn_.erase(std::pair(ch, note)); + } + } + } + + keyboard_.midiOutputController()->sendNoteOn(port, ch, note, vel); + } } - else { - //keyboard_.sendMessage("/touchkeys/pitchbend", "if", noteNumber_, 1.0, LO_ARGS_END); - int ch = keyboard_.key(noteNumber_)->midiChannel(); - int vel = keyboard_.key(noteNumber_)->midiVelocity(); - keyboard_.midiOutputController()->sendNoteOn(0, ch, noteNumber_ + 13, vel); - //keyboard_.midiOutputController()->sendNoteOff(0, ch, noteNumber_ + 12, vel); - } -#elif 0 - int ch = keyboard_.key(noteNumber_)->midiChannel(); - keyboard_.midiOutputController()->sendControlChange(0, ch, 73, 127); -#else - keyboard_.midiOutputController()->sendNoteOn(0, keyboard_.key(noteNumber_)->midiChannel(), noteNumber_, 127); -#endif } } void TouchkeyMultiFingerTriggerMapping::generateTriggerOff(timestamp_type timestamp) { - std::cout << "Trigger off\n"; if(!suspended_) { -#if 0 - //eyboard_.sendMessage("/touchkeys/pitchbend", "if", noteNumber_, 0.0, LO_ARGS_END); - int ch = keyboard_.key(noteNumber_)->midiChannel(); - int vel = keyboard_.key(noteNumber_)->midiVelocity(); - keyboard_.midiOutputController()->sendNoteOn(0, ch, noteNumber_ + 12, vel); - //keyboard_.midiOutputController()->sendNoteOff(0, ch, noteNumber_ + 13, vel); - //keyboard_.midiOutputController()->sendNoteOff(0, ch, noteNumber_ + 14, vel); -#elif 0 - int ch = keyboard_.key(noteNumber_)->midiChannel(); - keyboard_.midiOutputController()->sendControlChange(0, ch, 73, 0); -#else - keyboard_.midiOutputController()->sendNoteOn(0, keyboard_.key(noteNumber_)->midiChannel(), noteNumber_, 127); -#endif + if(triggerOffAction_ == kActionNoteOn || + triggerOffAction_ == kActionNoteOff) { + // Send a MIDI note on message with given note number and velocity + int port = static_cast(factory_)->segment().outputPort(); + int ch = keyboard_.key(noteNumber_)->midiChannel(); + int vel = triggerOffNoteVel_; + int note = triggerOffNoteNum_; + if(note < 0) // note < 0 means current note + note = noteNumber_; + if(note < 128) { + if(triggerOffAction_ == kActionNoteOn) { + // Can't send notes above 127... + if(vel < 0) // vel < 0 means same as current + vel = keyboard_.key(noteNumber_)->midiVelocity(); + if(vel > 127) + vel = 127; + + // Register that this note has been turned on + if(note != noteNumber_) + otherNotesOn_.insert(std::pair(ch, note)); + } + else { + // Note off + vel = 0; + if(note != noteNumber_) { + // Unregister this note if we are turning it off + if(otherNotesOn_.count(std::pair(ch, note)) > 0) { + otherNotesOn_.erase(std::pair(ch, note)); + } + } + } + + keyboard_.midiOutputController()->sendNoteOn(port, ch, note, vel); + } + } } } // MIDI note-off message received void TouchkeyMultiFingerTriggerMapping::midiNoteOffReceived(int channel) { - int ch = keyboard_.key(noteNumber_)->midiChannel(); - keyboard_.midiOutputController()->sendControlChange(0, ch, 73, 0); + // int ch = keyboard_.key(noteNumber_)->midiChannel(); + // keyboard_.midiOutputController()->sendControlChange(0, ch, 73, 0); } diff -r 85577160a0d4 -r 1526d2fbe01e Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMapping.h --- a/Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMapping.h Sat Jun 21 23:32:33 2014 +0100 +++ b/Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMapping.h Thu Aug 21 17:02:39 2014 +0100 @@ -26,11 +26,23 @@ #define __TouchKeys__TouchkeyMultiFingerTriggerMapping__ #include "../TouchkeyBaseMapping.h" +#include + +class TouchkeyMultiFingerTriggerMappingFactory; // This class handles the detection of finger motion specifically at // note release, which can be used to trigger specific release effects. class TouchkeyMultiFingerTriggerMapping : public TouchkeyBaseMapping { + friend class TouchkeyMultiFingerTriggerMappingFactory; +public: + enum { + kActionNone = 1, + kActionNoteOn, + kActionNoteOff, + kActionMax + }; + private: // Default values /*constexpr static const int kDefaultFilterBufferLength = 30; @@ -43,7 +55,13 @@ static const int kDefaultNumFramesForTrigger; static const int kDefaultNumConsecutiveTapsForTrigger; static const timestamp_diff_type kDefaultMaxTapSpacing; - + static const int kDefaultTriggerOnAction; + static const int kDefaultTriggerOffAction; + static const int kDefaultTriggerOnNoteNum; + static const int kDefaultTriggerOffNoteNum; + static const int kDefaultTriggerOnNoteVel; + static const int kDefaultTriggerOffNoteVel; + public: // ***** Constructors ***** @@ -53,12 +71,28 @@ // ***** Modifiers ***** + // Disable mappings from being sent + void disengage(bool shouldDelete = false); + // Reset the state back initial values void reset(); // Resend the current state of all parameters void resend(); + // Parameters for multi-finger trigger + void setTouchesForTrigger(int touches); + void setFramesForTrigger(int frames); + void setConsecutiveTapsForTrigger(int taps); + void setMaxTimeBetweenTapsForTrigger(timestamp_diff_type timeDiff); + void setNeedsMidiNoteOn(bool needsMidi); + void setTriggerOnAction(int action); + void setTriggerOffAction(int action); + void setTriggerOnNoteNumber(int note); + void setTriggerOffNoteNumber(int note); + void setTriggerOnNoteVelocity(int velocity); + void setTriggerOffNoteVelocity(int velocity); + // ***** Evaluators ***** // This method receives triggers whenever events occur in the touch data or the @@ -89,6 +123,9 @@ int numConsecutiveTapsForTrigger_; // How many taps with this number of touches are needed to trigger timestamp_diff_type maxTapSpacing_; // How far apart the taps can come and be considered a multi-tap gesture bool needsMidiNoteOn_; // Whether the MIDI note has to be on for this gesture to trigger + int triggerOnAction_, triggerOffAction_; // Actions to take on trigger on/off + int triggerOnNoteNum_, triggerOffNoteNum_; // Which notes to send if a note is being sent + int triggerOnNoteVel_, triggerOffNoteVel_; // Velocity to send if a note is being sent int lastNumActiveTouches_; // How many touches were active before float lastActiveTouchLocations_[3]; // Where (Y coord.) the active touches were last frame @@ -98,6 +135,8 @@ timestamp_type lastTapStartTimestamp_; // When the last tap ended bool hasTriggered_; // Whether we've generated a trigger + std::set > otherNotesOn_; // Which other notes are on as a result of triggers? + Node pastSamples_; // Locations of touch CriticalSection sampleBufferMutex_; // Mutex to protect threaded access to sample buffer }; diff -r 85577160a0d4 -r 1526d2fbe01e Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingFactory.cpp --- a/Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingFactory.cpp Sat Jun 21 23:32:33 2014 +0100 +++ b/Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingFactory.cpp Thu Aug 21 17:02:39 2014 +0100 @@ -23,6 +23,89 @@ */ #include "TouchkeyMultiFingerTriggerMappingFactory.h" +#include "TouchkeyMultiFingerTriggerMappingShortEditor.h" + +TouchkeyMultiFingerTriggerMappingFactory::TouchkeyMultiFingerTriggerMappingFactory(PianoKeyboard &keyboard, MidiKeyboardSegment& segment) +: TouchkeyBaseMappingFactory(keyboard, segment), +numTouchesForTrigger_(TouchkeyMultiFingerTriggerMapping::kDefaultNumTouchesForTrigger), +numFramesForTrigger_(TouchkeyMultiFingerTriggerMapping::kDefaultNumFramesForTrigger), +numConsecutiveTapsForTrigger_(TouchkeyMultiFingerTriggerMapping::kDefaultNumConsecutiveTapsForTrigger), +maxTapSpacing_(TouchkeyMultiFingerTriggerMapping::kDefaultMaxTapSpacing), +needsMidiNoteOn_(true), +triggerOnAction_(TouchkeyMultiFingerTriggerMapping::kDefaultTriggerOnAction), +triggerOffAction_(TouchkeyMultiFingerTriggerMapping::kDefaultTriggerOffAction), +triggerOnNoteNum_(TouchkeyMultiFingerTriggerMapping::kDefaultTriggerOnNoteNum), +triggerOffNoteNum_(TouchkeyMultiFingerTriggerMapping::kDefaultTriggerOffNoteNum), +triggerOnNoteVel_(TouchkeyMultiFingerTriggerMapping::kDefaultTriggerOnNoteVel), +triggerOffNoteVel_(TouchkeyMultiFingerTriggerMapping::kDefaultTriggerOffNoteVel) +{ + +} + +void TouchkeyMultiFingerTriggerMappingFactory::setTouchesForTrigger(int touches) { + if(touches < 1) + touches = 1; + if(touches > 3) + touches = 3; + numTouchesForTrigger_ = touches; +} + +void TouchkeyMultiFingerTriggerMappingFactory::setFramesForTrigger(int frames) { + if(frames < 1) + frames = 1; + numFramesForTrigger_ = frames; +} + +void TouchkeyMultiFingerTriggerMappingFactory::setConsecutiveTapsForTrigger(int taps) { + if(taps < 1) + taps = 1; + numConsecutiveTapsForTrigger_ = taps; +} + +void TouchkeyMultiFingerTriggerMappingFactory::setMaxTimeBetweenTapsForTrigger(timestamp_diff_type timeDiff) { + if(timeDiff < 0) + timeDiff = 0; + maxTapSpacing_ = timeDiff; +} + +void TouchkeyMultiFingerTriggerMappingFactory::setNeedsMidiNoteOn(bool needsMidi) { + needsMidiNoteOn_ = needsMidi; +} + +void TouchkeyMultiFingerTriggerMappingFactory::setTriggerOnAction(int action) { + if(action > 0 && action < TouchkeyMultiFingerTriggerMapping::kActionMax) + triggerOnAction_ = action; +} + +void TouchkeyMultiFingerTriggerMappingFactory::setTriggerOffAction(int action) { + if(action > 0 && action < TouchkeyMultiFingerTriggerMapping::kActionMax) + triggerOffAction_ = action; +} + +void TouchkeyMultiFingerTriggerMappingFactory::setTriggerOnNoteNumber(int note) { + triggerOnNoteNum_ = note; +} + +void TouchkeyMultiFingerTriggerMappingFactory::setTriggerOffNoteNumber(int note) { + triggerOffNoteNum_ = note; +} + +void TouchkeyMultiFingerTriggerMappingFactory::setTriggerOnNoteVelocity(int velocity) { + if(velocity > 127) + velocity = 127; + triggerOnNoteVel_ = velocity; +} + +void TouchkeyMultiFingerTriggerMappingFactory::setTriggerOffNoteVelocity(int velocity) { + if(velocity > 127) + velocity = 127; + triggerOffNoteVel_ = velocity; +} + +// ***** GUI Support ***** +MappingEditorComponent* TouchkeyMultiFingerTriggerMappingFactory::createBasicEditor() { + return new TouchkeyMultiFingerTriggerMappingShortEditor(*this); +} // ****** Preset Save/Load ****** XmlElement* TouchkeyMultiFingerTriggerMappingFactory::getPreset() { @@ -30,7 +113,17 @@ storeCommonProperties(properties); - // No properties for now + properties.setValue("numTouchesForTrigger", numTouchesForTrigger_); + properties.setValue("numFramesForTrigger", numFramesForTrigger_); + properties.setValue("numConsecutiveTapsForTrigger", numConsecutiveTapsForTrigger_); + properties.setValue("maxTapSpacing", maxTapSpacing_); + properties.setValue("needsMidiNoteOn", needsMidiNoteOn_); + properties.setValue("triggerOnAction", triggerOnAction_); + properties.setValue("triggerOffAction", triggerOffAction_); + properties.setValue("triggerOnNoteNum", triggerOnNoteNum_); + properties.setValue("triggerOffNoteNum", triggerOffNoteNum_); + properties.setValue("triggerOnNoteVel", triggerOnNoteVel_); + properties.setValue("triggerOffNoteVel", triggerOffNoteVel_); XmlElement* preset = properties.createXml("MappingFactory"); preset->setAttribute("type", "MultiFingerTrigger"); @@ -48,7 +141,46 @@ if(!loadCommonProperties(properties)) return false; - // Nothing specific to do for now + // Load specific properties + if(properties.containsKey("numTouchesForTrigger")) + numTouchesForTrigger_ = properties.getIntValue("numTouchesForTrigger"); + if(properties.containsKey("numFramesForTrigger")) + numFramesForTrigger_ = properties.getIntValue("numFramesForTrigger"); + if(properties.containsKey("numConsecutiveTapsForTrigger")) + numConsecutiveTapsForTrigger_ = properties.getIntValue("numConsecutiveTapsForTrigger"); + if(properties.containsKey("maxTapSpacing")) + maxTapSpacing_ = properties.getDoubleValue("maxTapSpacing"); + if(properties.containsKey("needsMidiNoteOn")) + needsMidiNoteOn_ = properties.getBoolValue("needsMidiNoteOn"); + if(properties.containsKey("triggerOnAction")) + triggerOnAction_ = properties.getBoolValue("triggerOnAction"); + if(properties.containsKey("triggerOffAction")) + triggerOffAction_ = properties.getBoolValue("triggerOffAction"); + if(properties.containsKey("triggerOnNoteNum")) + triggerOnNoteNum_ = properties.getBoolValue("triggerOnNoteNum"); + if(properties.containsKey("triggerOffNoteNum")) + triggerOffNoteNum_ = properties.getBoolValue("triggerOffNoteNum"); + if(properties.containsKey("triggerOnNoteVel")) + triggerOnNoteVel_ = properties.getBoolValue("triggerOnNoteVel"); + if(properties.containsKey("triggerOffNoteVel")) + triggerOffNoteVel_ = properties.getBoolValue("triggerOffNoteVel"); return true; } + +// ***** Private Methods ***** + +// Set the initial parameters for a new mapping +void TouchkeyMultiFingerTriggerMappingFactory::initializeMappingParameters(int noteNumber, TouchkeyMultiFingerTriggerMapping *mapping) { + mapping->setTouchesForTrigger(numTouchesForTrigger_); + mapping->setFramesForTrigger(numFramesForTrigger_); + mapping->setConsecutiveTapsForTrigger(numConsecutiveTapsForTrigger_); + mapping->setMaxTimeBetweenTapsForTrigger(maxTapSpacing_); + mapping->setNeedsMidiNoteOn(needsMidiNoteOn_); + mapping->setTriggerOnAction(triggerOnAction_); + mapping->setTriggerOffAction(triggerOffAction_); + mapping->setTriggerOnNoteNumber(triggerOnNoteNum_); + mapping->setTriggerOffNoteNumber(triggerOffNoteNum_); + mapping->setTriggerOnNoteVelocity(triggerOnNoteVel_); + mapping->setTriggerOffNoteVelocity(triggerOffNoteVel_); +} diff -r 85577160a0d4 -r 1526d2fbe01e Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingFactory.h --- a/Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingFactory.h Sat Jun 21 23:32:33 2014 +0100 +++ b/Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingFactory.h Thu Aug 21 17:02:39 2014 +0100 @@ -36,8 +36,7 @@ // ***** Constructor ***** // Default constructor, containing a reference to the PianoKeyboard class. - TouchkeyMultiFingerTriggerMappingFactory(PianoKeyboard &keyboard, MidiKeyboardSegment& segment) - : TouchkeyBaseMappingFactory(keyboard, segment) {} + TouchkeyMultiFingerTriggerMappingFactory(PianoKeyboard &keyboard, MidiKeyboardSegment& segment); // ***** Destructor ***** @@ -47,9 +46,56 @@ virtual const std::string factoryTypeName() { return "Multi-Finger\nTrigger"; } + // ***** Class-Specific Methods ***** + + // Parameters for multi-finger trigger + int getTouchesForTrigger() { return numTouchesForTrigger_; } + int getFramesForTrigger() { return numFramesForTrigger_; } + int getConsecutiveTapsForTrigger() { return numConsecutiveTapsForTrigger_; } + timestamp_diff_type getMaxTimeBetweenTapsForTrigger() { return maxTapSpacing_; } + bool getNeedsMidiNoteOn() { return needsMidiNoteOn_; } + int getTriggerOnAction() { return triggerOnAction_; } + int getTriggerOffAction() { return triggerOffAction_; } + int getTriggerOnNoteNumber() { return triggerOnNoteNum_; } + int getTriggerOffNoteNumber() { return triggerOffNoteNum_; } + int getTriggerOnNoteVelocity() { return triggerOnNoteVel_; } + int getTriggerOffNoteVelocity() { return triggerOffNoteVel_; } + + void setTouchesForTrigger(int touches); + void setFramesForTrigger(int frames); + void setConsecutiveTapsForTrigger(int taps); + void setMaxTimeBetweenTapsForTrigger(timestamp_diff_type timeDiff); + void setNeedsMidiNoteOn(bool needsMidi); + void setTriggerOnAction(int action); + void setTriggerOffAction(int action); + void setTriggerOnNoteNumber(int note); + void setTriggerOffNoteNumber(int note); + void setTriggerOnNoteVelocity(int velocity); + void setTriggerOffNoteVelocity(int velocity); + + // ***** GUI Support ***** + bool hasBasicEditor() { return true; } + MappingEditorComponent* createBasicEditor(); + bool hasExtendedEditor() { return false; } + MappingEditorComponent* createExtendedEditor() { return nullptr; } + // ****** Preset Save/Load ****** XmlElement* getPreset(); bool loadPreset(XmlElement const* preset); + +private: + // ***** Private Methods ***** + void initializeMappingParameters(int noteNumber, TouchkeyMultiFingerTriggerMapping *mapping); + + // Parameters + int numTouchesForTrigger_; // How many touches are needed for a trigger + int numFramesForTrigger_; // How many consecutive frames with these touches are needed to trigger + int numConsecutiveTapsForTrigger_; // How many taps with this number of touches are needed to trigger + timestamp_diff_type maxTapSpacing_; // How far apart the taps can come and be considered a multi-tap gesture + bool needsMidiNoteOn_; // Whether the MIDI note has to be on for this gesture to trigger + int triggerOnAction_, triggerOffAction_; // Actions to take on trigger on/off + int triggerOnNoteNum_, triggerOffNoteNum_; // Which notes to send if a note is being sent + int triggerOnNoteVel_, triggerOffNoteVel_; // Velocity to send if a note is being sent }; #endif /* defined(__TouchKeys__TouchkeyMultiFingerTriggerMappingFactory__) */ diff -r 85577160a0d4 -r 1526d2fbe01e Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingShortEditor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingShortEditor.cpp Thu Aug 21 17:02:39 2014 +0100 @@ -0,0 +1,275 @@ +/* + ============================================================================== + + 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.0 + + ------------------------------------------------------------------------------ + + 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... +//[/Headers] + +#include "TouchkeyMultiFingerTriggerMappingShortEditor.h" + + +//[MiscUserDefs] You can add your own user definitions and misc code here... +const int TouchkeyMultiFingerTriggerMappingShortEditor::kNoteSame = 256; +const int TouchkeyMultiFingerTriggerMappingShortEditor::kNoteOffset = 1; +//[/MiscUserDefs] + +//============================================================================== +TouchkeyMultiFingerTriggerMappingShortEditor::TouchkeyMultiFingerTriggerMappingShortEditor (TouchkeyMultiFingerTriggerMappingFactory& factory) + : factory_(factory) +{ + addAndMakeVisible (controlLabel = new Label ("control label", + "Touches:")); + controlLabel->setFont (Font (15.00f, Font::plain)); + controlLabel->setJustificationType (Justification::centredRight); + controlLabel->setEditable (false, false, false); + controlLabel->setColour (TextEditor::textColourId, Colours::black); + controlLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (touchesComboBox = new ComboBox ("control combo box")); + touchesComboBox->setEditableText (false); + touchesComboBox->setJustificationType (Justification::centredLeft); + touchesComboBox->setTextWhenNothingSelected (String::empty); + touchesComboBox->setTextWhenNoChoicesAvailable ("(no choices)"); + touchesComboBox->addListener (this); + + addAndMakeVisible (controlLabel2 = new Label ("control label", + "Repeat Taps:")); + controlLabel2->setFont (Font (15.00f, Font::plain)); + controlLabel2->setJustificationType (Justification::centredLeft); + controlLabel2->setEditable (false, false, false); + controlLabel2->setColour (TextEditor::textColourId, Colours::black); + controlLabel2->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (tapsComboBox = new ComboBox ("control combo box")); + tapsComboBox->setEditableText (false); + tapsComboBox->setJustificationType (Justification::centredLeft); + tapsComboBox->setTextWhenNothingSelected (String::empty); + tapsComboBox->setTextWhenNoChoicesAvailable ("(no choices)"); + tapsComboBox->addListener (this); + + addAndMakeVisible (controlLabel3 = new Label ("control label", + "Note:")); + controlLabel3->setFont (Font (15.00f, Font::plain)); + controlLabel3->setJustificationType (Justification::centredRight); + controlLabel3->setEditable (false, false, false); + controlLabel3->setColour (TextEditor::textColourId, Colours::black); + controlLabel3->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + + addAndMakeVisible (noteComboBox = new ComboBox ("control combo box")); + noteComboBox->setEditableText (false); + noteComboBox->setJustificationType (Justification::centredLeft); + noteComboBox->setTextWhenNothingSelected (String::empty); + noteComboBox->setTextWhenNoChoicesAvailable ("(no choices)"); + noteComboBox->addListener (this); + + addAndMakeVisible (sendOnReleaseButton = new ToggleButton ("new toggle button")); + sendOnReleaseButton->setButtonText ("Also send on release"); + sendOnReleaseButton->addListener (this); + + + //[UserPreSize] + for(int i = 1; i <= 3; i++) { + touchesComboBox->addItem(String(i), i); + } + for(int i = 1; i <= 5; i++) { + tapsComboBox->addItem(String(i), i); + } + noteComboBox->addItem("Same", kNoteSame); + for(int i = 0; i <= 127; i++) { + noteComboBox->addItem(String(i), i + kNoteOffset); + } + //[/UserPreSize] + + setSize (328, 71); + + + //[Constructor] You can add your own custom stuff here.. + //[/Constructor] +} + +TouchkeyMultiFingerTriggerMappingShortEditor::~TouchkeyMultiFingerTriggerMappingShortEditor() +{ + //[Destructor_pre]. You can add your own custom destruction code here.. + //[/Destructor_pre] + + controlLabel = nullptr; + touchesComboBox = nullptr; + controlLabel2 = nullptr; + tapsComboBox = nullptr; + controlLabel3 = nullptr; + noteComboBox = nullptr; + sendOnReleaseButton = nullptr; + + + //[Destructor]. You can add your own custom destruction code here.. + //[/Destructor] +} + +//============================================================================== +void TouchkeyMultiFingerTriggerMappingShortEditor::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 TouchkeyMultiFingerTriggerMappingShortEditor::resized() +{ + controlLabel->setBounds (8, 8, 64, 24); + touchesComboBox->setBounds (72, 8, 80, 24); + controlLabel2->setBounds (160, 8, 80, 24); + tapsComboBox->setBounds (240, 8, 80, 24); + controlLabel3->setBounds (8, 40, 64, 24); + noteComboBox->setBounds (72, 40, 80, 24); + sendOnReleaseButton->setBounds (168, 40, 152, 24); + //[UserResized] Add your own custom resize handling here.. + //[/UserResized] +} + +void TouchkeyMultiFingerTriggerMappingShortEditor::comboBoxChanged (ComboBox* comboBoxThatHasChanged) +{ + //[UsercomboBoxChanged_Pre] + //[/UsercomboBoxChanged_Pre] + + if (comboBoxThatHasChanged == touchesComboBox) + { + //[UserComboBoxCode_touchesComboBox] -- add your combo box handling code here.. + factory_.setTouchesForTrigger(touchesComboBox->getSelectedId()); + //[/UserComboBoxCode_touchesComboBox] + } + else if (comboBoxThatHasChanged == tapsComboBox) + { + //[UserComboBoxCode_tapsComboBox] -- add your combo box handling code here.. + factory_.setConsecutiveTapsForTrigger(tapsComboBox->getSelectedId()); + //[/UserComboBoxCode_tapsComboBox] + } + else if (comboBoxThatHasChanged == noteComboBox) + { + //[UserComboBoxCode_noteComboBox] -- add your combo box handling code here.. + int note = noteComboBox->getSelectedId(); + if(note == kNoteSame) + note = -1; + else + note -= kNoteOffset; + factory_.setTriggerOnNoteNumber(note); + factory_.setTriggerOffNoteNumber(note); + //[/UserComboBoxCode_noteComboBox] + } + + //[UsercomboBoxChanged_Post] + //[/UsercomboBoxChanged_Post] +} + +void TouchkeyMultiFingerTriggerMappingShortEditor::buttonClicked (Button* buttonThatWasClicked) +{ + //[UserbuttonClicked_Pre] + //[/UserbuttonClicked_Pre] + + if (buttonThatWasClicked == sendOnReleaseButton) + { + //[UserButtonCode_sendOnReleaseButton] -- add your button handler code here.. + if(sendOnReleaseButton->getToggleState()) { + factory_.setTriggerOffAction(TouchkeyMultiFingerTriggerMapping::kActionNoteOn); + } + else { + factory_.setTriggerOffAction(TouchkeyMultiFingerTriggerMapping::kActionNone); + } + //[/UserButtonCode_sendOnReleaseButton] + } + + //[UserbuttonClicked_Post] + //[/UserbuttonClicked_Post] +} + + + +//[MiscUserCode] You can add your own definitions of your custom methods or any other code here... +void TouchkeyMultiFingerTriggerMappingShortEditor::synchronize() { + touchesComboBox->setSelectedId(factory_.getTouchesForTrigger(), dontSendNotification); + tapsComboBox->setSelectedId(factory_.getConsecutiveTapsForTrigger(), dontSendNotification); + + int note = factory_.getTriggerOnNoteNumber(); + if(note < 0) + noteComboBox->setSelectedId(kNoteSame, dontSendNotification); + else + noteComboBox->setSelectedId(note + kNoteOffset, dontSendNotification); + + if(factory_.getTriggerOffAction() == TouchkeyMultiFingerTriggerMapping::kActionNoteOn) + sendOnReleaseButton->setToggleState(true, dontSendNotification); + else + sendOnReleaseButton->setToggleState(false, dontSendNotification); +} +//[/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 + + + + + +END_JUCER_METADATA +*/ +#endif + + +//[EndFile] You can add extra defines here... +//[/EndFile] diff -r 85577160a0d4 -r 1526d2fbe01e Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingShortEditor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/Mappings/MultiFingerTrigger/TouchkeyMultiFingerTriggerMappingShortEditor.h Thu Aug 21 17:02:39 2014 +0100 @@ -0,0 +1,86 @@ +/* + ============================================================================== + + 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.0 + + ------------------------------------------------------------------------------ + + The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-13 by Raw Material Software Ltd. + + ============================================================================== +*/ + +#ifndef __JUCE_HEADER_575F04D6673EEA8A__ +#define __JUCE_HEADER_575F04D6673EEA8A__ + +//[Headers] -- You can add your own extra header files here -- +#include "JuceHeader.h" +#include "TouchkeyMultiFingerTriggerMappingFactory.h" +//[/Headers] + + + +//============================================================================== +/** + //[Comments] + An auto-generated component, created by the Introjucer. + + Describe your class and how it works here! + //[/Comments] +*/ +class TouchkeyMultiFingerTriggerMappingShortEditor : public MappingEditorComponent, + public TextEditor::Listener, + public ComboBoxListener, + public ButtonListener +{ +private: + static const int kNoteSame; + static const int kNoteOffset; + +public: + //============================================================================== + TouchkeyMultiFingerTriggerMappingShortEditor (TouchkeyMultiFingerTriggerMappingFactory& factory); + ~TouchkeyMultiFingerTriggerMappingShortEditor(); + + //============================================================================== + //[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. + TouchkeyMultiFingerTriggerMappingFactory& factory_; + //[/UserVariables] + + //============================================================================== + ScopedPointer