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: OscMidiConverter.h: converts incoming OSC messages to outgoing MIDI andrewm@0: messages with adjustable ranges and parameters. andrewm@0: */ andrewm@0: andrewm@0: #ifndef __touchkeys__OscMidiConverter__ andrewm@0: #define __touchkeys__OscMidiConverter__ andrewm@0: andrewm@0: #include andrewm@0: #include "Osc.h" andrewm@0: #include "MidiOutputController.h" andrewm@0: #include "PianoKeyboard.h" andrewm@0: #include "MidiKeyboardSegment.h" andrewm@0: andrewm@0: /* OscMidiConverter andrewm@0: * andrewm@0: * This class handles the sending of MIDI output messages of a particular type andrewm@0: * (control change, aftertouch, pitch wheel) in response to incoming OSC messages. andrewm@0: * Each object takes responsibility for one type of MIDI output but can take andrewm@0: * several types of OSC message to control it. andrewm@0: */ andrewm@0: andrewm@0: class OscMidiConverter : public OscHandler { andrewm@0: public: andrewm@0: // Behavior for out-of-range inputs. andrewm@0: enum { andrewm@41: kOutOfRangeIgnore = 1, andrewm@0: kOutOfRangeClip, andrewm@0: kOutOfRangeExtrapolate andrewm@0: }; andrewm@0: andrewm@0: private: andrewm@0: // Structure holding information about a given OSC source andrewm@0: struct OscInput { andrewm@0: int uniqueId; // ID to keep track of recent values andrewm@0: int oscParamNumber; // Parameter number in the OSC message we map andrewm@0: float oscMinValue; // Min and max of its input range andrewm@0: float oscMaxValue; andrewm@0: float oscScaledCenterValue; // Value of the input that should correspond to control center, andrewm@0: // pre-normalized to 0-1 range andrewm@0: int outOfRangeBehavior; // What happens at the edge of the range andrewm@0: }; andrewm@0: andrewm@0: public: andrewm@0: // Constructor andrewm@0: OscMidiConverter(PianoKeyboard& keyboard, MidiKeyboardSegment& segment, int controllerId); andrewm@0: andrewm@0: // ***** MIDI methods ***** andrewm@0: andrewm@0: // Provide a reference to the MidiOutputController which actually sends the messages andrewm@0: void setMidiOutputController(MidiOutputController* m) { midiOutputController_ = m; } andrewm@0: andrewm@0: // Set which control this object is handling. If minimum or maximum values are specified, andrewm@0: // then the control will never exceed this range no matter what OSC messages come in. andrewm@0: // use14BitControl specifies whether a 14-bit (paired) MIDI CC message should be used, andrewm@0: // for relevant values of message. andrewm@0: void setMidiMessageType(int defaultValue = -1, int minValue = -1, andrewm@0: int maxValue = -1, int centerValue = -1, bool use14BitControl = false); andrewm@0: andrewm@0: // Set whether this converter passes through incoming CC messages from the MIDI input, andrewm@0: // and if so, which one. Doesn't need to be the same CC coming in as going out. andrewm@0: void listenToIncomingControl(int controller, int centerValue = -1, bool use14BitControl = false); andrewm@0: andrewm@0: // Force a resend of the current value andrewm@0: void resend(int channel); andrewm@0: andrewm@0: // Send the default controller value on the specified channel. Typically used andrewm@0: // before note onset. andrewm@0: void sendDefaultValue(int channel); andrewm@0: andrewm@0: // Return the current value of the MIDI controller without sending it andrewm@0: int currentControllerValue(int channel); andrewm@0: andrewm@0: // ***** OSC methods ***** andrewm@0: andrewm@0: // This message specifies an OSC path to be mapped to MIDI, along with its input ranges which andrewm@0: // correspond to the complete specified MIDI range. andrewm@0: void addControl(const string& oscPath, int oscParamNumber, float oscMinValue, float oscMaxValue, andrewm@0: float oscCenterValue, int outOfRangeBehavior); andrewm@0: void removeControl(const string& oscPath); andrewm@0: void removeAllControls(); andrewm@0: andrewm@0: // These methods update the range for an existing control andrewm@0: void setControlMinValue(const string& oscPath, float newValue); andrewm@0: void setControlMaxValue(const string& oscPath, float newValue); andrewm@0: void setControlCenterValue(const string& oscPath, float newValue); andrewm@0: void setControlOutOfRangeBehavior(const string& oscPath, int newBehavior); andrewm@0: andrewm@0: // Reset any active previous values on the given channel andrewm@0: void clearLastValues(int channel, bool send = true); andrewm@0: andrewm@0: // OSC Handler Method: called by PianoKeyboard (or other OSC source) andrewm@0: bool oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data); andrewm@0: andrewm@0: // Destructor andrewm@0: ~OscMidiConverter() {} andrewm@0: andrewm@0: private: andrewm@0: // ***** Private Methods ***** andrewm@0: int idWithChannel(int channel, int inputId) { return (inputId << 4) + channel; } andrewm@0: void sendCurrentValue(int port, int channel, int note, bool force); andrewm@0: andrewm@0: // ***** Member Variables ***** andrewm@0: andrewm@0: PianoKeyboard& keyboard_; // Main piano keyboard controller andrewm@0: MidiKeyboardSegment& keyboardSegment_; // Which segment of the keyboard this mapping is using andrewm@0: MidiOutputController* midiOutputController_; // Class handling MIDI output andrewm@0: andrewm@0: int controller_; // Which MIDI control to use andrewm@0: bool controllerIs14Bit_; // Whether to use a paired MIDI CC andrewm@0: int controlMinValue_, controlMaxValue_; // Ranges control can take andrewm@0: int controlCenterValue_; // The center value to use when all OSC inputs are 0 andrewm@0: int controlDefaultValue_; // Default value for the control on new notes andrewm@0: andrewm@0: int lastUniqueId_; // Global unique ID for input messages andrewm@0: andrewm@0: int incomingController_; // Which controller we listen to from the MIDI input andrewm@0: bool incomingControllerIs14Bit_; // Whether the input controller is 14 bit andrewm@0: int incomingControllerCenterValue_; // The center value to subtract from the incoming controller andrewm@0: andrewm@0: std::map inputs_; // OSC sources for this MIDI output andrewm@0: std::map lastValues_; // Recently received values from each OSC input andrewm@0: andrewm@0: float currentValue_[16]; // Current sum value of all inputs for each channel andrewm@0: int lastOutputValue_[16]; // The last value we sent out; saved to avoid duplicate messages andrewm@0: }; andrewm@0: andrewm@0: #endif /* defined(__touchkeys__OscMidiConverter__) */