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: MRPMapping.h: mapping class for magnetic resonator piano using continuous andrewm@0: key position. andrewm@0: */ andrewm@0: andrewm@0: #ifndef __touchkeys__MRPMapping__ andrewm@0: #define __touchkeys__MRPMapping__ andrewm@0: andrewm@0: #include andrewm@0: #include andrewm@0: #include "../TouchKeys/KeyTouchFrame.h" andrewm@0: #include "../TouchKeys/KeyPositionTracker.h" andrewm@0: #include "../TouchKeys/PianoKeyboard.h" andrewm@0: #include "Mapping.h" andrewm@0: #include "../Utility/IIRFilter.h" andrewm@0: andrewm@0: // How many velocity samples to save in the buffer. Make sure this is andrewm@0: // enough to cover the frequency of updates. andrewm@0: const int kMRPMappingVelocityBufferLength = 30; andrewm@0: andrewm@0: // This class handles the mapping from key position and, optionally, andrewm@0: // touch information to OSC messages which control the magnetic resonator andrewm@0: // piano. One copy of the object is created for each active note, and andrewm@0: // all objects use the PianoKeyboard Scheduler facility to request timed andrewm@0: // updates. andrewm@0: andrewm@0: class MRPMapping : public Mapping { andrewm@0: private: andrewm@0: /*// Useful constants for mapping MRP messages andrewm@0: const int kMIDINoteOnMessage = 0x90; andrewm@0: const int kDefaultMIDIChannel = 15; andrewm@0: const float kDefaultAftertouchScaler = 100.0; andrewm@0: andrewm@0: // Parameters for vibrato detection and mapping andrewm@0: const key_velocity kVibratoVelocityThreshold = scale_key_velocity(2.0); andrewm@0: const timestamp_diff_type kVibratoMinimumPeakSpacing = microseconds_to_timestamp(60000); andrewm@0: const timestamp_diff_type kVibratoTimeout = microseconds_to_timestamp(500000); andrewm@0: const int kVibratoMinimumOscillations = 4; andrewm@0: const float kVibratoRateScaler = 0.005;*/ andrewm@0: // Useful constants for mapping MRP messages andrewm@0: static const int kMIDINoteOnMessage; andrewm@0: static const int kDefaultMIDIChannel; andrewm@0: static const float kDefaultAftertouchScaler; andrewm@0: andrewm@0: // Parameters for vibrato detection and mapping andrewm@0: static const key_velocity kVibratoVelocityThreshold; andrewm@0: static const timestamp_diff_type kVibratoMinimumPeakSpacing; andrewm@0: static const timestamp_diff_type kVibratoTimeout; andrewm@0: static const int kVibratoMinimumOscillations; andrewm@0: static const float kVibratoRateScaler; andrewm@0: andrewm@0: struct PitchBend { andrewm@0: int note; // Note number of the bending key andrewm@0: bool isControllingBend; // True if the note in this structure andrewm@0: // is the one controlling bend (false if it's us) andrewm@0: bool isFinished; // True if the bend should finish after this cycle andrewm@0: Node* positionBuffer; // Key position for bending key andrewm@0: KeyPositionTracker* positionTracker; // Key states for bending key andrewm@0: }; andrewm@0: andrewm@0: public: andrewm@0: // ***** Constructors ***** andrewm@0: andrewm@0: // Default constructor, passing the buffer on which to trigger andrewm@0: MRPMapping(PianoKeyboard &keyboard, MappingFactory *factory, int noteNumber, Node* touchBuffer, andrewm@0: Node* positionBuffer, KeyPositionTracker* positionTracker); andrewm@0: andrewm@0: // Copy constructor andrewm@0: //MRPMapping(MRPMapping const& obj); andrewm@0: andrewm@0: // ***** Destructor ***** andrewm@0: andrewm@0: ~MRPMapping(); andrewm@0: andrewm@0: // ***** Modifiers ***** andrewm@0: andrewm@0: // Disable mappings from being sent andrewm@0: void disengage(); andrewm@0: andrewm@0: // Reset the state back initial values andrewm@0: void reset(); andrewm@0: andrewm@0: // Set the aftertouch sensitivity on continuous key position andrewm@0: // 0 means no aftertouch, 1 means default sensitivity, upward andrewm@0: // from there andrewm@0: void setAftertouchSensitivity(float sensitivity); andrewm@0: andrewm@0: // Engage a pitch bend from a different key, based on its position and state andrewm@0: void enablePitchBend(int toNote, Node* toPositionBuffer, andrewm@0: KeyPositionTracker *toPositionTracker); andrewm@0: andrewm@0: // ***** Evaluators ***** andrewm@0: andrewm@0: // This method receives triggers whenever events occur in the touch data or the andrewm@0: // continuous key position (state changes only). It alters the behavior and scheduling andrewm@0: // of the mapping but does not itself send OSC messages andrewm@0: void triggerReceived(TriggerSource* who, timestamp_type timestamp); andrewm@0: andrewm@0: // This method handles the OSC message transmission. It should be run in the Scheduler andrewm@0: // thread provided by PianoKeyboard. andrewm@0: timestamp_type performMapping(); andrewm@0: andrewm@0: private: andrewm@0: // ***** Private Methods ***** andrewm@0: andrewm@0: // Bring velocity calculations up to date andrewm@0: key_velocity updateVelocityMeasurements(); andrewm@0: andrewm@0: // Find the timestamp of the first transition into a PartialPress state andrewm@0: timestamp_type findTimestampOfPartialPress(); andrewm@0: andrewm@0: // ***** Member Variables ***** andrewm@0: andrewm@0: bool noteIsOn_; // Whether the MIDI note is active or not andrewm@0: float aftertouchScaler_; // Scaler which affects aftertouch sensitivity andrewm@0: float lastIntensity_, lastBrightness_; // Cached values for mapping qualities andrewm@0: float lastPitch_, lastHarmonic_; andrewm@0: andrewm@0: bool shouldLookForPitchBends_; // Whether to search for adjacent keys to start a pitch bend andrewm@0: std::vector activePitchBends_; // Which keys are involved in a pitch bend andrewm@0: andrewm@0: Node rawVelocity_; // History of key velocity measurements andrewm@0: IIRFilterNode filteredVelocity_; // Filtered key velocity information andrewm@0: Node::size_type lastCalculatedVelocityIndex_; // Keep track of how many velocity samples we've calculated andrewm@0: andrewm@0: bool vibratoActive_; // Whether a vibrato gesture is currently detected andrewm@0: int vibratoVelocityPeakCount_; // Counter for tracking velocity oscillations andrewm@0: timestamp_type vibratoLastPeakTimestamp_; // When the last velocity peak took place andrewm@0: andrewm@0: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MRPMapping) andrewm@0: }; andrewm@0: andrewm@0: #endif /* defined(__touchkeys__MRPMapping__) */