From 410e51c91a344137cfc7d023152afc292b74df99 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 20 Apr 2014 17:23:10 +0200 Subject: [PATCH 1/2] Template settings. --- src/MIDI.h | 2 +- src/MIDI.hpp | 390 +++++++++++++++++++++++--------------------- src/midi_Defs.h | 11 +- src/midi_Settings.h | 20 +++ 4 files changed, 228 insertions(+), 195 deletions(-) diff --git a/src/MIDI.h b/src/MIDI.h index 5575e32..6f21ec6 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -40,7 +40,7 @@ the hardware interface, meaning you can use HardwareSerial, SoftwareSerial or ak47's Uart classes. The only requirement is that the class implements the begin, read, write and available methods. */ -template +template class MidiInterface { public: diff --git a/src/MIDI.hpp b/src/MIDI.hpp index 7a154c2..b6df785 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -26,8 +26,8 @@ BEGIN_MIDI_NAMESPACE /// \brief Constructor for MidiInterface. -template -MidiInterface::MidiInterface(SerialPort& inSerial) +template +inline MidiInterface::MidiInterface(SerialPort& inSerial) : mSerial(inSerial) { #if MIDI_BUILD_INPUT && MIDI_USE_CALLBACKS @@ -56,8 +56,8 @@ MidiInterface::MidiInterface(SerialPort& inSerial) This is not really useful for the Arduino, as it is never called... */ -template -MidiInterface::~MidiInterface() +template +inline MidiInterface::~MidiInterface() { } @@ -69,21 +69,22 @@ MidiInterface::~MidiInterface() - Input channel set to 1 if no value is specified - Full thru mirroring */ -template -void MidiInterface::begin(Channel inChannel) +template +void MidiInterface::begin(Channel inChannel) { // Initialise the Serial port -#if defined(ARDUINO) - mSerial.begin(MIDI_BAUDRATE); -#elif defined(FSE_AVR) - mSerial. template open(); +#if defined(FSE_AVR) + mSerial. template open(); +#else + mSerial.begin(Settings::BaudRate); #endif -#if MIDI_BUILD_OUTPUT && MIDI_USE_RUNNING_STATUS - - mRunningStatus_TX = InvalidType; - -#endif // MIDI_BUILD_OUTPUT && MIDI_USE_RUNNING_STATUS +#if MIDI_BUILD_OUTPUT + if (Settings::UseRunningStatus) + { + mRunningStatus_TX = InvalidType; + } +#endif // MIDI_BUILD_OUTPUT #if MIDI_BUILD_INPUT @@ -133,22 +134,21 @@ void MidiInterface::begin(Channel inChannel) This is an internal method, use it only if you need to send raw data from your code, at your own risks. */ -template -void MidiInterface::send(MidiType inType, - DataByte inData1, - DataByte inData2, - Channel inChannel) +template +void MidiInterface::send(MidiType inType, + DataByte inData1, + DataByte inData2, + Channel inChannel) { // Then test if channel is valid if (inChannel >= MIDI_CHANNEL_OFF || inChannel == MIDI_CHANNEL_OMNI || inType < NoteOff) { - -#if MIDI_USE_RUNNING_STATUS - mRunningStatus_TX = InvalidType; -#endif - + if (Settings::UseRunningStatus) + { + mRunningStatus_TX = InvalidType; + } return; // Don't send anything } @@ -160,18 +160,20 @@ void MidiInterface::send(MidiType inType, const StatusByte status = getStatus(inType, inChannel); -#if MIDI_USE_RUNNING_STATUS - // Check Running Status - if (mRunningStatus_TX != status) + if (Settings::UseRunningStatus) { - // New message, memorise and send header - mRunningStatus_TX = status; - mSerial.write(mRunningStatus_TX); + if (mRunningStatus_TX != status) + { + // New message, memorise and send header + mRunningStatus_TX = status; + mSerial.write(mRunningStatus_TX); + } + } + else + { + // Don't care about running status, send the status byte. + mSerial.write(status); } -#else - // Don't care about running status, send the status byte. - mSerial.write(status); -#endif // Then send data mSerial.write(inData1); @@ -195,10 +197,10 @@ void MidiInterface::send(MidiType inType, Take a look at the values, names and frequencies of notes here: http://www.phys.unsw.edu.au/jw/notes.html */ -template -void MidiInterface::sendNoteOn(DataByte inNoteNumber, - DataByte inVelocity, - Channel inChannel) +template +void MidiInterface::sendNoteOn(DataByte inNoteNumber, + DataByte inVelocity, + Channel inChannel) { send(NoteOn, inNoteNumber, inVelocity, inChannel); } @@ -214,10 +216,10 @@ void MidiInterface::sendNoteOn(DataByte inNoteNumber, Take a look at the values, names and frequencies of notes here: http://www.phys.unsw.edu.au/jw/notes.html */ -template -void MidiInterface::sendNoteOff(DataByte inNoteNumber, - DataByte inVelocity, - Channel inChannel) +template +void MidiInterface::sendNoteOff(DataByte inNoteNumber, + DataByte inVelocity, + Channel inChannel) { send(NoteOff, inNoteNumber, inVelocity, inChannel); } @@ -226,9 +228,9 @@ void MidiInterface::sendNoteOff(DataByte inNoteNumber, \param inProgramNumber The Program to select (0 to 127). \param inChannel The channel on which the message will be sent (1 to 16). */ -template -void MidiInterface::sendProgramChange(DataByte inProgramNumber, - Channel inChannel) +template +void MidiInterface::sendProgramChange(DataByte inProgramNumber, + Channel inChannel) { send(ProgramChange, inProgramNumber, 0, inChannel); } @@ -239,10 +241,10 @@ void MidiInterface::sendProgramChange(DataByte inProgramNumber, \param inChannel The channel on which the message will be sent (1 to 16). @see MidiControlChangeNumber */ -template -void MidiInterface::sendControlChange(DataByte inControlNumber, - DataByte inControlValue, - Channel inChannel) +template +void MidiInterface::sendControlChange(DataByte inControlNumber, + DataByte inControlValue, + Channel inChannel) { send(ControlChange, inControlNumber, inControlValue, inChannel); } @@ -252,10 +254,10 @@ void MidiInterface::sendControlChange(DataByte inControlNumber, \param inPressure The amount of AfterTouch to apply (0 to 127). \param inChannel The channel on which the message will be sent (1 to 16). */ -template -void MidiInterface::sendPolyPressure(DataByte inNoteNumber, - DataByte inPressure, - Channel inChannel) +template +void MidiInterface::sendPolyPressure(DataByte inNoteNumber, + DataByte inPressure, + Channel inChannel) { send(AfterTouchPoly, inNoteNumber, inPressure, inChannel); } @@ -264,9 +266,9 @@ void MidiInterface::sendPolyPressure(DataByte inNoteNumber, \param inPressure The amount of AfterTouch to apply to all notes. \param inChannel The channel on which the message will be sent (1 to 16). */ -template -void MidiInterface::sendAfterTouch(DataByte inPressure, - Channel inChannel) +template +void MidiInterface::sendAfterTouch(DataByte inPressure, + Channel inChannel) { send(AfterTouchChannel, inPressure, 0, inChannel); } @@ -277,9 +279,9 @@ void MidiInterface::sendAfterTouch(DataByte inPressure, center value is 0. \param inChannel The channel on which the message will be sent (1 to 16). */ -template -void MidiInterface::sendPitchBend(int inPitchValue, - Channel inChannel) +template +void MidiInterface::sendPitchBend(int inPitchValue, + Channel inChannel) { const unsigned bend = inPitchValue - MIDI_PITCHBEND_MIN; send(PitchBend, (bend & 0x7f), (bend >> 7) & 0x7f, inChannel); @@ -292,11 +294,11 @@ void MidiInterface::sendPitchBend(int inPitchValue, and +1.0f (max upwards bend), center value is 0.0f. \param inChannel The channel on which the message will be sent (1 to 16). */ -template -void MidiInterface::sendPitchBend(double inPitchValue, - Channel inChannel) +template +void MidiInterface::sendPitchBend(double inPitchValue, + Channel inChannel) { - const int value = inPitchValue * MIDI_PITCHBEND_MAX; + const int value = inPitchValue * MIDI_PITCHBEND_MAX * Settings::Toto; sendPitchBend(value, inChannel); } @@ -309,29 +311,32 @@ void MidiInterface::sendPitchBend(double inPitchValue, default value for ArrayContainsBoundaries is set to 'false' for compatibility with previous versions of the library. */ -template -void MidiInterface::sendSysEx(unsigned inLength, - const byte* inArray, - bool inArrayContainsBoundaries) +template +void MidiInterface::sendSysEx(unsigned inLength, + const byte* inArray, + bool inArrayContainsBoundaries) { - if (inArrayContainsBoundaries == false) + const bool writeBeginEndBytes = !inArrayContainsBoundaries; + + if (writeBeginEndBytes) { mSerial.write(0xf0); + } - for (unsigned i = 0; i < inLength; ++i) - mSerial.write(inArray[i]); + for (unsigned i = 0; i < inLength; ++i) + { + mSerial.write(inArray[i]); + } + if (writeBeginEndBytes) + { mSerial.write(0xf7); } - else - { - for (unsigned i = 0; i < inLength; ++i) - mSerial.write(inArray[i]); - } -#if MIDI_USE_RUNNING_STATUS - mRunningStatus_TX = InvalidType; -#endif + if (Settings::UseRunningStatus) + { + mRunningStatus_TX = InvalidType; + } } /*! \brief Send a Tune Request message. @@ -339,8 +344,8 @@ void MidiInterface::sendSysEx(unsigned inLength, When a MIDI unit receives this message, it should tune its oscillators (if equipped with any). */ -template -void MidiInterface::sendTuneRequest() +template +void MidiInterface::sendTuneRequest() { sendRealTime(TuneRequest); } @@ -351,9 +356,9 @@ void MidiInterface::sendTuneRequest() \param inValuesNibble MTC data See MIDI Specification for more information. */ -template -void MidiInterface::sendTimeCodeQuarterFrame(DataByte inTypeNibble, - DataByte inValuesNibble) +template +void MidiInterface::sendTimeCodeQuarterFrame(DataByte inTypeNibble, + DataByte inValuesNibble) { const byte data = (((inTypeNibble & 0x07) << 4) | (inValuesNibble & 0x0f)); sendTimeCodeQuarterFrame(data); @@ -365,42 +370,45 @@ void MidiInterface::sendTimeCodeQuarterFrame(DataByte inTypeNibble, \param inData if you want to encode directly the nibbles in your program, you can send the byte here. */ -template -void MidiInterface::sendTimeCodeQuarterFrame(DataByte inData) +template +void MidiInterface::sendTimeCodeQuarterFrame(DataByte inData) { mSerial.write((byte)TimeCodeQuarterFrame); mSerial.write(inData); -#if MIDI_USE_RUNNING_STATUS - mRunningStatus_TX = InvalidType; -#endif + if (Settings::UseRunningStatus) + { + mRunningStatus_TX = InvalidType; + } } /*! \brief Send a Song Position Pointer message. \param inBeats The number of beats since the start of the song. */ -template -void MidiInterface::sendSongPosition(unsigned inBeats) +template +void MidiInterface::sendSongPosition(unsigned inBeats) { mSerial.write((byte)SongPosition); mSerial.write(inBeats & 0x7f); mSerial.write((inBeats >> 7) & 0x7f); -#if MIDI_USE_RUNNING_STATUS - mRunningStatus_TX = InvalidType; -#endif + if (Settings::UseRunningStatus) + { + mRunningStatus_TX = InvalidType; + } } /*! \brief Send a Song Select message */ -template -void MidiInterface::sendSongSelect(DataByte inSongNumber) +template +void MidiInterface::sendSongSelect(DataByte inSongNumber) { mSerial.write((byte)SongSelect); mSerial.write(inSongNumber & 0x7f); -#if MIDI_USE_RUNNING_STATUS - mRunningStatus_TX = InvalidType; -#endif + if (Settings::UseRunningStatus) + { + mRunningStatus_TX = InvalidType; + } } /*! \brief Send a Real Time (one byte) message. @@ -410,8 +418,8 @@ void MidiInterface::sendSongSelect(DataByte inSongNumber) You can also send a Tune Request with this method. @see MidiType */ -template -void MidiInterface::sendRealTime(MidiType inType) +template +void MidiInterface::sendRealTime(MidiType inType) { switch (inType) { @@ -432,18 +440,19 @@ void MidiInterface::sendRealTime(MidiType inType) // Do not cancel Running Status for real-time messages as they can be // interleaved within any message. Though, TuneRequest can be sent here, // and as it is a System Common message, it must reset Running Status. -#if MIDI_USE_RUNNING_STATUS - if (inType == TuneRequest) mRunningStatus_TX = InvalidType; -#endif + if (Settings::UseRunningStatus && inType == TuneRequest) + { + mRunningStatus_TX = InvalidType; + } } /*! @} */ // End of doc group MIDI Output // ----------------------------------------------------------------------------- -template -StatusByte MidiInterface::getStatus(MidiType inType, - Channel inChannel) const +template +StatusByte MidiInterface::getStatus(MidiType inType, + Channel inChannel) const { return ((byte)inType | ((inChannel - 1) & 0x0f)); } @@ -469,16 +478,16 @@ StatusByte MidiInterface::getStatus(MidiType inType, it is sent back on the MIDI output. @see see setInputChannel() */ -template -inline bool MidiInterface::read() +template +inline bool MidiInterface::read() { return read(mInputChannel); } /*! \brief Read messages on a specified channel. */ -template -inline bool MidiInterface::read(Channel inChannel) +template +inline bool MidiInterface::read(Channel inChannel) { if (inChannel >= MIDI_CHANNEL_OFF) return false; // MIDI Input disabled. @@ -506,8 +515,8 @@ inline bool MidiInterface::read(Channel inChannel) // ----------------------------------------------------------------------------- // Private method: MIDI parser -template -bool MidiInterface::parse() +template +bool MidiInterface::parse() { if (mSerial.available() == 0) // No data available. @@ -770,24 +779,26 @@ bool MidiInterface::parse() // Then update the index of the pending message. mPendingMessageIndex++; -#if USE_1BYTE_PARSING - // Message is not complete. - return false; -#else - // Call the parser recursively - // to parse the rest of the message. - return parse(); -#endif + if (Settings::Use1ByteParsing) + { + // Message is not complete. + return false; + } + else + { + // Call the parser recursively to parse the rest of the message. + return parse(); + } } } } // Private method, see midi_Settings.h for documentation -template -inline void MidiInterface::handleNullVelocityNoteOnAsNoteOff() +template +inline void MidiInterface::handleNullVelocityNoteOnAsNoteOff() { - #if MIDI_HANDLE_NULL_VELOCITY_NOTE_ON_AS_NOTE_OFF - if (getType() == NoteOn && getData2() == 0) + if (Settings::HandleNullVelocityNoteOnAsNoteOff && + getType() == NoteOn && getData2() == 0) { mMessage.type = NoteOff; } @@ -795,8 +806,8 @@ inline void MidiInterface::handleNullVelocityNoteOnAsNoteOff() } // Private method: check if the received message is on the listened channel -template -inline bool MidiInterface::inputFilter(Channel inChannel) +template +inline bool MidiInterface::inputFilter(Channel inChannel) { // This method handles recognition of channel // (to know if the message is destinated to the Arduino) @@ -827,8 +838,8 @@ inline bool MidiInterface::inputFilter(Channel inChannel) } // Private method: reset input attributes -template -inline void MidiInterface::resetInput() +template +inline void MidiInterface::resetInput() { mPendingMessageIndex = 0; mPendingMessageExpectedLenght = 0; @@ -841,8 +852,8 @@ inline void MidiInterface::resetInput() Returns an enumerated type. @see MidiType */ -template -MidiType MidiInterface::getType() const +template +MidiType MidiInterface::getType() const { return mMessage.type; } @@ -852,22 +863,22 @@ MidiType MidiInterface::getType() const \return Channel range is 1 to 16. For non-channel messages, this will return 0. */ -template -Channel MidiInterface::getChannel() const +template +Channel MidiInterface::getChannel() const { return mMessage.channel; } /*! \brief Get the first data byte of the last received message. */ -template -DataByte MidiInterface::getData1() const +template +DataByte MidiInterface::getData1() const { return mMessage.data1; } /*! \brief Get the second data byte of the last received message. */ -template -DataByte MidiInterface::getData2() const +template +DataByte MidiInterface::getData2() const { return mMessage.data2; } @@ -876,8 +887,8 @@ DataByte MidiInterface::getData2() const @see getSysExArrayLength to get the array's length in bytes. */ -template -const byte* MidiInterface::getSysExArray() const +template +const byte* MidiInterface::getSysExArray() const { return mMessage.sysexArray; } @@ -887,24 +898,25 @@ const byte* MidiInterface::getSysExArray() const It is coded using data1 as LSB and data2 as MSB. \return The array's length, in bytes. */ -template -unsigned MidiInterface::getSysExArrayLength() const +template +unsigned MidiInterface::getSysExArrayLength() const { - const unsigned size = ((unsigned)(mMessage.data2) << 8) | mMessage.data1; - return (size > MIDI_SYSEX_ARRAY_SIZE) ? MIDI_SYSEX_ARRAY_SIZE : size; + static const unsigned maxSize = Settings::SysExArraySize; + const unsigned size = (unsigned(mMessage.data2) << 8) | mMessage.data1; + return (size > maxSize) ? maxSize : size; } /*! \brief Check if a valid message is stored in the structure. */ -template -bool MidiInterface::check() const +template +bool MidiInterface::check() const { return mMessage.valid; } // ----------------------------------------------------------------------------- -template -Channel MidiInterface::getInputChannel() const +template +Channel MidiInterface::getInputChannel() const { return mInputChannel; } @@ -913,8 +925,8 @@ Channel MidiInterface::getInputChannel() const \param inChannel the channel value. Valid values are 1 to 16, MIDI_CHANNEL_OMNI if you want to listen to all channels, and MIDI_CHANNEL_OFF to disable input. */ -template -void MidiInterface::setInputChannel(Channel inChannel) +template +void MidiInterface::setInputChannel(Channel inChannel) { mInputChannel = inChannel; } @@ -926,8 +938,8 @@ void MidiInterface::setInputChannel(Channel inChannel) This is a utility static method, used internally, made public so you can handle MidiTypes more easily. */ -template -MidiType MidiInterface::getTypeFromStatusByte(byte inStatus) +template +MidiType MidiInterface::getTypeFromStatusByte(byte inStatus) { if ((inStatus < 0x80) || (inStatus == 0xf4) || @@ -949,14 +961,14 @@ MidiType MidiInterface::getTypeFromStatusByte(byte inStatus) /*! \brief Returns channel in the range 1-16 */ -template -inline Channel MidiInterface::getChannelFromStatusByte(byte inStatus) +template +inline Channel MidiInterface::getChannelFromStatusByte(byte inStatus) { return (inStatus & 0x0f) + 1; } -template -bool MidiInterface::isChannelMessage(MidiType inType) +template +bool MidiInterface::isChannelMessage(MidiType inType) { return (inType == NoteOff || inType == NoteOn || @@ -975,24 +987,24 @@ bool MidiInterface::isChannelMessage(MidiType inType) @{ */ -template void MidiInterface::setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOffCallback = fptr; } -template void MidiInterface::setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOnCallback = fptr; } -template void MidiInterface::setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) { mAfterTouchPolyCallback = fptr; } -template void MidiInterface::setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)) { mControlChangeCallback = fptr; } -template void MidiInterface::setHandleProgramChange(void (*fptr)(byte channel, byte number)) { mProgramChangeCallback = fptr; } -template void MidiInterface::setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)) { mAfterTouchChannelCallback = fptr; } -template void MidiInterface::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; } -template void MidiInterface::setHandleSystemExclusive(void (*fptr)(byte* array, byte size)) { mSystemExclusiveCallback = fptr; } -template void MidiInterface::setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)) { mTimeCodeQuarterFrameCallback = fptr; } -template void MidiInterface::setHandleSongPosition(void (*fptr)(unsigned beats)) { mSongPositionCallback = fptr; } -template void MidiInterface::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; } -template void MidiInterface::setHandleTuneRequest(void (*fptr)(void)) { mTuneRequestCallback = fptr; } -template void MidiInterface::setHandleClock(void (*fptr)(void)) { mClockCallback = fptr; } -template void MidiInterface::setHandleStart(void (*fptr)(void)) { mStartCallback = fptr; } -template void MidiInterface::setHandleContinue(void (*fptr)(void)) { mContinueCallback = fptr; } -template void MidiInterface::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; } -template void MidiInterface::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; } -template void MidiInterface::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; } +template void MidiInterface::setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOffCallback = fptr; } +template void MidiInterface::setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)) { mNoteOnCallback = fptr; } +template void MidiInterface::setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure)) { mAfterTouchPolyCallback = fptr; } +template void MidiInterface::setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)) { mControlChangeCallback = fptr; } +template void MidiInterface::setHandleProgramChange(void (*fptr)(byte channel, byte number)) { mProgramChangeCallback = fptr; } +template void MidiInterface::setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure)) { mAfterTouchChannelCallback = fptr; } +template void MidiInterface::setHandlePitchBend(void (*fptr)(byte channel, int bend)) { mPitchBendCallback = fptr; } +template void MidiInterface::setHandleSystemExclusive(void (*fptr)(byte* array, byte size)) { mSystemExclusiveCallback = fptr; } +template void MidiInterface::setHandleTimeCodeQuarterFrame(void (*fptr)(byte data)) { mTimeCodeQuarterFrameCallback = fptr; } +template void MidiInterface::setHandleSongPosition(void (*fptr)(unsigned beats)) { mSongPositionCallback = fptr; } +template void MidiInterface::setHandleSongSelect(void (*fptr)(byte songnumber)) { mSongSelectCallback = fptr; } +template void MidiInterface::setHandleTuneRequest(void (*fptr)(void)) { mTuneRequestCallback = fptr; } +template void MidiInterface::setHandleClock(void (*fptr)(void)) { mClockCallback = fptr; } +template void MidiInterface::setHandleStart(void (*fptr)(void)) { mStartCallback = fptr; } +template void MidiInterface::setHandleContinue(void (*fptr)(void)) { mContinueCallback = fptr; } +template void MidiInterface::setHandleStop(void (*fptr)(void)) { mStopCallback = fptr; } +template void MidiInterface::setHandleActiveSensing(void (*fptr)(void)) { mActiveSensingCallback = fptr; } +template void MidiInterface::setHandleSystemReset(void (*fptr)(void)) { mSystemResetCallback = fptr; } /*! \brief Detach an external function from the given type. @@ -1000,8 +1012,8 @@ template void MidiInterface::setHandleSystemReset( \param inType The type of message to unbind. When a message of this type is received, no function will be called. */ -template -void MidiInterface::disconnectCallbackFromType(MidiType inType) +template +void MidiInterface::disconnectCallbackFromType(MidiType inType) { switch (inType) { @@ -1031,8 +1043,8 @@ void MidiInterface::disconnectCallbackFromType(MidiType inType) /*! @} */ // End of doc group MIDI Callbacks // Private - launch callback function based on received type. -template -void MidiInterface::launchCallback() +template +void MidiInterface::launchCallback() { // The order is mixed to allow frequent messages to trigger their callback faster. switch (mMessage.type) @@ -1092,8 +1104,8 @@ void MidiInterface::launchCallback() @see MidiFilterMode */ -template -void MidiInterface::setThruFilterMode(MidiFilterMode inThruFilterMode) +template +void MidiInterface::setThruFilterMode(MidiFilterMode inThruFilterMode) { mThruFilterMode = inThruFilterMode; if (mThruFilterMode != Off) @@ -1102,27 +1114,27 @@ void MidiInterface::setThruFilterMode(MidiFilterMode inThruFilterMod mThruActivated = false; } -template -MidiFilterMode MidiInterface::getFilterMode() const +template +MidiFilterMode MidiInterface::getFilterMode() const { return mThruFilterMode; } -template -bool MidiInterface::getThruState() const +template +bool MidiInterface::getThruState() const { return mThruActivated; } -template -void MidiInterface::turnThruOn(MidiFilterMode inThruFilterMode) +template +void MidiInterface::turnThruOn(MidiFilterMode inThruFilterMode) { mThruActivated = true; mThruFilterMode = inThruFilterMode; } -template -void MidiInterface::turnThruOff() +template +void MidiInterface::turnThruOff() { mThruActivated = false; mThruFilterMode = Off; @@ -1136,8 +1148,8 @@ void MidiInterface::turnThruOff() // to output unless filter is set to Off. // - Channel messages are passed to the output whether their channel // is matching the input channel and the filter setting -template -void MidiInterface::thruFilter(Channel inChannel) +template +void MidiInterface::thruFilter(Channel inChannel) { // If the feature is disabled, don't do anything. if (!mThruActivated || (mThruFilterMode == Off)) diff --git a/src/midi_Defs.h b/src/midi_Defs.h index 324f361..dc2b29a 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -207,11 +207,12 @@ struct Message #define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \ midi::MidiInterface Name((Type&)SerialPort); -/*! \brief Shortcut for MIDI Interface class with template argument. - The class name for a MIDI object using the hardware UART would be - midi::MidiInterface, when the macro is MIDI_CLASS(HardwareSerial). +/*! \brief Create an instance of the library attached to a serial port with + custom settings. + @see DefaultSettings + @see MIDI_CREATE_INSTANCE */ -#define MIDI_CLASS(Type) \ - midi::MidiInterface +#define MIDI_CREATE_CUSTOM_INSTANCE(Type, SerialPort, Name, Settings) \ + midi::MidiInterface Name((Type&)SerialPort); END_MIDI_NAMESPACE diff --git a/src/midi_Settings.h b/src/midi_Settings.h index cd2d021..f2ea338 100644 --- a/src/midi_Settings.h +++ b/src/midi_Settings.h @@ -99,4 +99,24 @@ BEGIN_MIDI_NAMESPACE +/*! \brief Default Settings Traits struct + To change the default settings, don't edit them there, create a subclass and + override the values in that subclass, then use the MIDI_CREATE_CUSTOM_INSTANCE + macro to create your instance. The settings you don't override will keep their + default value. Eg: + struct MySettings : public midi::DefaultSettings + { + static const bool UseRunningStatus = false; // Messes with my old equipment! + }; + MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial2, midi, MySettings); + */ +struct DefaultSettings +{ + static const bool UseRunningStatus = true; + static const bool HandleNullVelocityNoteOnAsNoteOff = true; + static const bool Use1ByteParsing = true; + static const unsigned BaudRate = 31250; + static const unsigned SysExArraySize = 128; +}; + END_MIDI_NAMESPACE From f88012b38fb3179339ee2fc5a3a35b59145ed891 Mon Sep 17 00:00:00 2001 From: Francois Best Date: Sun, 20 Apr 2014 17:24:35 +0200 Subject: [PATCH 2/2] Removed auto-instanciation --- src/MIDI.cpp | 21 --------------- src/MIDI.h | 63 ++++++++++++++------------------------------- src/MIDI.hpp | 43 +++++++++++++++---------------- src/midi_Defs.h | 8 +++--- src/midi_Settings.h | 30 --------------------- 5 files changed, 45 insertions(+), 120 deletions(-) diff --git a/src/MIDI.cpp b/src/MIDI.cpp index b8f1c0c..fa356ce 100644 --- a/src/MIDI.cpp +++ b/src/MIDI.cpp @@ -25,27 +25,6 @@ // ----------------------------------------------------------------------------- -#if !(MIDI_BUILD_INPUT) && !(MIDI_BUILD_OUTPUT) -# error To use MIDI, you need to enable at least input or output. -#endif - -#if MIDI_BUILD_THRU && !(MIDI_BUILD_OUTPUT) -# error For thru to work, you need to enable output. -#endif -#if MIDI_BUILD_THRU && !(MIDI_BUILD_INPUT) -# error For thru to work, you need to enable input. -#endif - -// ----------------------------------------------------------------------------- - -#if MIDI_AUTO_INSTANCIATE && defined(ARDUINO) - MIDI_CREATE_INSTANCE(MIDI_DEFAULT_SERIAL_CLASS, - MIDI_DEFAULT_SERIAL_PORT, - MIDI); -#endif - -// ----------------------------------------------------------------------------- - BEGIN_MIDI_NAMESPACE /*! \brief Encode System Exclusive messages. diff --git a/src/MIDI.h b/src/MIDI.h index 6f21ec6..dc6baed 100644 --- a/src/MIDI.h +++ b/src/MIDI.h @@ -26,10 +26,6 @@ #include "midi_Settings.h" #include "midi_Defs.h" -#ifdef FSE_AVR -#include -#endif - // ----------------------------------------------------------------------------- BEGIN_MIDI_NAMESPACE @@ -44,8 +40,8 @@ template class MidiInterface { public: - MidiInterface(SerialPort& inSerial); - ~MidiInterface(); + inline MidiInterface(SerialPort& inSerial); + inline ~MidiInterface(); public: void begin(Channel inChannel = 1); @@ -53,8 +49,6 @@ public: // ------------------------------------------------------------------------- // MIDI Output -#if MIDI_BUILD_OUTPUT - public: inline void sendNoteOn(DataByte inNoteNumber, DataByte inVelocity, @@ -100,17 +94,9 @@ public: DataByte inData2, Channel inChannel); -private: - inline StatusByte getStatus(MidiType inType, - Channel inChannel) const; - -#endif // MIDI_BUILD_OUTPUT - // ------------------------------------------------------------------------- // MIDI Input -#if MIDI_BUILD_INPUT - public: inline bool read(); inline bool read(Channel inChannel); @@ -133,25 +119,10 @@ public: static inline Channel getChannelFromStatusByte(byte inStatus); static inline bool isChannelMessage(MidiType inType); -private: - bool parse(); - inline void handleNullVelocityNoteOnAsNoteOff(); - inline bool inputFilter(Channel inChannel); - inline void resetInput(); - -private: - StatusByte mRunningStatus_RX; - Channel mInputChannel; - byte mPendingMessage[3]; - unsigned mPendingMessageExpectedLenght; - unsigned mPendingMessageIndex; - Message mMessage; // ------------------------------------------------------------------------- // Input Callbacks -#if MIDI_USE_CALLBACKS - public: inline void setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity)); inline void setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity)); @@ -196,14 +167,9 @@ private: void (*mActiveSensingCallback)(void); void (*mSystemResetCallback)(void); -#endif // MIDI_USE_CALLBACKS -#endif // MIDI_BUILD_INPUT - // ------------------------------------------------------------------------- // MIDI Soft Thru -#if MIDI_BUILD_THRU - public: inline MidiFilterMode getFilterMode() const; inline bool getThruState() const; @@ -216,11 +182,28 @@ public: private: void thruFilter(byte inChannel); +private: + bool parse(); + inline void handleNullVelocityNoteOnAsNoteOff(); + inline bool inputFilter(Channel inChannel); + inline void resetInput(); + private: bool mThruActivated : 1; MidiFilterMode mThruFilterMode : 7; -#endif // MIDI_BUILD_THRU +private: + StatusByte mRunningStatus_RX; + Channel mInputChannel; + byte mPendingMessage[3]; + unsigned mPendingMessageExpectedLenght; + unsigned mPendingMessageIndex; + Message mMessage; + +private: + inline StatusByte getStatus(MidiType inType, + Channel inChannel) const; + #if MIDI_USE_RUNNING_STATUS @@ -241,10 +224,4 @@ END_MIDI_NAMESPACE // ----------------------------------------------------------------------------- -#if MIDI_AUTO_INSTANCIATE && defined(ARDUINO) - extern MIDI_NAMESPACE::MidiInterface MIDI; -#endif - -// ----------------------------------------------------------------------------- - #include "MIDI.hpp" diff --git a/src/MIDI.hpp b/src/MIDI.hpp index b6df785..2ffd715 100644 --- a/src/MIDI.hpp +++ b/src/MIDI.hpp @@ -143,7 +143,7 @@ void MidiInterface::send(MidiType inType, // Then test if channel is valid if (inChannel >= MIDI_CHANNEL_OFF || inChannel == MIDI_CHANNEL_OMNI || - inType < NoteOff) + inType < 0x80) { if (Settings::UseRunningStatus) { @@ -178,12 +178,14 @@ void MidiInterface::send(MidiType inType, // Then send data mSerial.write(inData1); if (inType != ProgramChange && inType != AfterTouchChannel) + { mSerial.write(inData2); - - return; + } } else if (inType >= TuneRequest && inType <= SystemReset) + { sendRealTime(inType); // System Real-time and 1 byte. + } } // ----------------------------------------------------------------------------- @@ -212,7 +214,7 @@ void MidiInterface::sendNoteOn(DataByte inNoteNumber, Note: you can send NoteOn with zero velocity to make a NoteOff, this is based on the Running Status principle, to avoid sending status messages and thus - sending only NoteOn data. This method will always send a real NoteOff message. + sending only NoteOn data. sendNoteOff will always send a real NoteOff message. Take a look at the values, names and frequencies of notes here: http://www.phys.unsw.edu.au/jw/notes.html */ @@ -492,24 +494,22 @@ inline bool MidiInterface::read(Channel inChannel) if (inChannel >= MIDI_CHANNEL_OFF) return false; // MIDI Input disabled. - if (parse()) + if (!parse()) + return false; + + handleNullVelocityNoteOnAsNoteOff(); + const bool channelMatch = inputFilter(inChannel); + + if (MIDI_USE_CALLBACKS && channelMatch) { - handleNullVelocityNoteOnAsNoteOff(); - if (inputFilter(inChannel)) - { - -#if (MIDI_BUILD_OUTPUT && MIDI_BUILD_THRU) - thruFilter(inChannel); -#endif - -#if MIDI_USE_CALLBACKS - launchCallback(); -#endif - return true; - } + launchCallback(); } - return false; +#if MIDI_BUILD_THRU + thruFilter(inChannel); +#endif + + return channelMatch; } // ----------------------------------------------------------------------------- @@ -802,7 +802,6 @@ inline void MidiInterface::handleNullVelocityNoteOnAsNoteO { mMessage.type = NoteOff; } - #endif } // Private method: check if the received message is on the listened channel @@ -953,10 +952,10 @@ MidiType MidiInterface::getTypeFromStatusByte(byte inStatu if (inStatus < 0xf0) { // Channel message, remove channel nibble. - return (MidiType)(inStatus & 0xf0); + return MidiType(inStatus & 0xf0); } - return (MidiType)inStatus; + return MidiType(inStatus); } /*! \brief Returns channel in the range 1-16 diff --git a/src/midi_Defs.h b/src/midi_Defs.h index dc2b29a..84315be 100644 --- a/src/midi_Defs.h +++ b/src/midi_Defs.h @@ -24,6 +24,7 @@ #pragma once #include "midi_Namespace.h" +#include "midi_Settings.h" #include BEGIN_MIDI_NAMESPACE @@ -39,8 +40,7 @@ BEGIN_MIDI_NAMESPACE // ----------------------------------------------------------------------------- // Type definitions -typedef uint8_t byte; - +typedef uint8_t byte; typedef byte StatusByte; typedef byte DataByte; typedef byte Channel; @@ -163,7 +163,6 @@ enum MidiControlChangeNumber */ struct Message { - /*! The MIDI channel on which the message was recieved. \n Value goes from 1 to 16. */ @@ -196,13 +195,14 @@ struct Message validity means the message respects the MIDI norm. */ bool valid; - }; // ----------------------------------------------------------------------------- /*! \brief Create an instance of the library attached to a serial port. You can use HardwareSerial or SoftwareSerial for the serial port. + Example: MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, midi2); + Then call midi2.begin(), midi2.read() etc.. */ #define MIDI_CREATE_INSTANCE(Type, SerialPort, Name) \ midi::MidiInterface Name((Type&)SerialPort); diff --git a/src/midi_Settings.h b/src/midi_Settings.h index f2ea338..85270e8 100644 --- a/src/midi_Settings.h +++ b/src/midi_Settings.h @@ -44,36 +44,6 @@ #define MIDI_USE_CALLBACKS 1 -// ----------------------------------------------------------------------------- - -// Create a MIDI object automatically on the port defined with MIDI_SERIAL_PORT. -#ifndef MIDI_AUTO_INSTANCIATE -# ifdef ARDUINO -# define MIDI_AUTO_INSTANCIATE 1 -# else -# define MIDI_AUTO_INSTANCIATE 0 ///< @see MIDI_CREATE_INSTANCE -# endif -#endif - -// ----------------------------------------------------------------------------- -// Default serial port configuration (if MIDI_AUTO_INSTANCIATE is set) - -// Set the default port to use for MIDI. -#if MIDI_AUTO_INSTANCIATE -# ifdef ARDUINO -# include "Arduino.h" -# ifdef USBCON -# define MIDI_DEFAULT_SERIAL_PORT Serial1 // For Leonardo -# else -# define MIDI_DEFAULT_SERIAL_PORT Serial // For other Arduinos -# endif -# define MIDI_DEFAULT_SERIAL_CLASS HardwareSerial -# include "HardwareSerial.h" -# else -# error Auto-instanciation disabled. Use MIDI_CREATE_INSTANCE macro. -# endif -#endif - // ----------------------------------------------------------------------------- // Misc. options