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__) */