f@0: #pragma once f@0: f@0: #include "RtMidi.h" f@0: #include f@0: #include f@0: #include f@0: f@0: class Config; f@0: f@0: f@0: namespace collidoscope { f@0: f@0: f@0: class MIDIException : public std::exception f@0: { f@0: public: f@0: f@0: MIDIException( std::string message ) : mMessage( message ) {} f@0: f@0: virtual const std::string& getMessage( void ) const { return mMessage; } f@0: f@0: #ifdef _WINDOWS f@0: const char* what() const override { return mMessage.c_str(); } f@0: #else f@0: const char* what() const noexcept override { return mMessage.c_str(); } f@0: #endif f@0: f@0: protected: f@0: std::string mMessage; f@0: }; f@0: f@3: /** f@3: * A MIDI message f@3: */ f@0: class MIDIMessage f@0: { f@0: friend class MIDI; f@0: public: f@0: f@0: enum class Voice { eNoteOn, eNoteOff, ePitchBend, eControlChange, eIgnore }; f@0: f@0: Voice getVoice() { return mVoice; } f@0: f@0: unsigned char getChannel() { return mChannel; } f@0: f@3: /** f@3: * First byte of MIDI data f@3: */ f@0: unsigned char getData_1() { return mData1; } f@0: f@3: /** f@3: * Second byte of MIDI data f@3: */ f@0: unsigned char getData_2() { return mData2; } f@0: f@0: private: f@0: f@0: Voice mVoice = Voice::eIgnore; f@0: unsigned char mChannel; f@0: unsigned char mData1; f@0: unsigned char mData2; f@0: f@0: f@0: }; f@0: f@3: /** f@3: * Handles MIDI messages from the keyboards and Teensy. It uses RtMidi library. f@3: * f@3: */ f@0: class MIDI f@0: { f@0: f@0: public: f@0: f@0: MIDI(); f@0: ~MIDI(); f@0: f@0: void setup( const Config& ); f@0: f@3: /** f@3: * Check new incoming messages and stores them into the vector passed as argument by reference. f@3: */ f@0: void checkMessages( std::vector< MIDIMessage >& ); f@0: f@0: private: f@0: f@3: // callback passed to RtMidi library f@0: static void RtMidiInCallback( double deltatime, std::vector *message, void *userData ); f@0: f@3: // parse RtMidi messages and turns them into more readable collidoscope::MIDIMessages f@0: MIDIMessage parseRtMidiMessage( std::vector *message ); f@0: f@3: // messages to pass to checkMessages caller f@0: std::vector< MIDIMessage > mMIDIMessages; f@3: // use specific variables for pitch bend messages. Pitch bend messages are coming f@3: // from the strip sensors that are very jerky and send a lot of values. So instead f@3: // of saving all the messages in mMIDIMessages just save the last received in mPitchBendMessages f@3: // and optimize away redundant messages. f@0: std::array< MIDIMessage, NUM_WAVES > mPitchBendMessages; f@3: // Same principle of pitch bend messages f@0: std::array< MIDIMessage, NUM_WAVES > mFilterMessages; f@0: f@3: // vecotr containing all the MIDI input devices detected. f@0: std::vector< std::unique_ptr > mInputs; f@3: // Used for mutual access to the MIDI messages by the MIDI thread and the graphic thread. f@0: std::mutex mMutex; f@0: }; f@0: f@0: f@0: f@0: } // collidsocope }