libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

cmMidi.c 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmTime.h"
  4. #include "cmMidi.h"
  5. enum
  6. {
  7. mdStatusDescLabelCharCnt = 5
  8. };
  9. typedef struct
  10. {
  11. cmMidiByte_t status;
  12. cmMidiByte_t byteCnt;
  13. char label[ mdStatusDescLabelCharCnt+1 ];
  14. } cmMidiStatusDesc;
  15. cmMidiStatusDesc _cmMidiStatusDescArray[] =
  16. {
  17. // channel messages
  18. { kNoteOffMdId, 2, "nof" },
  19. { kNoteOnMdId, 2, "non" },
  20. { kPolyPresMdId,2, "ppr" },
  21. { kCtlMdId, 2, "ctl" },
  22. { kPgmMdId, 1, "pgm" },
  23. { kChPresMdId, 1, "cpr" },
  24. { kPbendMdId, 2, "pb" },
  25. { kSysExMdId, kInvalidMidiByte,"sex" },
  26. // system common
  27. { kSysComMtcMdId, 1, "mtc" },
  28. { kSysComSppMdId, 2, "spp" },
  29. { kSysComSelMdId, 1, "sel" },
  30. { kSysComUndef0MdId, 0, "cu0" },
  31. { kSysComUndef1MdId, 0, "cu1" },
  32. { kSysComTuneMdId, 0, "tun" },
  33. { kSysComEoxMdId, 0, "eox" },
  34. // system real-time
  35. { kSysRtClockMdId, 0, "clk" },
  36. { kSysRtUndef0MdId,0, "ud0" },
  37. { kSysRtStartMdId, 0, "beg" },
  38. { kSysRtContMdId, 0, "cnt" },
  39. { kSysRtStopMdId, 0, "end" },
  40. { kSysRtUndef1MdId,0, "ud1" },
  41. { kSysRtSenseMdId, 0, "sns" },
  42. { kSysRtResetMdId, 0, "rst" },
  43. { kInvalidStatusMdId, kInvalidMidiByte, "ERR" }
  44. };
  45. cmMidiStatusDesc _cmMidiMetaStatusDescArray[] =
  46. {
  47. { kSeqNumbMdId, 2, "seqn" },
  48. { kTextMdId, -1, "text" },
  49. { kCopyMdId, -1, "copy" },
  50. { kTrkNameMdId, -1, "name" },
  51. { kInstrNameMdId, -1, "instr" },
  52. { kLyricsMdId, -1, "lyric" },
  53. { kMarkerMdId, -1, "mark" },
  54. { kCuePointMdId, -1, "cue" },
  55. { kMidiChMdId, 1, "chan" },
  56. { kEndOfTrkMdId, 0, "eot" },
  57. { kTempoMdId, 3, "tempo" },
  58. { kSmpteMdId, 5, "smpte" },
  59. { kTimeSigMdId, 4, "tsig" },
  60. { kKeySigMdId, 2, "ksig" },
  61. { kSeqSpecMdId, -1, "seqs" },
  62. { kInvalidMetaMdId, kInvalidMidiByte, "ERROR"}
  63. };
  64. //====================================================================================================
  65. const char* cmMidiStatusToLabel( cmMidiByte_t status )
  66. {
  67. unsigned i;
  68. if( !cmMidiIsStatus(status) )
  69. return NULL;
  70. // remove the channel value from ch msg status bytes
  71. if( cmMidiIsChStatus(status) )
  72. status &= 0xf0;
  73. for(i=0; _cmMidiStatusDescArray[i].status != kInvalidStatusMdId; ++i)
  74. if( _cmMidiStatusDescArray[i].status == status )
  75. return _cmMidiStatusDescArray[i].label;
  76. return _cmMidiStatusDescArray[i].label;
  77. }
  78. const char* cmMidiMetaStatusToLabel( cmMidiByte_t metaStatus )
  79. {
  80. int i;
  81. for(i=0; _cmMidiMetaStatusDescArray[i].status != kInvalidMetaMdId; ++i)
  82. if( _cmMidiMetaStatusDescArray[i].status == metaStatus )
  83. break;
  84. return _cmMidiMetaStatusDescArray[i].label;
  85. }
  86. cmMidiByte_t cmMidiStatusToByteCount( cmMidiByte_t status )
  87. {
  88. unsigned i;
  89. if( !cmMidiIsStatus(status) )
  90. return kInvalidMidiByte;
  91. // remove the channel value from ch msg status bytes
  92. if( cmMidiIsChStatus(status) )
  93. status &= 0xf0;
  94. for(i=0; _cmMidiStatusDescArray[i].status != kInvalidStatusMdId; ++i)
  95. if( _cmMidiStatusDescArray[i].status == status )
  96. return _cmMidiStatusDescArray[i].byteCnt;
  97. assert(0);
  98. return 0;
  99. }
  100. unsigned cmMidiTo14Bits( cmMidiByte_t d0, cmMidiByte_t d1 )
  101. {
  102. unsigned val = d0;
  103. val <<= 7;
  104. val += d1;
  105. return val;
  106. }
  107. void cmMidiSplit14Bits( unsigned v, cmMidiByte_t* d0Ref, cmMidiByte_t* d1Ref )
  108. {
  109. *d0Ref = (v & 0x3f80) >> 7;
  110. *d1Ref = v & 0x7f;
  111. }
  112. int cmMidiToPbend( cmMidiByte_t d0, cmMidiByte_t d1 )
  113. {
  114. int v = cmMidiTo14Bits(d0,d1);
  115. return v - 8192;
  116. }
  117. void cmMidiSplitPbend( int v, cmMidiByte_t* d0Ref, cmMidiByte_t* d1Ref )
  118. {
  119. unsigned uv = v + 8192;
  120. cmMidiSplit14Bits(uv,d0Ref,d1Ref);
  121. }
  122. //====================================================================================================
  123. const char* cmMidiToSciPitch( cmMidiByte_t pitch, char* label, unsigned labelCharCnt )
  124. {
  125. static char buf[ kMidiSciPitchCharCnt ];
  126. if( label == NULL || labelCharCnt == 0 )
  127. {
  128. label = buf;
  129. labelCharCnt = kMidiSciPitchCharCnt;
  130. }
  131. assert( labelCharCnt >= kMidiSciPitchCharCnt );
  132. if( /*pitch < 0 ||*/ pitch > 127 )
  133. {
  134. label[0] = 0;
  135. return label;
  136. }
  137. assert( labelCharCnt >= 5 && /*pitch >= 0 &&*/ pitch <= 127 );
  138. char noteV[] = { 'C', 'C', 'D', 'D', 'E', 'F', 'F', 'G', 'G', 'A', 'A', 'B' };
  139. char shrpV[] = { ' ', '#', ' ', '#', ' ', ' ', '#', ' ', '#', ' ', '#', ' ' };
  140. int octave = (pitch / 12)-1;
  141. unsigned noteIdx = pitch % 12;
  142. char noteCh = noteV[ noteIdx ];
  143. char sharpCh = shrpV[ noteIdx ];
  144. unsigned idx = 1;
  145. label[labelCharCnt-1] = 0;
  146. label[0] = noteCh;
  147. if( sharpCh != ' ' )
  148. {
  149. label[1] = sharpCh;
  150. idx = 2;
  151. }
  152. assert( -1 <= octave && octave <= 9);
  153. snprintf(label+idx,kMidiSciPitchCharCnt-idx-1,"%i",octave);
  154. return label;
  155. }
  156. cmMidiByte_t cmSciPitchToMidi( const char* sciPitchStr )
  157. {
  158. const char* cp = sciPitchStr;
  159. bool sharpFl = false;
  160. bool flatFl = false;
  161. int octave;
  162. int idx = -1;
  163. if( sciPitchStr==NULL || strlen(sciPitchStr) > 5 )
  164. return kInvalidMidiPitch;
  165. switch(tolower(*cp))
  166. {
  167. case 'a': idx = 9; break;
  168. case 'b': idx = 11; break;
  169. case 'c': idx = 0; break;
  170. case 'd': idx = 2; break;
  171. case 'e': idx = 4; break;
  172. case 'f': idx = 5; break;
  173. case 'g': idx = 7; break;
  174. default:
  175. return kInvalidMidiPitch;
  176. }
  177. ++cp;
  178. if( !(*cp) )
  179. return kInvalidMidiPitch;
  180. if((sharpFl = *cp=='#') == true )
  181. ++idx;
  182. else
  183. if((flatFl = *cp=='b') == true )
  184. --idx;
  185. if( sharpFl || flatFl )
  186. {
  187. ++cp;
  188. if( !(*cp) )
  189. return kInvalidMidiPitch;
  190. }
  191. if( isdigit(*cp) == false && *cp!='-' )
  192. return kInvalidMidiPitch;
  193. octave = atoi(cp);
  194. unsigned rv = (octave*12) + idx + 12;
  195. if( 0 <= rv && rv <= 127 )
  196. return rv;
  197. return kInvalidMidiPitch;
  198. }