view Source/TouchKeys/OscMidiConverter.h @ 20:dfff66c07936

Lots of minor changes to support building on Visual Studio. A few MSVC-specific #ifdefs to eliminate things Visual Studio doesn't like. This version now compiles on Windows (provided liblo, Juce and pthread are present) but the TouchKeys device support is not yet enabled. Also, the code now needs to be re-checked on Mac and Linux.
author Andrew McPherson <andrewm@eecs.qmul.ac.uk>
date Sun, 09 Feb 2014 18:40:51 +0000
parents 353276611036
children 85577160a0d4
line wrap: on
line source
/*
  TouchKeys: multi-touch musical keyboard control software
  Copyright (c) 2013 Andrew McPherson

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
  =====================================================================
 
  OscMidiConverter.h: converts incoming OSC messages to outgoing MIDI
  messages with adjustable ranges and parameters.
*/

#ifndef __touchkeys__OscMidiConverter__
#define __touchkeys__OscMidiConverter__

#include <vector>
#include "Osc.h"
#include "MidiOutputController.h"
#include "PianoKeyboard.h"
#include "MidiKeyboardSegment.h"

/* OscMidiConverter
 *
 * This class handles the sending of MIDI output messages of a particular type
 * (control change, aftertouch, pitch wheel) in response to incoming OSC messages.
 * Each object takes responsibility for one type of MIDI output but can take
 * several types of OSC message to control it.
 */

class OscMidiConverter : public OscHandler {
public:
    // Behavior for out-of-range inputs.
    enum {
        kOutOfRangeIgnore = 0,
        kOutOfRangeClip,
        kOutOfRangeExtrapolate
    };

private:
    // Structure holding information about a given OSC source
	struct OscInput {
        int uniqueId;               // ID to keep track of recent values
		int oscParamNumber;         // Parameter number in the OSC message we map
		float oscMinValue;          // Min and max of its input range
		float oscMaxValue;
        float oscScaledCenterValue; // Value of the input that should correspond to control center,
                                    // pre-normalized to 0-1 range
		int outOfRangeBehavior;     // What happens at the edge of the range
	};
    
public:
	// Constructor
	OscMidiConverter(PianoKeyboard& keyboard, MidiKeyboardSegment& segment, int controllerId);
	
	// ***** MIDI methods *****
    
    // Provide a reference to the MidiOutputController which actually sends the messages
	void setMidiOutputController(MidiOutputController* m) { midiOutputController_ = m; }
	
    // Set which control this object is handling. If minimum or maximum values are specified,
    // then the control will never exceed this range no matter what OSC messages come in.
    // use14BitControl specifies whether a 14-bit (paired) MIDI CC message should be used,
    // for relevant values of message.
    void setMidiMessageType(int defaultValue = -1, int minValue = -1,
                            int maxValue = -1, int centerValue = -1, bool use14BitControl = false);
    
    // Set whether this converter passes through incoming CC messages from the MIDI input,
    // and if so, which one. Doesn't need to be the same CC coming in as going out.
    void listenToIncomingControl(int controller, int centerValue = -1, bool use14BitControl = false);
    
    // Force a resend of the current value
    void resend(int channel);
    
    // Send the default controller value on the specified channel. Typically used
    // before note onset.
    void sendDefaultValue(int channel);
    
    // Return the current value of the MIDI controller without sending it
    int currentControllerValue(int channel);
    
	// ***** OSC methods *****
	
    // This message specifies an OSC path to be mapped to MIDI, along with its input ranges which
    // correspond to the complete specified MIDI range.
	void addControl(const string& oscPath, int oscParamNumber, float oscMinValue, float oscMaxValue,
                    float oscCenterValue, int outOfRangeBehavior);
	void removeControl(const string& oscPath);
	void removeAllControls();
    
    // These methods update the range for an existing control
    void setControlMinValue(const string& oscPath, float newValue);
    void setControlMaxValue(const string& oscPath, float newValue);
    void setControlCenterValue(const string& oscPath, float newValue);
    void setControlOutOfRangeBehavior(const string& oscPath, int newBehavior);
	
    // Reset any active previous values on the given channel
    void clearLastValues(int channel, bool send = true);
    
	// OSC Handler Method: called by PianoKeyboard (or other OSC source)
	bool oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data);
	
	// Destructor
	~OscMidiConverter() {}
	
private:
    // ***** Private Methods *****
    int idWithChannel(int channel, int inputId) { return (inputId << 4) + channel; }
    void sendCurrentValue(int port, int channel, int note, bool force);
    
	// ***** Member Variables *****
	
	PianoKeyboard& keyboard_;						// Main piano keyboard controller
    MidiKeyboardSegment& keyboardSegment_;          // Which segment of the keyboard this mapping is using
	MidiOutputController* midiOutputController_;	// Class handling MIDI output
    
    int controller_;                                // Which MIDI control to use
    bool controllerIs14Bit_;                        // Whether to use a paired MIDI CC
    int controlMinValue_, controlMaxValue_;         // Ranges control can take
    int controlCenterValue_;                        // The center value to use when all OSC inputs are 0
    int controlDefaultValue_;                       // Default value for the control on new notes

    int lastUniqueId_;                              // Global unique ID for input messages
    
    int incomingController_;                         // Which controller we listen to from the MIDI input
    bool incomingControllerIs14Bit_;                // Whether the input controller is 14 bit
    int incomingControllerCenterValue_;             // The center value to subtract from the incoming controller
    
    std::map<std::string, OscInput> inputs_;        // OSC sources for this MIDI output
    std::map<int, float> lastValues_;               // Recently received values from each OSC input
    
    float currentValue_[16];                        // Current sum value of all inputs for each channel
    int lastOutputValue_[16];                       // The last value we sent out; saved to avoid duplicate messages
};

#endif /* defined(__touchkeys__OscMidiConverter__) */