libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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