123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- #ifndef cmMidiFile_h
- #define cmMidiFile_h
-
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- //( { file_desc:"MIDI file reader and writer." kw:[midi file]}
- // MIDI file timing:
- // Messages in the MIDI file are time tagged with a delta offset in 'ticks'
- // from the previous message in the same track.
- //
- // A 'tick' can be converted to microsends as follows:
- //
- // microsecond per tick = micros per quarter note / ticks per quarter note
- //
- // MpT = MpQN / TpQN
- //
- // TpQN is given as a constant in the MIDI file header.
- // MpQN is given as the value of the MIDI file tempo message.
- //
- // See cmMidiFileSeekUSecs() for an example of converting ticks to milliseconds.
- //
- // As part of the file reading process, the status byte of note-on messages
- // with velocity=0 are is changed to a note-off message. See _cmMidiFileReadChannelMsg().
- //)
-
- //(
- typedef cmHandle_t cmMidiFileH_t;
- typedef unsigned cmMfRC_t;
-
- typedef struct
- {
- cmMidiByte_t hr;
- cmMidiByte_t min;
- cmMidiByte_t sec;
- cmMidiByte_t frm;
- cmMidiByte_t sfr;
- } cmMidiSmpte_t;
-
- typedef struct
- {
- cmMidiByte_t num;
- cmMidiByte_t den;
- cmMidiByte_t metro;
- cmMidiByte_t th2s;
- } cmMidiTimeSig_t;
-
- typedef struct
- {
- cmMidiByte_t key;
- cmMidiByte_t scale;
- } cmMidiKeySig_t;
-
- typedef struct
- {
- cmMidiByte_t ch;
- cmMidiByte_t d0;
- cmMidiByte_t d1;
- unsigned durMicros; // note duration in microseconds (corrected for tempo changes)
- } cmMidiChMsg_t;
-
-
- typedef struct cmMidiTrackMsg_str
- {
- unsigned uid; // uid's are unique among all msg's in the file
- unsigned dtick; // delta ticks between events on this track
- unsigned long long atick; // global (all tracks interleaved) accumulated ticks
- unsigned long long amicro; // global (all tracks interleaved) accumulated microseconds adjusted for tempo changes
- cmMidiByte_t status; // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
- cmMidiByte_t metaId; //
- unsigned short trkIdx; //
- unsigned byteCnt; // length of data pointed to by u.voidPtr (or any other pointer in the union)
- struct cmMidiTrackMsg_str* link; // link to next record in this track
-
- union
- {
- cmMidiByte_t bVal;
- unsigned iVal;
- unsigned short sVal;
- const char* text;
- const void* voidPtr;
- const cmMidiSmpte_t* smptePtr;
- const cmMidiTimeSig_t* timeSigPtr;
- const cmMidiKeySig_t* keySigPtr;
- const cmMidiChMsg_t* chMsgPtr;
- const cmMidiByte_t* sysExPtr;
- } u;
- } cmMidiTrackMsg_t;
-
- #define cmMidiFileIsNoteOn(m) (cmMidiIsNoteOn((m)->status) && (m)->u.chMsgPtr->d1>0)
- #define cmMidiFileIsNoteOff(m) (cmMidiIsNoteOff((m)->status,(m)->u.chMsgPtr->d1))
-
- #define cmMidiFileIsSustainPedalUp(m) (cmMidiIsSustainPedalUp( (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
- #define cmMidiFileIsSustainPedalDown(m) (cmMidiIsSustainPedalDown( (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
-
- #define cmMidiFileIsSostenutoPedalUp(m) (cmMidiIsSostenutoPedalUp( (m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
- #define cmMidiFileIsSostenutoPedalDown(m) (cmMidiIsSostenutoPedalDown((m)->status,(m)->u.chMsgPtr->d0,(m)->u.chMsgPtr->d1))
-
- enum
- {
- kOkMfRC = cmOkRC, // 0
- kFileFailMfRC, // 1
- kNotAMidiFileMfRC, // 2
- kMemAllocFailMfRC, // 3
- kFileCorruptMfRC, // 4
- kMissingEoxMfRC, // 5
- kUnknownMetaIdMfRC, // 6
- kInvalidHandleMfRC, // 7
- kMissingNoteOffMfRC, // 8
- kInvalidStatusMfRC, // 9
- kSustainPedalMfRC, // 10
- kSostenutoPedalMfRC, // 11
- kLargeDeltaTickMfRC, // 12 (a large delta tick value was filtered)
- kUidNotFoundMfRC, // 13
- kUidNotANoteMsgMfRC // 14
- };
-
- extern cmMidiFileH_t cmMidiFileNullHandle;
-
- cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn );
- cmMfRC_t cmMidiFileClose( cmMidiFileH_t* hp );
-
- cmMfRC_t cmMidiFileWrite( cmMidiFileH_t h, const char* fn );
-
- bool cmMidiFileIsValid( cmMidiFileH_t h );
-
- // Returns track count or kInvalidCnt if 'h' is invalid.
- unsigned cmMidiFileTrackCount( cmMidiFileH_t h );
-
- // Return midi file format id (0,1,2) or kInvalidId if 'h' is invalid.
- unsigned cmMidiFileType( cmMidiFileH_t h );
-
- // Returns ticks per quarter note or kInvalidMidiByte if 'h' is invalid or 0 if file uses SMPTE ticks per frame time base.
- unsigned cmMidiFileTicksPerQN( cmMidiFileH_t h );
-
- // The file name used in an earlier call to midiFileOpen() or NULL if this
- // midi file did not originate from an actual file.
- const char* cmMidiFileName( cmMidiFileH_t h );
-
- // Returns SMPTE ticks per frame or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base.
- cmMidiByte_t cmMidiFileTicksPerSmpteFrame( cmMidiFileH_t h );
-
- // Returns SMPTE format or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base.
- cmMidiByte_t cmMidiFileSmpteFormatId( cmMidiFileH_t h );
-
- // Returns count of records in track 'trackIdx' or kInvalidCnt if 'h' is invalid.
- unsigned cmMidiFileTrackMsgCount( cmMidiFileH_t h, unsigned trackIdx );
-
- // Returns base of record chain from track 'trackIdx' or NULL if 'h' is invalid.
- const cmMidiTrackMsg_t* cmMidiFileTrackMsg( cmMidiFileH_t h, unsigned trackIdx );
-
- // Returns the total count of records in the midi file and the number in the array returned by cmMidiFileMsgArray().
- // Return kInvalidCnt if 'h' is invalid.
- unsigned cmMidiFileMsgCount( cmMidiFileH_t h );
-
- // Returns a pointer to the base of an array of pointers to each record in the file sorted in ascending time order.
- // Returns NULL if 'h' is invalid.
- const cmMidiTrackMsg_t** cmMidiFileMsgArray( cmMidiFileH_t h );
-
- // Set the velocity of a note-on/off msg identified by 'uid'.
- cmMfRC_t cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel );
-
- // Return a pointer to the first msg at or after 'usecsOffs' or kInvalidIdx if no
- // msg exists after 'usecsOffs'. Note that 'usecOffs' is an offset from the beginning
- // of the file.
- // On return *'msgUsecsPtr' is set to the actual time of the msg.
- // (which will be equal to or greater than 'usecsOffs').
- unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned long long usecsOffs, unsigned* msgUsecsPtr, unsigned* newMicrosPerTickPtr );
-
- double cmMidiFileDurSecs( cmMidiFileH_t h );
-
- // Calculate Note Duration
- void cmMidiFileCalcNoteDurations( cmMidiFileH_t h );
-
- // Set the delay prior to the first non-zero msg.
- void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks );
-
- // This function packs a track msg into a single consecutive
- // block of memory buf[ bufByteCnt ]. Call cmMidiFilePackTracMsgBufByteCount()
- // to get the required buffer length for any given cmMidiTrackMsg_t instance.
- cmMidiTrackMsg_t* cmMidiFilePackTrackMsg( const cmMidiTrackMsg_t* m, void* buf, unsigned bufByteCnt );
- unsigned cmMidiFilePackTrackMsgBufByteCount( const cmMidiTrackMsg_t* m );
-
- void cmMidiFilePrintMsgs( cmMidiFileH_t h, cmRpt_t* rpt );
- void cmMidiFilePrintTrack( cmMidiFileH_t h, unsigned trkIdx, cmRpt_t* rpt );
- bool cmMidiFileIsNull( cmMidiFileH_t h );
- void cmMidiFileTest( const char* fn, cmCtx_t* ctx );
-
- // Generate a piano-roll plot description file which can be displayed with cmXScore.m
- cmMfRC_t cmMidiFileGenPlotFile( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* outFn );
-
-
- //)
-
- #ifdef __cplusplus
- }
- #endif
-
- #endif
|