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: