123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- #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;
-
- struct cmMidiTrackMsg_str;
-
- typedef struct
- {
- cmMidiByte_t ch;
- cmMidiByte_t d0;
- cmMidiByte_t d1;
- unsigned durMicros; // note duration in microseconds (corrected for tempo changes)
- struct cmMidiTrackMsg_str* end; // note-off or pedal-up message
- } 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
- kInvalidTrkIndexMfRC // 15
- };
-
- extern cmMidiFileH_t cmMidiFileNullHandle;
-
- cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* h, const char* fn );
- cmMfRC_t cmMidiFileCreate( cmCtx_t* ctx, cmMidiFileH_t* hp, unsigned trkN, unsigned ticksPerQN );
- 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 all records
- // 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 );
-
- // Insert a MIDI message relative to the reference msg identified by 'uid'.
- // If dtick is positive/negative then the new msg is inserted after/before the reference msg.
- cmMfRC_t cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiByte_t ch, cmMidiByte_t status, cmMidiByte_t d0, cmMidiByte_t d1 );
-
- //
- // Insert a new cmMidiTrackMsg_t into the MIDI file on the specified track.
- //
- // Only the following fields need be set in 'msg'.
- // atick - used to position the msg in the track
- // status - this field is always set (Note that channel information must stripped from the status byte and included in the channel msg data)
- // metaId - this field is optional depending on the msg type
- // byteCnt - used to allocate storage for the data element in 'cmMidiTrackMsg_t.u'
- // u - the message data
- //
- cmMfRC_t cmMidiFileInsertTrackMsg( cmMidiFileH_t h, unsigned trkIdx, const cmMidiTrackMsg_t* msg, unsigned* uidRef );
- cmMfRC_t cmMidiFileInsertTrackChMsg( cmMidiFileH_t h, unsigned trkIdx, unsigned atick, cmMidiByte_t status, cmMidiByte_t d0, cmMidiByte_t d1, unsigned* uidRef );
- cmMfRC_t cmMidFileInsertTrackTempoMsg( cmMidiFileH_t h, unsigned trkIdx, unsigned atick, unsigned bpm, unsigned* uidRef );
-
- // 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 );
- 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
|