libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #ifndef cmMidiFile_h
  2. #define cmMidiFile_h
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. // MIDI file timing:
  7. // Messages in the MIDI file are time tagged with a delta offset in 'ticks'
  8. // from the previous message in the same track.
  9. //
  10. // A 'tick' can be converted to microsends as follows:
  11. //
  12. // microsecond per tick = micros per quarter note / ticks per quarter note
  13. //
  14. // MpT = MpQN / TpQN
  15. //
  16. // TpQN is given as a constant in the MIDI file header.
  17. // MpQN is given as the value of the MIDI file tempo message.
  18. //
  19. // See cmMidiFileSeekUSecs() for an example of converting ticks to milliseconds.
  20. //
  21. // As part of the file reading process, the status byte of note-on messages
  22. // with velocity=0 are is changed to a note-off message. See _cmMidiFileReadChannelMsg().
  23. typedef cmHandle_t cmMidiFileH_t;
  24. typedef unsigned cmMfRC_t;
  25. typedef struct
  26. {
  27. cmMidiByte_t hr;
  28. cmMidiByte_t min;
  29. cmMidiByte_t sec;
  30. cmMidiByte_t frm;
  31. cmMidiByte_t sfr;
  32. } cmMidiSmpte_t;
  33. typedef struct
  34. {
  35. cmMidiByte_t num;
  36. cmMidiByte_t den;
  37. cmMidiByte_t metro;
  38. cmMidiByte_t th2s;
  39. } cmMidiTimeSig_t;
  40. typedef struct
  41. {
  42. cmMidiByte_t key;
  43. cmMidiByte_t scale;
  44. } cmMidiKeySig_t;
  45. typedef struct
  46. {
  47. cmMidiByte_t ch;
  48. cmMidiByte_t d0;
  49. cmMidiByte_t d1;
  50. unsigned durTicks; // note duration calc'd by cmMidiFileCalcNoteDurations();
  51. } cmMidiChMsg_t;
  52. typedef struct cmMidiTrackMsg_str
  53. {
  54. unsigned uid; // uid's are unique among all msg's in the file
  55. unsigned dtick; // delta ticks
  56. unsigned atick; // accumulated ticks
  57. cmMidiByte_t status; // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
  58. cmMidiByte_t metaId; //
  59. unsigned short trkIdx; //
  60. unsigned byteCnt; // length of data pointed to by u.voidPtr (or any other pointer in the union)
  61. struct cmMidiTrackMsg_str* link; // link to next record in this track
  62. union
  63. {
  64. cmMidiByte_t bVal;
  65. unsigned iVal;
  66. unsigned short sVal;
  67. const char* text;
  68. const void* voidPtr;
  69. const cmMidiSmpte_t* smptePtr;
  70. const cmMidiTimeSig_t* timeSigPtr;
  71. const cmMidiKeySig_t* keySigPtr;
  72. const cmMidiChMsg_t* chMsgPtr;
  73. const cmMidiByte_t* sysExPtr;
  74. } u;
  75. } cmMidiTrackMsg_t;
  76. enum
  77. {
  78. kOkMfRC = cmOkRC, // 0
  79. kFileFailMfRC, // 1
  80. kNotAMidiFileMfRC, // 2
  81. kMemAllocFailMfRC, // 3
  82. kFileCorruptMfRC, // 4
  83. kMissingEoxMfRC, // 5
  84. kUnknownMetaIdMfRC, // 6
  85. kInvalidHandleMfRC, // 7
  86. kMissingNoteOffMfRC, // 8
  87. kInvalidStatusMfRC, // 9
  88. kSustainPedalMfRC // 10
  89. };
  90. extern cmMidiFileH_t cmMidiFileNullHandle;
  91. cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx );
  92. cmMfRC_t cmMidiFileClose( cmMidiFileH_t* hp );
  93. cmMfRC_t cmMidiFileWrite( cmMidiFileH_t h, const char* fn );
  94. bool cmMidiFileIsValid( cmMidiFileH_t h );
  95. // Returns track count or kInvalidCnt if 'h' is invalid.
  96. unsigned cmMidiFileTrackCount( cmMidiFileH_t h );
  97. // Return midi file format id (0,1,2) or kInvalidId if 'h' is invalid.
  98. unsigned cmMidiFileType( cmMidiFileH_t h );
  99. // Returns ticks per quarter note or kInvalidMidiByte if 'h' is invalid or 0 if file uses SMPTE ticks per frame time base.
  100. unsigned cmMidiFileTicksPerQN( cmMidiFileH_t h );
  101. // The file name used in an earlier call to midiFileOpen() or NULL if this
  102. // midi file did not originate from an actual file.
  103. const char* cmMidiFileName( cmMidiFileH_t h );
  104. // Returns SMPTE ticks per frame or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base.
  105. cmMidiByte_t cmMidiFileTicksPerSmpteFrame( cmMidiFileH_t h );
  106. // Returns SMPTE format or kInvalidMidiByte if 'h' is invalid or 0 if file uses ticks per quarter note time base.
  107. cmMidiByte_t cmMidiFileSmpteFormatId( cmMidiFileH_t h );
  108. // Returns count of records in track 'trackIdx' or kInvalidCnt if 'h' is invalid.
  109. unsigned cmMidiFileTrackMsgCount( cmMidiFileH_t h, unsigned trackIdx );
  110. // Returns base of record chain from track 'trackIdx' or NULL if 'h' is invalid.
  111. const cmMidiTrackMsg_t* cmMidiFileTrackMsg( cmMidiFileH_t h, unsigned trackIdx );
  112. // Returns the total count of records in the midi file and the number in the array returned by cmMidiFileMsgArray().
  113. // Return kInvalidCnt if 'h' is invalid.
  114. unsigned cmMidiFileMsgCount( cmMidiFileH_t h );
  115. // Returns a pointer to the base of an array of pointers to each record in the file sorted in ascending time order.
  116. // Returns NULL if 'h' is invalid.
  117. const cmMidiTrackMsg_t** cmMidiFileMsgArray( cmMidiFileH_t h );
  118. // Return a pointer to the first msg at or after 'usecsOffs' or kInvalidIdx if no
  119. // msg exists after 'usecsOffs'. Note that 'usecOffs' is an offset from the beginning
  120. // of the file.
  121. // On return *'msgUsecsPtr' is set to the actual time of the msg.
  122. // (which will be equal to or greater than 'usecsOffs').
  123. unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned usecsOffs, unsigned* msgUsecsPtr, unsigned* newMicrosPerTickPtr );
  124. double cmMidiFileDurSecs( cmMidiFileH_t h );
  125. // Convert the track message 'dtick' field to delta-microseconds.
  126. void cmMidiFileTickToMicros( cmMidiFileH_t h );
  127. // Convert the track message 'dtick' field to samples.
  128. // If the absFl is set then the delta times are converted to absolute time.
  129. void cmMidiFileTickToSamples( cmMidiFileH_t h, double srate, bool absFl );
  130. // Calculate Note Duration
  131. void cmMidiFileCalcNoteDurations( cmMidiFileH_t h );
  132. // Set the delay prior to the first non-zero msg.
  133. void cmMidiFileSetDelay( cmMidiFileH_t h, unsigned ticks );
  134. // This function packs a track msg into a single consecutive
  135. // block of memory buf[ bufByteCnt ]. Call cmMidiFilePackTracMsgBufByteCount()
  136. // to get the required buffer length for any given cmMidiTrackMsg_t instance.
  137. cmMidiTrackMsg_t* cmMidiFilePackTrackMsg( const cmMidiTrackMsg_t* m, void* buf, unsigned bufByteCnt );
  138. unsigned cmMidiFilePackTrackMsgBufByteCount( const cmMidiTrackMsg_t* m );
  139. void cmMidiFilePrint( cmMidiFileH_t h, unsigned trkIdx, cmRpt_t* rpt );
  140. bool cmMidiFileIsNull( cmMidiFileH_t h );
  141. void cmMidiFileTest( const char* fn, cmCtx_t* ctx );
  142. #ifdef __cplusplus
  143. }
  144. #endif
  145. #endif