diff --git a/cmMidi.c b/cmMidi.c index 587797f..4259247 100644 --- a/cmMidi.c +++ b/cmMidi.c @@ -121,6 +121,31 @@ cmMidiByte_t cmMidiStatusToByteCount( cmMidiByte_t status ) return 0; } +unsigned cmMidiTo14Bits( cmMidiByte_t d0, cmMidiByte_t d1 ) +{ + unsigned val = d0; + val <<= 7; + val += d1; + return val; +} + +void cmMidiSplit14Bits( unsigned v, cmMidiByte_t* d0Ref, cmMidiByte_t* d1Ref ) +{ + *d0Ref = (v & 0x3f80) >> 7; + *d1Ref = v & 0x7f; +} + +int cmMidiToPbend( cmMidiByte_t d0, cmMidiByte_t d1 ) +{ + int v = cmMidiTo14Bits(d0,d1); + return v - 8192; +} + +void cmMidiSplitPbend( int v, cmMidiByte_t* d0Ref, cmMidiByte_t* d1Ref ) +{ + unsigned uv = v + 8192; + cmMidiSplit14Bits(uv,d0Ref,d1Ref); +} //==================================================================================================== const char* cmMidiToSciPitch( cmMidiByte_t pitch, char* label, unsigned labelCharCnt ) diff --git a/cmMidi.h b/cmMidi.h index be70d58..c6feafb 100644 --- a/cmMidi.h +++ b/cmMidi.h @@ -5,133 +5,137 @@ extern "C" { #endif -enum -{ - kMidiChCnt = 16, - kInvalidMidiByte = 128, - kMidiNoteCnt = kInvalidMidiByte, - kMidiCtlCnt = kInvalidMidiByte, - kMidiPgmCnt = kInvalidMidiByte, - kInvalidMidiPitch = kInvalidMidiByte, - kInvalidMidiVelocity = kInvalidMidiByte, - kInvalidMidiCtl = kInvalidMidiByte, - kInvalidMidiPgm = kInvalidMidiByte, - kMidiSciPitchCharCnt = 5 // A#-1 -}; + enum + { + kMidiChCnt = 16, + kInvalidMidiByte = 128, + kMidiNoteCnt = kInvalidMidiByte, + kMidiCtlCnt = kInvalidMidiByte, + 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, + // 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, + 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, + 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, - kEndOfTrkMdId = 0x2f, - kTempoMdId = 0x51, - kSmpteMdId = 0x54, - kTimeSigMdId = 0x58, - kKeySigMdId = 0x59, - kSeqSpecMdId = 0x7f, - kInvalidMetaMdId = 0x80, + kSeqNumbMdId = 0x00, + kTextMdId = 0x01, + kCopyMdId = 0x02, + kTrkNameMdId = 0x03, + kInstrNameMdId = 0x04, + kLyricsMdId = 0x05, + kMarkerMdId = 0x06, + kCuePointMdId = 0x07, + kMidiChMdId = 0x20, + kEndOfTrkMdId = 0x2f, + kTempoMdId = 0x51, + kSmpteMdId = 0x54, + kTimeSigMdId = 0x58, + kKeySigMdId = 0x59, + kSeqSpecMdId = 0x7f, + kInvalidMetaMdId = 0x80, - kSustainCtlMdId = 64 + kSustainCtlMdId = 64 -}; + }; -typedef unsigned char cmMidiByte_t; + typedef unsigned char cmMidiByte_t; -//=============================================================================================== -// Utility Functions -// + //=============================================================================================== + // Utility Functions + // #define cmMidiIsStatus( s ) (kNoteOffMdId <= (s) /*&& ((unsigned)(s)) <= kSysRtResetMdId*/ ) #define cmMidiIsChStatus( s ) (kNoteOffMdId <= (s) && (s) < kSysExMdId) -const char* cmMidiStatusToLabel( cmMidiByte_t status ); -const char* cmMidiMetaStatusToLabel( cmMidiByte_t metaStatus ); + const char* cmMidiStatusToLabel( cmMidiByte_t status ); + const char* cmMidiMetaStatusToLabel( cmMidiByte_t metaStatus ); -// Returns kInvalidMidiByte if status is not a valid status byte -cmMidiByte_t cmMidiStatusToByteCount( cmMidiByte_t status ); + // Returns kInvalidMidiByte if status is not a valid status byte + cmMidiByte_t cmMidiStatusToByteCount( cmMidiByte_t status ); + + unsigned cmMidiTo14Bits( cmMidiByte_t d0, cmMidiByte_t d1 ); + void cmMidiSplit14Bits( unsigned v, cmMidiByte_t* d0Ref, cmMidiByte_t* d1Ref ); + int cmMidiToPbend( cmMidiByte_t d0, cmMidiByte_t d1 ); + void cmMidiSplitPbend( int v, cmMidiByte_t* d0Ref, cmMidiByte_t* d1Ref ); + + //=============================================================================================== + // MIDI Communication data types + // + + typedef struct + { + unsigned deltaUs; // time since last MIDI msg in microseconds + cmMidiByte_t status; // midi status byte + cmMidiByte_t d0; // midi data byte 0 + cmMidiByte_t d1; // midi data byte 1 + cmMidiByte_t pad; + } cmMidiMsg; + + typedef struct + { + void* cbDataPtr; // application supplied reference value from mdParserCreate() + unsigned devIdx; // the device the msg originated from + unsigned portIdx; // the port index on the source device + cmMidiMsg* msgArray; // pointer to an array of 'msgCnt' mdMsg records or NULL if sysExMsg is non-NULL + cmMidiByte_t* sysExMsg; // pointer to a sys-ex msg or NULL if msgArray is non-NULL (see note below) + unsigned msgCnt; // count of mdMsg records or sys-ex bytes + } cmMidiPacket_t; + + // 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. -//=============================================================================================== -// MIDI Communication data types -// - -typedef struct -{ - unsigned deltaUs; // time since last MIDI msg in microseconds - cmMidiByte_t status; // midi status byte - cmMidiByte_t d0; // midi data byte 0 - cmMidiByte_t d1; // midi data byte 1 - cmMidiByte_t pad; -} cmMidiMsg; - -typedef struct -{ - void* cbDataPtr; // application supplied reference value from mdParserCreate() - unsigned devIdx; // the device the msg originated from - unsigned portIdx; // the port index on the source device - cmMidiMsg* msgArray; // pointer to an array of 'msgCnt' mdMsg records or NULL if sysExMsg is non-NULL - cmMidiByte_t* sysExMsg; // pointer to a sys-ex msg or NULL if msgArray is non-NULL (see note below) - unsigned msgCnt; // count of mdMsg records or sys-ex bytes -} cmMidiPacket_t; - -// 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 + // should have at least 5 (kMidiPitchCharCnt) char's (including the terminating zero). + // If 'pitch' is outside of the range 0-127 then a blank string is returned. + const char* cmMidiToSciPitch( cmMidiByte_t pitch, char* label, unsigned labelCharCnt ); -// If label is NULL or labelCharCnt==0 then a pointer to an internal static -// buffer is returned. If label[] is given the it -// should have at least 5 (kMidiPitchCharCnt) char's (including the terminating zero). -// If 'pitch' is outside of the range 0-127 then a blank string is returned. -const char* cmMidiToSciPitch( cmMidiByte_t pitch, char* label, unsigned labelCharCnt ); - - -// 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. -cmMidiByte_t cmSciPitchToMidi( const char* sciPitchStr ); + // 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. + cmMidiByte_t cmSciPitchToMidi( const char* sciPitchStr ); #ifdef __cplusplus }