Mercurial > hg > touchkeys
view Source/TouchKeys/PianoKey.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/>. ===================================================================== PianoKey.h: handles the operation of a single key on the keyboard, including fusing touch and MIDI data. Also has hooks for continuous key angle. */ #ifndef KEYCONTROL_PIANOKEY_H #define KEYCONTROL_PIANOKEY_H #include <set> #include <map> #include <list> #include "../JuceLibraryCode/JuceHeader.h" #include "../Utility/Node.h" #include "PianoTypes.h" #include "KeyIdleDetector.h" #include "KeyPositionTracker.h" #include "KeyTouchFrame.h" #include "../Utility/Scheduler.h" #include "../Utility/IIRFilter.h" const unsigned int kPianoKeyStateBufferLength = 20; // How many previous states to save const unsigned int kPianoKeyIdleBufferLength = 10; // How many idle/active transitions to save const unsigned int kPianoKeyPositionTrackerBufferLength = 30; // How many state histories to save const key_position kPianoKeyDefaultIdleActivityThreshold = scale_key_position(.020); const key_position kPianoKeyDefaultIdlePositionThreshold = scale_key_position(.05); const int kPianoKeyDefaultIdleCounter = 20; const timestamp_diff_type kPianoKeyDefaultTouchTimeoutInterval = microseconds_to_timestamp(0); // was 20000 const timestamp_diff_type kPianoKeyGuiUpdateInterval = microseconds_to_timestamp(15000); // How frequently to update the position display // Possible key states enum { kKeyStateToBeInitialized = -1, kKeyStateUnknown = 0, kKeyStateDisabled, kKeyStateIdle, kKeyStateActive }; // Possible touch events enum { kTouchEventIdle = 0, kTouchEventAdd, kTouchEventRemove }; typedef int key_state; class PianoKeyboard; class MidiKeyboardSegment; /* * PianoKey * * This class holds the buffer and state information for a single piano key, * with methods to manage its status. */ class PianoKey : public TriggerDestination { private: // ***** Internal Classes ***** // Data on key touch events: what, when and where struct KeyTouchEvent { int type; timestamp_type timestamp; KeyTouchFrame frame; }; public: // ***** Constructors ***** PianoKey(PianoKeyboard& keyboard, int noteNumber, int bufferLength); //PianoKey(PianoKey const& obj); // ***** Destructor ***** ~PianoKey(); // ***** Access Methods ***** Node<key_position>& buffer() { return positionBuffer_; } // ***** Control Methods ***** // // Force changes in the key state (e.g. to resolve stuck notes) // Enable or disable a key from generating events void disable(); void enable(); // Force the key to the Idle state, provided it is enabled void forceIdle(); // Clear any previous state, go back to initial state void reset(); void insertSample(key_position pos, timestamp_type ts); // ***** Trigger Methods ***** // // This will be called by positionBuffer_ on each new sample. Examine each sample to see // whether the key is idle or not. void triggerReceived(TriggerSource* who, timestamp_type timestamp); // ***** MIDI Methods ***** // // If MIDI input is used to control this note, the controller should call these functions void midiNoteOn(MidiKeyboardSegment *who, int velocity, int channel, timestamp_type timestamp); void midiNoteOff(MidiKeyboardSegment *who, timestamp_type timestamp); void midiAftertouch(MidiKeyboardSegment *who, int value, timestamp_type timestamp); bool midiNoteIsOn() { return midiNoteIsOn_; } int midiVelocity() { return midiVelocity_; } int midiChannel() { return midiChannel_; } void changeMidiChannel(int newChannel) { midiChannel_ = newChannel; } int midiOutputPort() { return midiOutputPort_; } void changeMidiOutputPort(int newPort) { midiOutputPort_ = newPort; } // ***** Touch Methods ***** // // If touchkeys are used, the controller uses these functions to provide data // touchInsertFrame() implies touch is active if not already. void touchInsertFrame(KeyTouchFrame& newFrame, timestamp_type timestamp); void touchOff(timestamp_type timestamp); bool touchIsActive() { return touchIsActive_; } void setTouchSensorsPresent(bool present) { touchSensorsArePresent_ = present; } // This function is called on a timer when the key receives MIDI data before touch data // and wants to wait to integrate the two. If the touch data doesn't materialize, this function // is called by the scheduler. timestamp_type touchTimedOut(); private: // ***** MIDI Methods (private) ***** // This method does the real work of midiNoteOn(), and might be called from it directly // or after a delay. void midiNoteOnHelper(MidiKeyboardSegment *who); // ***** Touch Methods (private) ***** std::pair<float, std::list<int> > touchMatchClosestPoints(const float* oldPoints, const float *newPoints, float count, int oldIndex, std::set<int>& availableNewPoints, float currentTotalDistance); void touchAdd(const KeyTouchFrame& frame, int index, timestamp_type timestamp); void touchRemove(const KeyTouchFrame& frame, int idRemoved, int remainingCount, timestamp_type timestamp); void touchMultiFingerGestures(const KeyTouchFrame& lastFrame, const KeyTouchFrame& newFrame, timestamp_type timestamp); // ***** State Machine Methods ***** // // This class maintains a current state that determines its response to the incoming // key position data. void changeState(key_state newState); void changeState(key_state newState, timestamp_type timestamp); void terminateActivity(); // ***** Member Variables ***** // Reference back to the keyboard which centralizes control PianoKeyboard& keyboard_; // Identity of the key (MIDI note number) int noteNumber_; // --- Data related to MIDI --- bool midiNoteIsOn_; // Whether this note is currently active from MIDI int midiChannel_; // MIDI channel currently associated with this note int midiOutputPort_; // Which port MIDI output for this note goes to int midiVelocity_; // Velocity of last MIDI onset Node<int> midiAftertouch_; // Aftertouch history on this note, if any // Timestamps for the most recent MIDI note on and note off events timestamp_type midiOnTimestamp_, midiOffTimestamp_; // --- Data related to continuous key position --- Node<key_position> positionBuffer_; // Buffer that holds the key positions KeyIdleDetector idleDetector_; // Detector for whether the key is still or moving KeyPositionTracker positionTracker_; // Object to track the various active states of the key timestamp_type timeOfLastGuiUpdate_; // How long it's been since the last key position GUI call timestamp_type timeOfLastDebugPrint_; // TESTING Node<key_state> stateBuffer_; // State history key_state state_; // Current state of the key (see enum above) CriticalSection stateMutex_; // Use this to synchronize changes of state //IIRFilterNode<key_position> testFilter_; // Filter the raw key position data, for testing // --- Data related to surface touches --- bool touchSensorsArePresent_; // Whether touch sensitivity exists on this key bool touchIsActive_; // Whether the user is currently touching the key Node<KeyTouchFrame> touchBuffer_; // Buffer that holds touchkey frames std::multimap<int, KeyTouchEvent> touchEvents_; // Mapping from touch number to event bool touchIsWaiting_; // Whether we're waiting for a touch to occur MidiKeyboardSegment *touchWaitingSource_; // Who we're waiting from a touch for timestamp_type touchWaitingTimestamp_; // When the timeout will occur timestamp_diff_type touchTimeoutInterval_; // How long to wait for a touch before timing out JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PianoKey) }; #endif /* KEYCONTROL_PIANOKEY_H */