view Source/Mappings/Vibrato/TouchkeyVibratoMapping.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 3580ffe87dc8
children
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/>.
 
  =====================================================================

  TouchkeyVibratoMapping.h: per-note mapping for the vibrato mapping class,
  which creates vibrato through side-to-side motion of the finger on the
  key surface.
*/

#ifndef __touchkeys__TouchkeyVibratoMapping__
#define __touchkeys__TouchkeyVibratoMapping__


#include <map>
#include <boost/bind.hpp>
#include "../../TouchKeys/KeyTouchFrame.h"
#include "../../TouchKeys/KeyPositionTracker.h"
#include "../../TouchKeys/PianoKeyboard.h"
#include "../TouchkeyBaseMapping.h"
#include "../../Utility/IIRFilter.h"

// This class handles the detection and mapping of vibrato gestures
// based on Touchkey data. It outputs MIDI or OSC messages that
// can be used to affect the pitch of the active note.

class TouchkeyVibratoMapping : public TouchkeyBaseMapping {
    friend class TouchkeyVibratoMappingFactory;

private:
    // Useful constants for mapping MRP messages
    /*constexpr static const int kDefaultMIDIChannel = 0;
    constexpr static const int kDefaultFilterBufferLength = 30;
    
    constexpr static const float kDefaultVibratoThresholdX = 0.05;
    constexpr static const float kDefaultVibratoRatioX = 0.3;
    constexpr static const float kDefaultVibratoThresholdY = 0.02;
    constexpr static const float kDefaultVibratoRatioY = 0.8;
    constexpr static const timestamp_diff_type kDefaultVibratoTimeout = microseconds_to_timestamp(400000); // 0.4s
    constexpr static const float kDefaultVibratoPrescaler = 2.0;
    constexpr static const float kDefaultVibratoRangeSemitones = 1.25;
    
    constexpr static const timestamp_diff_type kZeroCrossingMinimumTime = microseconds_to_timestamp(50000); // 50ms
    constexpr static const timestamp_diff_type kMinimumOnsetTime = microseconds_to_timestamp(30000); // 30ms
    constexpr static const timestamp_diff_type kMaximumOnsetTime = microseconds_to_timestamp(300000); // 300ms
    constexpr static const timestamp_diff_type kMinimumReleaseTime = microseconds_to_timestamp(30000); // 30ms
    constexpr static const timestamp_diff_type kMaximumReleaseTime = microseconds_to_timestamp(300000); // 300ms*/
    
    static const int kDefaultMIDIChannel;
    static const int kDefaultFilterBufferLength;
    
    static const float kDefaultVibratoThresholdX;
    static const float kDefaultVibratoRatioX;
    static const float kDefaultVibratoThresholdY;
    static const float kDefaultVibratoRatioY;
    static const timestamp_diff_type kDefaultVibratoTimeout;
    static const float kDefaultVibratoPrescaler;
    static const float kDefaultVibratoRangeSemitones;
    
    static const timestamp_diff_type kZeroCrossingMinimumTime;
    static const timestamp_diff_type kMinimumOnsetTime;
    static const timestamp_diff_type kMaximumOnsetTime;
    static const timestamp_diff_type kMinimumReleaseTime;
    static const timestamp_diff_type kMaximumReleaseTime;
    
    static const float kWhiteKeySingleAxisThreshold;
    
    enum {
        kStateInactive = 0,
        kStateSwitchingOn,
        kStateActive,
        kStateSwitchingOff
    };
    
public:
	// ***** Constructors *****
	
	// Default constructor, passing the buffer on which to trigger
	TouchkeyVibratoMapping(PianoKeyboard &keyboard, MappingFactory *factory, int noteNumber, Node<KeyTouchFrame>* touchBuffer,
               Node<key_position>* positionBuffer, KeyPositionTracker* positionTracker);

    // ***** Destructor *****
    
    ~TouchkeyVibratoMapping();
	
    // ***** Modifiers *****
    
    // Disable mappings from being sent
    void disengage(bool shouldDelete = false);
	
    // Reset the state back initial values
	void reset();
    
    // Resend the current state of all parameters
    void resend();

    // Parameters for vibrato algorithm
    //void setType(int vibratoType);
    void setRange(float rangeSemitones);
    void setPrescaler(float prescaler);
    void setThresholds(float thresholdX, float thresholdY, float ratioX, float ratioY);
    void setTimeout(timestamp_diff_type timeout);
    
	// ***** Evaluators *****
    
    // This method receives triggers whenever events occur in the touch data or the
    // continuous key position (state changes only). It alters the behavior and scheduling
    // of the mapping but does not itself send OSC messages
	void triggerReceived(TriggerSource* who, timestamp_type timestamp);
	
    // This method handles the OSC message transmission. It should be run in the Scheduler
    // thread provided by PianoKeyboard.
    timestamp_type performMapping();
    
private:
    // ***** Private Methods *****
    void midiNoteOnReceived(int channel, int velocity);
    void midiNoteOffReceived(int channel);
    
    void changeStateSwitchingOn(timestamp_type timestamp);
    void changeStateActive(timestamp_type timestamp);
    void changeStateSwitchingOff(timestamp_type timestamp);
    void changeStateInactive(timestamp_type timestamp);

    void resetDetectionState();
    void clearBuffers();
    
    bool keyIsWhite();
    
    void sendVibratoMessage(float pitchBendSemitones, bool force = false);
    
	// ***** Member Variables *****
    
    int vibratoState_;                          // Whether a vibrato gesture is currently detected
    
    timestamp_type rampBeginTime_;              // If in a switching state, when does the transition begin?
    float rampScaleValue_;                      // If in a switching state, what is the end point of the ramp?
    timestamp_diff_type rampLength_;            // If in a switching state, how long is the transition?
    float lastCalculatedRampValue_;             // Value of the ramp that was last calculated
    
    float onsetThresholdX_, onsetThresholdY_;   // Thresholds for detecting vibrato (first extremum)
    float onsetRatioX_, onsetRatioY_;           // Thresholds for detection vibrato (second extremum)
    timestamp_diff_type onsetTimeout_;          // Timeout between first and second extrema
    
    float onsetLocationX_, onsetLocationY_;     // Where the touch began at MIDI note on
    float lastX_, lastY_;                       // Where the touch was at the last frame we received
    int idOfCurrentTouch_;                      // Which touch ID we're currently following
    timestamp_type lastTimestamp_;              // When the last data point arrived
    Node<float>::size_type lastProcessedIndex_; // Index of the last filtered position sample we've handled
    
    timestamp_type lastZeroCrossingTimestamp_;  // Timestamp of the last zero crossing
    timestamp_diff_type lastZeroCrossingInterval_;   // Interval between the last two zero-crossings of filtered distance
    bool lastSampleWasPositive_;                // Whether the last sample was > 0
    
    bool foundFirstExtremum_;                   // Whether the first extremum has occurred
    float firstExtremumX_, firstExtremumY_;     // Where the first extremum occurred
    timestamp_type firstExtremumTimestamp_;     // Where the first extremum occurred
    timestamp_type lastExtremumTimestamp_;      // When the most recent extremum occurred
    
    float vibratoPrescaler_;                    // Parameter controlling prescaler before nonlinear scaling
    float vibratoRangeSemitones_;               // Amount of pitch bend in one direction at maximum
    
    float lastPitchBendSemitones_;              // The last pitch bend value we sent out
    
    Node<float> rawDistance_;                   // Distance from onset location
    IIRFilterNode<float> filteredDistance_;     // Bandpass filtered finger motion
    CriticalSection distanceAccessMutex_;       // Mutex that protects the access buffer from changes
};

#endif /* defined(__touchkeys__TouchkeyVibratoMapping__) */