2019-12-24 15:05:24 +00:00
|
|
|
#ifndef cwMidi_h
|
|
|
|
#define cwMidi_h
|
|
|
|
|
|
|
|
namespace cw
|
|
|
|
{
|
|
|
|
namespace midi
|
|
|
|
{
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
kMidiChCnt = 16,
|
|
|
|
kInvalidMidiByte = 128,
|
|
|
|
kMidiNoteCnt = kInvalidMidiByte,
|
|
|
|
kMidiCtlCnt = kInvalidMidiByte,
|
2022-10-15 13:26:35 +00:00
|
|
|
kMidiVelCnt = kInvalidMidiByte,
|
2019-12-24 15:05:24 +00:00
|
|
|
kMidiPgmCnt = kInvalidMidiByte,
|
|
|
|
kInvalidMidiPitch = kInvalidMidiByte,
|
|
|
|
kInvalidMidiVelocity = kInvalidMidiByte,
|
|
|
|
kInvalidMidiCtl = kInvalidMidiByte,
|
|
|
|
kInvalidMidiPgm = kInvalidMidiByte,
|
|
|
|
kMidiSciPitchCharCnt = 5 // A#-1
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// MIDI status bytes
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
kInvalidStatusMdId = 0x00,
|
|
|
|
kNoteOffMdId = 0x80,
|
|
|
|
kNoteOnMdId = 0x90,
|
|
|
|
kPolyPresMdId = 0xa0,
|
|
|
|
kCtlMdId = 0xb0,
|
|
|
|
kPgmMdId = 0xc0,
|
|
|
|
kChPresMdId = 0xd0,
|
|
|
|
kPbendMdId = 0xe0,
|
|
|
|
kSysExMdId = 0xf0,
|
|
|
|
|
|
|
|
kSysComMtcMdId = 0xf1,
|
|
|
|
kSysComSppMdId = 0xf2,
|
|
|
|
kSysComSelMdId = 0xf3,
|
|
|
|
kSysComUndef0MdId = 0xf4,
|
|
|
|
kSysComUndef1MdId = 0xf5,
|
|
|
|
kSysComTuneMdId = 0xf6,
|
|
|
|
kSysComEoxMdId = 0xf7,
|
|
|
|
|
|
|
|
kSysRtClockMdId = 0xf8,
|
|
|
|
kSysRtUndef0MdId = 0xf9,
|
|
|
|
kSysRtStartMdId = 0xfa,
|
|
|
|
kSysRtContMdId = 0xfb,
|
|
|
|
kSysRtStopMdId = 0xfc,
|
|
|
|
kSysRtUndef1MdId = 0xfd,
|
|
|
|
kSysRtSenseMdId = 0xfe,
|
|
|
|
kSysRtResetMdId = 0xff,
|
|
|
|
kMetaStId = 0xff,
|
|
|
|
|
|
|
|
kSeqNumbMdId = 0x00,
|
|
|
|
kTextMdId = 0x01,
|
|
|
|
kCopyMdId = 0x02,
|
|
|
|
kTrkNameMdId = 0x03,
|
|
|
|
kInstrNameMdId = 0x04,
|
|
|
|
kLyricsMdId = 0x05,
|
|
|
|
kMarkerMdId = 0x06,
|
|
|
|
kCuePointMdId = 0x07,
|
|
|
|
kMidiChMdId = 0x20,
|
2021-02-21 13:47:29 +00:00
|
|
|
kMidiPortMdId = 0x21,
|
2019-12-24 15:05:24 +00:00
|
|
|
kEndOfTrkMdId = 0x2f,
|
|
|
|
kTempoMdId = 0x51,
|
|
|
|
kSmpteMdId = 0x54,
|
|
|
|
kTimeSigMdId = 0x58,
|
|
|
|
kKeySigMdId = 0x59,
|
|
|
|
kSeqSpecMdId = 0x7f,
|
|
|
|
kInvalidMetaMdId = 0x80,
|
|
|
|
|
|
|
|
kSustainCtlMdId = 0x40,
|
|
|
|
kPortamentoCtlMdId = 0x41,
|
|
|
|
kSostenutoCtlMdId = 0x42,
|
|
|
|
kSoftPedalCtlMdId = 0x43,
|
|
|
|
kLegatoCtlMdId = 0x44
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//===============================================================================================
|
|
|
|
// Utility Functions
|
|
|
|
//
|
|
|
|
|
|
|
|
template< typename T> bool isStatus( T s ) { return (kNoteOffMdId <= (s) /*&& ((unsigned)(s)) <= kSysRtResetMdId*/ ); }
|
|
|
|
template< typename T> bool isChStatus( T s ) { return (kNoteOffMdId <= (s) && (s) < kSysExMdId); }
|
|
|
|
|
|
|
|
template< typename T> bool isNoteOn( T s ) { return ( kNoteOnMdId <= (s) && (s) <= (kNoteOnMdId + kMidiChCnt) ); }
|
2021-02-21 13:47:29 +00:00
|
|
|
template< typename T> bool isNoteOff( T s, T d1 ) { return ( (isNoteOn(s) && (d1)==0) || (kNoteOffMdId <= (s) && (s) <= (kNoteOffMdId + kMidiChCnt)) ); }
|
2019-12-24 15:05:24 +00:00
|
|
|
template< typename T> bool isCtl( T s ) { return ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) ); }
|
|
|
|
|
|
|
|
template< typename T> bool isSustainPedal( T s, T d0 ) { return ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)== kSustainCtlMdId ); }
|
2021-02-21 13:47:29 +00:00
|
|
|
template< typename T> bool isSustainPedalDown( T s, T d0, T d1) { return ( isSustainPedal(s,d0) && (d1)>=64 ); }
|
|
|
|
template< typename T> bool isSustainPedalUp( T s, T d0, T d1) { return ( isSustainPedal(s,d0) && (d1)<64 ); }
|
2019-12-24 15:05:24 +00:00
|
|
|
|
|
|
|
template< typename T> bool isSostenutoPedal( T s, T d0 ) { return ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)== kSostenutoCtlMdId ); }
|
2021-02-21 13:47:29 +00:00
|
|
|
template< typename T> bool isSostenutoPedalDown( T s, T d0, T d1) { return ( isSostenutoPedal(s,d0) && (d1)>=64 ); }
|
|
|
|
template< typename T> bool isSostenutoPedalUp( T s, T d0, T d1) { return ( isSostenutoPedal(s,d0) && (d1)<64 ); }
|
2019-12-24 15:05:24 +00:00
|
|
|
|
2022-11-11 19:03:51 +00:00
|
|
|
template< typename T> bool isSoftPedal( T s, T d0 ) { return ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)== kSoftPedalCtlMdId ); }
|
|
|
|
template< typename T> bool isSoftPedalDown( T s, T d0, T d1) { return ( isSoftPedal(s,d0) && (d1)>=64 ); }
|
|
|
|
template< typename T> bool isSoftPedalUp( T s, T d0, T d1) { return ( isSoftPedal(s,d0) && (d1)<64 ); }
|
|
|
|
|
2019-12-24 15:05:24 +00:00
|
|
|
template< typename T> bool isPedal( T s, T d0 ) { return ( kCtlMdId <= (s) && (s) <= (kCtlMdId + kMidiChCnt) && (d0)>=kSustainCtlMdId && (d0)<=kLegatoCtlMdId ); }
|
2021-02-21 13:47:29 +00:00
|
|
|
template< typename T> bool isPedalDown( T s, T d0, T d1 ) { return ( isPedal(s,d0) && (d1)>=64 ); }
|
|
|
|
template< typename T> bool isPedalUp( T s, T d0, T d1 ) { return ( isPedal(s,d0) && (d1)<64 ); }
|
2019-12-24 15:05:24 +00:00
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
|
2019-12-24 15:05:24 +00:00
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
const char* statusToLabel( uint8_t status );
|
|
|
|
const char* metaStatusToLabel( uint8_t metaStatus );
|
|
|
|
const char* pedalLabel( uint8_t d0 );
|
2019-12-24 15:05:24 +00:00
|
|
|
|
|
|
|
// Returns kInvalidMidiByte if status is not a valid status byte
|
2020-03-23 14:41:28 +00:00
|
|
|
uint8_t statusToByteCount( uint8_t status );
|
2019-12-24 15:05:24 +00:00
|
|
|
|
2020-03-23 14:41:28 +00:00
|
|
|
unsigned to14Bits( uint8_t d0, uint8_t d1 );
|
|
|
|
void split14Bits( unsigned v, uint8_t& d0Ref, uint8_t& d1Ref );
|
|
|
|
int toPbend( uint8_t d0, uint8_t d1 );
|
|
|
|
void splitPbend( int v, uint8_t& d0Ref, uint8_t& d1Ref );
|
2019-12-24 15:05:24 +00:00
|
|
|
|
|
|
|
//===============================================================================================
|
|
|
|
// MIDI Communication data types
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
// Notes: If the sys-ex message can be contained in a single msg then
|
|
|
|
// then the first msg byte is kSysExMdId and the last is kSysComEoxMdId.
|
|
|
|
// If the sys-ex message is broken into multiple pieces then only the
|
|
|
|
// first will begin with kSysExMdId and the last will end with kSysComEoxMdId.
|
|
|
|
|
|
|
|
|
|
|
|
// If label is NULL or labelCharCnt==0 then a pointer to an internal static
|
|
|
|
// buffer is returned. If label[] is given the it
|
2022-03-20 14:15:28 +00:00
|
|
|
// should have at least 5 (kMidiSciPitchCharCnt) char's (including the terminating zero).
|
2019-12-24 15:05:24 +00:00
|
|
|
// If 'pitch' is outside of the range 0-127 then a blank string is returned.
|
2020-03-23 14:41:28 +00:00
|
|
|
const char* midiToSciPitch( uint8_t pitch, char* label, unsigned labelCharCnt );
|
2019-12-24 15:05:24 +00:00
|
|
|
|
|
|
|
// Convert a scientific pitch to MIDI pitch. acc == 1 == sharp, acc == -1 == flat.
|
|
|
|
// The pitch character must be in the range 'A' to 'G'. Upper or lower case is valid.
|
|
|
|
// Return kInvalidMidiPitch if the arguments are not valid.
|
2020-03-23 14:41:28 +00:00
|
|
|
uint8_t sciPitchToMidiPitch( char pitch, int acc, int octave );
|
2019-12-24 15:05:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Scientific pitch string: [A-Ga-g][#b][#] where # may be -1 to 9.
|
|
|
|
// Return kInvalidMidiPitch if sciPtichStr does not contain a valid
|
|
|
|
// scientific pitch string. This function will convert C-1 to G9 to
|
|
|
|
// valid MIDI pitch values 0 to 127. Scientific pitch strings outside
|
|
|
|
// of this range will be returned as kInvalidMidiPitch.
|
2020-03-23 14:41:28 +00:00
|
|
|
uint8_t sciPitchToMidi( const char* sciPitchStr );
|
2019-12-24 15:05:24 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|