andrewm@0: /* andrewm@0: TouchKeys: multi-touch musical keyboard control software andrewm@0: Copyright (c) 2013 Andrew McPherson andrewm@0: andrewm@0: This program is free software: you can redistribute it and/or modify andrewm@0: it under the terms of the GNU General Public License as published by andrewm@0: the Free Software Foundation, either version 3 of the License, or andrewm@0: (at your option) any later version. andrewm@0: andrewm@0: This program is distributed in the hope that it will be useful, andrewm@0: but WITHOUT ANY WARRANTY; without even the implied warranty of andrewm@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrewm@0: GNU General Public License for more details. andrewm@0: andrewm@0: You should have received a copy of the GNU General Public License andrewm@0: along with this program. If not, see . andrewm@0: andrewm@0: ===================================================================== andrewm@0: andrewm@0: TouchkeyVibratoMappingFactory.cpp: factory for the vibrato mapping class, andrewm@0: which creates vibrato through side-to-side motion of the finger on the andrewm@0: key surface. andrewm@0: */ andrewm@0: andrewm@0: #include "TouchkeyVibratoMappingFactory.h" andrewm@0: #include "TouchkeyVibratoMappingShortEditor.h" andrewm@0: andrewm@0: // Class constants andrewm@0: const int TouchkeyVibratoMappingFactory::kDefaultVibratoControl = MidiKeyboardSegment::kControlPitchWheel; andrewm@0: andrewm@0: // Default constructor, containing a reference to the PianoKeyboard class. andrewm@0: andrewm@0: TouchkeyVibratoMappingFactory::TouchkeyVibratoMappingFactory(PianoKeyboard &keyboard, MidiKeyboardSegment& segment) : andrewm@7: TouchkeyBaseMappingFactory(keyboard, segment), andrewm@0: vibratoControl_(kDefaultVibratoControl), andrewm@0: vibratoRange_(TouchkeyVibratoMapping::kDefaultVibratoRangeSemitones), andrewm@0: vibratoPrescaler_(TouchkeyVibratoMapping::kDefaultVibratoPrescaler), andrewm@0: vibratoTimeout_(TouchkeyVibratoMapping::kDefaultVibratoTimeout), andrewm@0: vibratoOnsetThresholdX_(TouchkeyVibratoMapping::kDefaultVibratoThresholdX), andrewm@0: vibratoOnsetThresholdY_(TouchkeyVibratoMapping::kDefaultVibratoThresholdY), andrewm@0: vibratoOnsetRatioX_(TouchkeyVibratoMapping::kDefaultVibratoRatioX), andrewm@0: vibratoOnsetRatioY_(TouchkeyVibratoMapping::kDefaultVibratoRatioY) andrewm@0: { andrewm@0: // Set up the MIDI converter to use pitch wheel andrewm@0: configurePitchWheelVibrato(); andrewm@0: } andrewm@0: andrewm@0: // ***** Destructor ***** andrewm@0: andrewm@0: TouchkeyVibratoMappingFactory::~TouchkeyVibratoMappingFactory() { andrewm@0: andrewm@0: } andrewm@0: andrewm@0: // ***** Accessors / Modifiers ***** andrewm@0: andrewm@0: void TouchkeyVibratoMappingFactory::setName(const string& name) { andrewm@0: TouchkeyBaseMappingFactory::setName(name); andrewm@0: setVibratoControl(vibratoControl_); andrewm@0: } andrewm@0: andrewm@0: // ***** Vibrato Methods ***** andrewm@0: andrewm@0: void TouchkeyVibratoMappingFactory::setVibratoControl(int vibratoControl) { andrewm@0: if(vibratoControl < 0 || vibratoControl >= MidiKeyboardSegment::kControlMax) andrewm@0: return; andrewm@0: andrewm@0: // Update the variable which affects future mappings andrewm@0: vibratoControl_ = vibratoControl; andrewm@0: andrewm@0: if(vibratoControl_ == MidiKeyboardSegment::kControlPitchWheel) andrewm@0: configurePitchWheelVibrato(); andrewm@0: else andrewm@0: configureControlChangeVibrato(); andrewm@0: } andrewm@0: andrewm@0: void TouchkeyVibratoMappingFactory::setVibratoRange(float range, bool updateCurrent) { andrewm@0: /*if(updateCurrent) { andrewm@0: // Send new range to all active mappings andrewm@0: // TODO: mutex protect andrewm@0: std::map::iterator it = mappings_.begin(); andrewm@0: while(it != mappings_.end()) { andrewm@0: // Tell this mapping to update its range andrewm@0: TouchkeyVibratoMapping *mapping = it->second.first; andrewm@0: mapping->setRange(rangeSemitones); andrewm@0: it++; andrewm@0: } andrewm@0: }*/ andrewm@0: andrewm@0: // Update the variable which affects future mappings andrewm@0: vibratoRange_ = range; andrewm@0: if(vibratoRange_ < 0.01) andrewm@0: vibratoRange_ = 0.01; andrewm@0: if(vibratoRange_ > 127.0) andrewm@0: vibratoRange_ = 127.0; andrewm@0: } andrewm@0: andrewm@0: void TouchkeyVibratoMappingFactory::setVibratoPrescaler(float prescaler, bool updateCurrent) { andrewm@0: /*if(updateCurrent) { andrewm@0: // Send new range to all active mappings andrewm@0: // TODO: mutex protect andrewm@0: std::map::iterator it = mappings_.begin(); andrewm@0: while(it != mappings_.end()) { andrewm@0: // Tell this mapping to update its range andrewm@0: TouchkeyVibratoMapping *mapping = it->second.first; andrewm@0: mapping->setPrescaler(prescaler); andrewm@0: it++; andrewm@0: } andrewm@0: }*/ andrewm@0: andrewm@0: // Update the variable which affects future mappings andrewm@0: vibratoPrescaler_ = prescaler; andrewm@0: } andrewm@0: andrewm@0: void TouchkeyVibratoMappingFactory::setVibratoThreshold(float threshold, bool updateCurrent) { andrewm@0: vibratoOnsetThresholdX_ = threshold; andrewm@0: if(vibratoOnsetThresholdX_ < 0) andrewm@0: vibratoOnsetThresholdX_ = 0; andrewm@0: if(vibratoOnsetThresholdX_ > 1.0) andrewm@0: vibratoOnsetThresholdX_ = 1.0; andrewm@0: } andrewm@0: andrewm@0: void TouchkeyVibratoMappingFactory::setVibratoThresholds(float thresholdX, float thresholdY, float ratioX, float ratioY, bool updateCurrent) { andrewm@0: /*if(updateCurrent) { andrewm@0: // Send new range to all active mappings andrewm@0: // TODO: mutex protect andrewm@0: std::map::iterator it = mappings_.begin(); andrewm@0: while(it != mappings_.end()) { andrewm@0: // Tell this mapping to update its range andrewm@0: TouchkeyVibratoMapping *mapping = it->second.first; andrewm@0: mapping->setThresholds(thresholdX, thresholdY, ratioX, ratioY); andrewm@0: it++; andrewm@0: } andrewm@0: }*/ andrewm@0: andrewm@0: // Update the variables which affect future mappings andrewm@0: vibratoOnsetThresholdX_ = thresholdX; andrewm@0: vibratoOnsetThresholdY_ = thresholdY; andrewm@0: vibratoOnsetRatioX_ = ratioX; andrewm@0: vibratoOnsetRatioY_ = ratioY; andrewm@0: } andrewm@0: andrewm@0: void TouchkeyVibratoMappingFactory::setVibratoTimeout(timestamp_diff_type timeout, bool updateCurrent) { andrewm@0: /*if(updateCurrent) { andrewm@0: // Send new range to all active mappings andrewm@0: // TODO: mutex protect andrewm@0: std::map::iterator it = mappings_.begin(); andrewm@0: while(it != mappings_.end()) { andrewm@0: // Tell this mapping to update its range andrewm@0: TouchkeyVibratoMapping *mapping = it->second.first; andrewm@0: mapping->setTimeout(timeout); andrewm@0: it++; andrewm@0: } andrewm@0: }*/ andrewm@0: andrewm@0: // Update the variable which affects future mappings andrewm@0: vibratoTimeout_ = timeout; andrewm@0: } andrewm@0: andrewm@49: #ifndef TOUCHKEYS_NO_GUI andrewm@0: // ***** GUI Support ***** andrewm@0: MappingEditorComponent* TouchkeyVibratoMappingFactory::createBasicEditor() { andrewm@0: return new TouchkeyVibratoMappingShortEditor(*this); andrewm@0: } andrewm@49: #endif andrewm@49: andrewm@49: // ****** OSC Control Support ****** andrewm@49: OscMessage* TouchkeyVibratoMappingFactory::oscControlMethod(const char *path, const char *types, andrewm@49: int numValues, lo_arg **values, void *data) { andrewm@49: if(!strcmp(path, "/set-vibrato-control")) { andrewm@49: // Change the vibrato control andrewm@49: if(numValues > 0) { andrewm@49: if(types[0] == 'i') { andrewm@49: setVibratoControl(values[0]->i); andrewm@49: return OscTransmitter::createSuccessMessage(); andrewm@49: } andrewm@49: } andrewm@49: } andrewm@49: else if(!strcmp(path, "/set-vibrato-range")) { andrewm@49: // Change the vibrato range in semitones andrewm@49: if(numValues > 0) { andrewm@49: if(types[0] == 'f') { andrewm@49: setVibratoRange(values[0]->f); andrewm@49: return OscTransmitter::createSuccessMessage(); andrewm@49: } andrewm@49: } andrewm@49: } andrewm@49: else if(!strcmp(path, "/set-vibrato-prescaler")) { andrewm@49: // Change the vibrato prescaler andrewm@49: if(numValues > 0) { andrewm@49: if(types[0] == 'f') { andrewm@49: setVibratoPrescaler(values[0]->f); andrewm@49: return OscTransmitter::createSuccessMessage(); andrewm@49: } andrewm@49: } andrewm@49: } andrewm@49: else if(!strcmp(path, "/set-vibrato-timeout")) { andrewm@49: // Change the vibrato timeout andrewm@49: if(numValues > 0) { andrewm@49: if(types[0] == 'f') { andrewm@49: setVibratoTimeout(values[0]->f); andrewm@49: return OscTransmitter::createSuccessMessage(); andrewm@49: } andrewm@49: } andrewm@49: } andrewm@49: else if(!strcmp(path, "/set-vibrato-threshold")) { andrewm@49: // Change the vibrato threshold andrewm@49: if(numValues > 0) { andrewm@49: if(types[0] == 'f') { andrewm@49: setVibratoThreshold(values[0]->f); andrewm@49: return OscTransmitter::createSuccessMessage(); andrewm@49: } andrewm@49: } andrewm@49: } andrewm@49: andrewm@49: // If no match, check the base class andrewm@49: return TouchkeyBaseMappingFactory::oscControlMethod(path, types, numValues, values, data); andrewm@49: } andrewm@0: andrewm@35: andrewm@35: // ****** Preset Save/Load ****** andrewm@35: XmlElement* TouchkeyVibratoMappingFactory::getPreset() { andrewm@35: PropertySet properties; andrewm@35: andrewm@35: storeCommonProperties(properties); andrewm@35: properties.setValue("vibratoControl", vibratoControl_); andrewm@35: properties.setValue("vibratoRange", vibratoRange_); andrewm@35: properties.setValue("vibratoPrescaler", vibratoPrescaler_); andrewm@35: properties.setValue("vibratoTimeout", vibratoTimeout_); andrewm@35: properties.setValue("vibratoOnsetThresholdX", vibratoOnsetThresholdX_); andrewm@35: properties.setValue("vibratoOnsetThresholdY", vibratoOnsetThresholdY_); andrewm@35: properties.setValue("vibratoOnsetRatioX", vibratoOnsetRatioX_); andrewm@35: properties.setValue("vibratoOnsetRatioY", vibratoOnsetRatioY_); andrewm@35: andrewm@35: XmlElement* preset = properties.createXml("MappingFactory"); andrewm@35: preset->setAttribute("type", "Vibrato"); andrewm@35: andrewm@35: return preset; andrewm@35: } andrewm@35: andrewm@35: bool TouchkeyVibratoMappingFactory::loadPreset(XmlElement const* preset) { andrewm@35: if(preset == 0) andrewm@35: return false; andrewm@35: andrewm@35: PropertySet properties; andrewm@35: properties.restoreFromXml(*preset); andrewm@35: andrewm@35: if(!loadCommonProperties(properties)) andrewm@35: return false; andrewm@35: if(!properties.containsKey("vibratoControl") || andrewm@35: !properties.containsKey("vibratoRange") || andrewm@35: !properties.containsKey("vibratoPrescaler") || andrewm@35: !properties.containsKey("vibratoTimeout") || andrewm@35: !properties.containsKey("vibratoOnsetThresholdX") || andrewm@35: !properties.containsKey("vibratoOnsetThresholdY") || andrewm@35: !properties.containsKey("vibratoOnsetRatioX") || andrewm@35: !properties.containsKey("vibratoOnsetRatioY")) andrewm@35: return false; andrewm@35: andrewm@35: vibratoControl_ = properties.getDoubleValue("vibratoControl"); andrewm@35: vibratoRange_ = properties.getDoubleValue("vibratoRange"); andrewm@35: vibratoPrescaler_ = properties.getDoubleValue("vibratoPrescaler"); andrewm@35: vibratoTimeout_ = properties.getDoubleValue("vibratoTimeout"); andrewm@35: vibratoOnsetThresholdX_ = properties.getDoubleValue("vibratoOnsetThresholdX"); andrewm@35: vibratoOnsetThresholdY_ = properties.getDoubleValue("vibratoOnsetThresholdY"); andrewm@35: vibratoOnsetRatioX_ = properties.getDoubleValue("vibratoOnsetRatioX"); andrewm@35: vibratoOnsetRatioY_ = properties.getDoubleValue("vibratoOnsetRatioY"); andrewm@35: andrewm@35: // Update MIDI information; this doesn't actually change the controller andrewm@35: // (which is already set) but it adds a listener and updates the ranges andrewm@35: setVibratoControl(vibratoControl_); andrewm@35: andrewm@35: return true; andrewm@35: } andrewm@35: andrewm@35: andrewm@0: // ***** Private Methods ***** andrewm@0: andrewm@0: // Set the initial parameters for a new mapping andrewm@0: void TouchkeyVibratoMappingFactory::initializeMappingParameters(int noteNumber, TouchkeyVibratoMapping *mapping) { andrewm@0: mapping->setRange(vibratoRange_); andrewm@0: mapping->setPrescaler(vibratoPrescaler_); andrewm@0: mapping->setThresholds(vibratoOnsetThresholdX_, vibratoOnsetThresholdY_, vibratoOnsetRatioX_, vibratoOnsetRatioY_); andrewm@0: mapping->setTimeout(vibratoTimeout_); andrewm@0: } andrewm@0: andrewm@0: // Configure the OSC-MIDI converter to handle pitchwheel vibrato andrewm@0: void TouchkeyVibratoMappingFactory::configurePitchWheelVibrato() { andrewm@7: // Range of 0 indicates special case of using global pitch wheel range andrewm@7: setMidiParameters(MidiKeyboardSegment::kControlPitchWheel, 0.0, 0.0, 0.0); andrewm@0: andrewm@0: if(midiConverter_ != 0) { andrewm@0: midiConverter_->listenToIncomingControl(MidiKeyboardSegment::kControlPitchWheel); andrewm@0: } andrewm@0: } andrewm@0: andrewm@0: // Configure the OSC-MIDI converter to handle vibrato based on a CC andrewm@0: void TouchkeyVibratoMappingFactory::configureControlChangeVibrato() { andrewm@0: setMidiParameters(vibratoControl_, 0.0, 127.0, 0.0, 0, 0, 127, 0, false, OscMidiConverter::kOutOfRangeExtrapolate); andrewm@0: andrewm@0: if(midiConverter_ != 0) { andrewm@0: midiConverter_->listenToIncomingControl(vibratoControl_); andrewm@0: } andrewm@0: } andrewm@0: andrewm@0: