cmtools is a collection of utilities for generating and processing machine readable musical scores based on MusicXML, MIDI and other data files.
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmCtx.h"
  6. #include "cmMem.h"
  7. #include "cmMallocDebug.h"
  8. #include "cmLinkedHeap.h"
  9. #include "cmFileSys.h"
  10. #include "cmText.h"
  11. #include "cmPgmOpts.h"
  12. #include "cmXScore.h"
  13. #include "cmMidiScoreFollow.h"
  14. #include "cmScoreProc.h"
  15. #include "cmSymTbl.h"
  16. #include "cmTime.h"
  17. #include "cmMidi.h"
  18. #include "cmScore.h"
  19. #include "cmMidiFile.h"
  20. #include "cmFloatTypes.h"
  21. #include "cmAudioFile.h"
  22. #include "cmTimeLine.h"
  23. enum
  24. {
  25. kOkCtRC = cmOkRC,
  26. kNoActionIdSelectedCtRC,
  27. kMissingRequiredFileNameCtRC,
  28. kScoreGenFailedCtRC,
  29. kScoreFollowFailedCtRC,
  30. kMidiFileRptFailedCtRC,
  31. kTimeLineRptFailedCtRC,
  32. kAudioFileRptFailedCtRC
  33. };
  34. const cmChar_t poEndHelpStr[] = "";
  35. const cmChar_t poBegHelpStr[] =
  36. "xscore_proc Music XML to electronic score generator\n"
  37. "\n"
  38. "USAGE:\n"
  39. "\n"
  40. "Parse an XML score file and decoration file to produce a score file in CSV format.\n"
  41. "\n"
  42. "cmtool --score_gen -x <xml_file> -d <dec_fn> {-c <csvScoreOutFn} {-m <midiOutFn>} {-s <svgOutFn>} {-r report} {-b begMeasNumb} {t begTempoBPM}\n"
  43. "\n"
  44. "Notes:\n"
  45. "1. If <dec_fn> does not exist then a decoration template file will be generated based on the MusicXML file. \n"
  46. "2. Along with the CSV score file MIDI and HTML/SVG files will also be produced based on the contents of the MusicXML and decoration file.\n"
  47. "3. See README.md for a detailed description of the how to edit the decoration file.\n"
  48. "\n"
  49. "\n"
  50. "Use the score follower to generate a timeline configuration file.\n"
  51. "\n"
  52. "cmtool --timeline_gen -c <csvScoreFn> -i <midiInFn> -r <matchRptFn> -s <matchSvgFn> {-m <midiOutFn>} {-t timelineOutFn} \n"
  53. "\n"
  54. "Measure some perforamance attributes:\n"
  55. "\n"
  56. "cmtool --meas_gen -g <pgmRsrcFn> -r <measRptFn>\n"
  57. "\n"
  58. "Generate a score file report\n"
  59. "\n"
  60. "cmtool --score_report -c <csvScoreFn> -r <scoreRptFn>\n"
  61. "\n"
  62. "Generate a MIDI file report and optional SVG piano roll image\n"
  63. "\n"
  64. "cmtool --midi_report -i <midiInFn> -r <midiRptFn> {-s <svgOutFn>}\n"
  65. "\n"
  66. "Generate a timeline report\n"
  67. "\n"
  68. "cmtool --timeline_report -t <timelineFn> -r <timelineRptFn>\n"
  69. "\n"
  70. "Generate an audio file report\n"
  71. "\n"
  72. "cmtool --audiofile_report -a <audioFn> -r <rptFn>\n"
  73. "\n";
  74. void print( void* arg, const char* text )
  75. {
  76. printf("%s",text);
  77. }
  78. bool verify_file_exists( cmCtx_t* ctx, const cmChar_t* fn, const cmChar_t* msg )
  79. {
  80. if( fn == NULL || cmFsIsFile(fn)==false )
  81. return cmErrMsg(&ctx->err,kMissingRequiredFileNameCtRC,"The required file <%s> does not exist.",msg);
  82. return kOkCtRC;
  83. }
  84. bool verify_non_null_filename( cmCtx_t* ctx, const cmChar_t* fn, const cmChar_t* msg )
  85. {
  86. if( fn == NULL )
  87. return cmErrMsg(&ctx->err,kMissingRequiredFileNameCtRC,"The required file name <%s> is blank.",msg);
  88. return kOkCtRC;
  89. }
  90. cmRC_t score_gen( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* decFn, const cmChar_t* csvOutFn, const cmChar_t* midiOutFn, const cmChar_t* svgOutFn, unsigned reportFl, int begMeasNumb, int begTempoBPM, bool svgStandAloneFl, bool svgPanZoomFl, bool damperRptFl )
  91. {
  92. cmRC_t rc;
  93. if((rc = verify_file_exists(ctx,xmlFn,"XML file")) != kOkCtRC )
  94. return rc;
  95. if( cmXScoreTest( ctx, xmlFn, decFn, csvOutFn, midiOutFn, svgOutFn, reportFl, begMeasNumb, begTempoBPM, svgStandAloneFl, svgPanZoomFl, damperRptFl ) != kOkXsRC )
  96. return cmErrMsg(&ctx->err,kScoreGenFailedCtRC,"score_gen failed.");
  97. return kOkCtRC;
  98. }
  99. cmRC_t score_follow( cmCtx_t* ctx, const cmChar_t* csvScoreFn, const cmChar_t* midiInFn, const cmChar_t* matchRptOutFn, const cmChar_t* matchSvgOutFn, const cmChar_t* midiOutFn, const cmChar_t* timelineFn )
  100. {
  101. cmRC_t rc;
  102. if((rc = verify_file_exists(ctx,csvScoreFn,"Score CSV file")) != kOkCtRC )
  103. return rc;
  104. if((rc = verify_file_exists(ctx,midiInFn,"MIDI input file")) != kOkCtRC )
  105. return rc;
  106. //if((rc = verify_file_exists(ctx,matchRptOutFn,"Match report file")) != kOkCtRC )
  107. // return rc;
  108. //if((rc = verify_file_exists(ctx,matchSvgOutFn,"Match HTML/SVG file")) != kOkCtRC )
  109. // return rc;
  110. if(cmMidiScoreFollowMain(ctx, csvScoreFn, midiInFn, matchRptOutFn, matchSvgOutFn, midiOutFn, timelineFn) != kOkMsfRC )
  111. return cmErrMsg(&ctx->err,kScoreFollowFailedCtRC,"score_follow failed.");
  112. return kOkCtRC;
  113. }
  114. cmRC_t meas_gen( cmCtx_t* ctx, const cmChar_t* pgmRsrcFn, const cmChar_t* outFn )
  115. {
  116. cmRC_t rc;
  117. if((rc = verify_file_exists(ctx,pgmRsrcFn,"Program resource file")) != kOkCtRC )
  118. return rc;
  119. if((rc = verify_non_null_filename( ctx,outFn,"Measurements output file.")) != kOkCtRC )
  120. return rc;
  121. return cmScoreProc(ctx, "meas", pgmRsrcFn, outFn );
  122. }
  123. cmRC_t score_report( cmCtx_t* ctx, const cmChar_t* csvScoreFn, const cmChar_t* rptFn )
  124. {
  125. cmRC_t rc;
  126. if((rc = verify_file_exists(ctx,csvScoreFn,"Score CSV file")) != kOkCtRC )
  127. return rc;
  128. cmScoreReport(ctx,csvScoreFn,rptFn);
  129. return rc;
  130. }
  131. cmRC_t midi_file_report( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* rptFn, const cmChar_t* svgFn, bool standAloneFl, bool panZoomFl )
  132. {
  133. cmRC_t rc ;
  134. if((rc = verify_file_exists(ctx,midiFn,"MIDI file")) != kOkCtRC )
  135. return rc;
  136. if((rc = cmMidiFileReport(ctx, midiFn, rptFn )) != kOkMfRC )
  137. return cmErrMsg(&ctx->err,kMidiFileRptFailedCtRC,"MIDI file report generation failed.");
  138. if( svgFn != NULL )
  139. if((rc = cmMidiFileGenSvgFile(ctx, midiFn, svgFn, "midi_file_svg.css", standAloneFl, panZoomFl )) != kOkMfRC )
  140. return cmErrMsg(&ctx->err,kMidiFileRptFailedCtRC,"MIDI file SVG output generation failed.");
  141. return kOkCtRC;
  142. }
  143. cmRC_t timeline_report( cmCtx_t* ctx, const cmChar_t* timelineFn, const cmChar_t* tlPrefixPath, const cmChar_t* rptFn )
  144. {
  145. cmRC_t rc ;
  146. if((rc = verify_file_exists(ctx,timelineFn,"Timeline file")) != kOkCtRC )
  147. return rc;
  148. if((rc = cmTimeLineReport( ctx, timelineFn, tlPrefixPath, rptFn )) != kOkTlRC )
  149. return cmErrMsg(&ctx->err,kTimeLineRptFailedCtRC,"The timeline file report failed.");
  150. return rc;
  151. }
  152. cmRC_t audio_file_report( cmCtx_t* ctx, const cmChar_t* audioFn, const cmChar_t* rptFn )
  153. {
  154. cmRC_t rc;
  155. if((rc = verify_file_exists(ctx,audioFn,"Audio file")) != kOkCtRC )
  156. return rc;
  157. if((rc = cmAudioFileReportInfo( ctx, audioFn, rptFn )) != kOkTlRC )
  158. return cmErrMsg(&ctx->err,kAudioFileRptFailedCtRC,"The audio file report failed.");
  159. return rc;
  160. }
  161. int main( int argc, char* argv[] )
  162. {
  163. cmRC_t rc = cmOkRC;
  164. enum
  165. {
  166. kInvalidPoId = kBasePoId,
  167. kActionPoId,
  168. kXmlFileNamePoId,
  169. kDecorateFileNamePoId,
  170. kCsvOutFileNamePoId,
  171. kPgmRsrcFileNamePoId,
  172. kMidiOutFileNamePoId,
  173. kMidiInFileNamePoId,
  174. kSvgOutFileNamePoId,
  175. kStatusOutFileNamePoId,
  176. kTimelineFileNamePoId,
  177. kTimelinePrefixPoId,
  178. kAudioFileNamePoId,
  179. kReportFlagPoId,
  180. kSvgStandAloneFlPoId,
  181. kSvgPanZoomFlPoId,
  182. kBegMeasPoId,
  183. kBegBpmPoId,
  184. kDamperRptPoId,
  185. kBegMidiUidPoId,
  186. kEndMidiUidPoId
  187. };
  188. enum {
  189. kNoSelId,
  190. kScoreGenSelId,
  191. kScoreFollowSelId,
  192. kMeasGenSelId,
  193. kScoreReportSelId,
  194. kMidiReportSelId,
  195. kTimelineReportSelId,
  196. kAudioReportSelId
  197. };
  198. // initialize the heap check library
  199. bool memDebugFl = 0; //cmDEBUG_FL;
  200. unsigned memGuardByteCnt = memDebugFl ? 8 : 0;
  201. unsigned memAlignByteCnt = 16;
  202. unsigned memFlags = memDebugFl ? kTrackMmFl | kDeferFreeMmFl | kFillUninitMmFl : 0;
  203. cmPgmOptH_t poH = cmPgmOptNullHandle;
  204. const cmChar_t* appTitle = "cmtools";
  205. cmCtx_t ctx;
  206. const cmChar_t* xmlFn = NULL;
  207. const cmChar_t* decFn = NULL;
  208. const cmChar_t* pgmRsrcFn = NULL;
  209. const cmChar_t* csvScoreFn = NULL;
  210. const cmChar_t* midiOutFn = NULL;
  211. const cmChar_t* midiInFn = NULL;
  212. const cmChar_t* audioFn = NULL;
  213. const cmChar_t* svgOutFn = NULL;
  214. const cmChar_t* timelineFn = NULL;
  215. const cmChar_t* timelinePrefix = NULL;
  216. const cmChar_t* rptFn = NULL;
  217. unsigned reportFl = 0;
  218. unsigned svgStandAloneFl = 1;
  219. unsigned svgPanZoomFl = 1;
  220. int begMeasNumb = 0;
  221. int begTempoBPM = 60;
  222. unsigned damperRptFl = 0;
  223. unsigned begMidiUId = cmInvalidId;
  224. unsigned endMidiUId = cmInvalidId;
  225. unsigned actionSelId = kNoSelId;
  226. cmCtxSetup(&ctx,appTitle,print,print,NULL,memGuardByteCnt,memAlignByteCnt,memFlags);
  227. cmMdInitialize( memGuardByteCnt, memAlignByteCnt, memFlags, &ctx.rpt );
  228. cmFsInitialize( &ctx, appTitle);
  229. cmTsInitialize(&ctx );
  230. cmPgmOptInitialize(&ctx, &poH, poBegHelpStr, poEndHelpStr );
  231. cmPgmOptInstallEnum( poH, kActionPoId, 'S', "score_gen", 0, kScoreGenSelId, kNoSelId, &actionSelId, 1,
  232. "Run the score generation tool.","Action selector");
  233. cmPgmOptInstallEnum( poH, kActionPoId, 'F', "score_follow", 0, kScoreFollowSelId, kNoSelId, &actionSelId, 1,
  234. "Run the time line marker generation tool.",NULL);
  235. cmPgmOptInstallEnum( poH, kActionPoId, 'M', "meas_gen", 0, kMeasGenSelId, kNoSelId, &actionSelId, 1,
  236. "Generate perfomance measurements.",NULL);
  237. cmPgmOptInstallEnum( poH, kActionPoId, 'R', "score_report", 0, kScoreReportSelId, kNoSelId, &actionSelId, 1,
  238. "Generate a score file report.",NULL);
  239. cmPgmOptInstallEnum( poH, kActionPoId, 'I', "midi_report", 0, kMidiReportSelId, kNoSelId, &actionSelId, 1,
  240. "Generate a MIDI file report and optional SVG piano roll output.",NULL);
  241. cmPgmOptInstallEnum( poH, kActionPoId, 'E', "timeline_report", 0, kTimelineReportSelId, kNoSelId, &actionSelId, 1,
  242. "Generate a timeline report.",NULL);
  243. cmPgmOptInstallEnum( poH, kActionPoId, 'A', "audio_report", 0, kAudioReportSelId, kNoSelId, &actionSelId, 1,
  244. "Generate an audio file report.",NULL);
  245. cmPgmOptInstallStr( poH, kXmlFileNamePoId, 'x', "muisic_xml_fn",0, NULL, &xmlFn, 1,
  246. "Name of the input MusicXML file.");
  247. cmPgmOptInstallStr( poH, kDecorateFileNamePoId, 'd', "dec_fn", 0, NULL, &decFn, 1,
  248. "Name of a score decoration file.");
  249. cmPgmOptInstallStr( poH, kCsvOutFileNamePoId, 'c', "score_csv_fn",0, NULL, &csvScoreFn, 1,
  250. "Name of a CSV score file.");
  251. cmPgmOptInstallStr( poH, kPgmRsrcFileNamePoId, 'g', "pgm_rsrc_fn", 0, NULL, &pgmRsrcFn, 1,
  252. "Name of program resource file.");
  253. cmPgmOptInstallStr( poH, kMidiOutFileNamePoId, 'm', "midi_out_fn", 0, NULL, &midiOutFn, 1,
  254. "Name of a MIDI file to generate as output.");
  255. cmPgmOptInstallStr( poH, kMidiInFileNamePoId, 'i', "midi_in_fn", 0, NULL, &midiInFn, 1,
  256. "Name of a MIDI file to generate as output.");
  257. cmPgmOptInstallStr( poH, kSvgOutFileNamePoId, 's', "svg_fn", 0, NULL, &svgOutFn, 1,
  258. "Name of a HTML/SVG file to generate as output.");
  259. cmPgmOptInstallStr( poH, kTimelineFileNamePoId, 't', "timeline_fn", 0, NULL, &timelineFn, 1,
  260. "Name of a timeline to generate as output.");
  261. cmPgmOptInstallStr( poH, kTimelinePrefixPoId, 'l', "tl_prefix", 0, NULL, &timelinePrefix,1,
  262. "Timeline data path prefix.");
  263. cmPgmOptInstallStr( poH, kAudioFileNamePoId, 'a', "audio_fn", 0, NULL, &audioFn, 1,
  264. "Audio file name.");
  265. cmPgmOptInstallStr( poH, kStatusOutFileNamePoId,'r', "report_fn", 0, NULL, &rptFn, 1,
  266. "Name of a status file to generate as output.");
  267. cmPgmOptInstallFlag( poH, kReportFlagPoId, 'f', "debug_fl", 0, 1, &reportFl, 1,
  268. "Print a report of the score following processing." );
  269. cmPgmOptInstallInt( poH, kBegMeasPoId, 'b', "beg_meas", 0, 1, &begMeasNumb, 1,
  270. "The first measure the to be written to the output CSV, MIDI and SVG files." );
  271. cmPgmOptInstallInt( poH, kBegBpmPoId, 'e', "beg_bpm", 0, 0, &begTempoBPM, 1,
  272. "Set to 0 to use the tempo from the score otherwise set to use the tempo at begMeasNumb." );
  273. cmPgmOptInstallFlag( poH, kDamperRptPoId, 'u', "damper", 0, 1, &damperRptFl, 1,
  274. "Print the pedal events during 'score_gen' processing.");
  275. cmPgmOptInstallFlag( poH, kSvgStandAloneFlPoId, 'n', "svg_stand_alone_fl",0, 1, &svgStandAloneFl, 1,
  276. "Write the SVG file as a stand alone HTML file. Enabled by default." );
  277. cmPgmOptInstallFlag( poH, kSvgPanZoomFlPoId, 'z', "svg_pan_zoom_fl", 0, 1, &svgPanZoomFl, 1,
  278. "Include the pan-zoom control. Enabled by default." );
  279. cmPgmOptInstallUInt( poH, kBegMidiUidPoId, 'w', "beg_midi_uid", 0, 1, &begMidiUId, 1,
  280. "Begin MIDI msg. uuid." );
  281. cmPgmOptInstallUInt( poH, kEndMidiUidPoId, 'y', "end_midi_uid", 0, 1, &endMidiUId, 1,
  282. "End MIDI msg. uuid." );
  283. // parse the command line arguments
  284. if( cmPgmOptParse(poH, argc, argv ) == kOkPoRC )
  285. {
  286. // handle the built-in arg's (e.g. -v,-p,-h)
  287. // (returns false if only built-in options were selected)
  288. if( cmPgmOptHandleBuiltInActions(poH, &ctx.rpt ) == false )
  289. goto errLabel;
  290. switch( actionSelId )
  291. {
  292. case kScoreGenSelId:
  293. rc = score_gen( &ctx, xmlFn, decFn, csvScoreFn, midiOutFn, svgOutFn, reportFl, begMeasNumb, begTempoBPM, svgStandAloneFl, svgPanZoomFl, damperRptFl );
  294. break;
  295. case kScoreFollowSelId:
  296. rc = score_follow( &ctx, csvScoreFn, midiInFn, rptFn, svgOutFn, midiOutFn, timelineFn );
  297. break;
  298. case kMeasGenSelId:
  299. rc = meas_gen(&ctx, pgmRsrcFn, rptFn);
  300. break;
  301. case kScoreReportSelId:
  302. rc = score_report(&ctx, csvScoreFn, rptFn );
  303. break;
  304. case kMidiReportSelId:
  305. rc = midi_file_report(&ctx, midiInFn, rptFn, svgOutFn, svgStandAloneFl, svgPanZoomFl );
  306. break;
  307. case kTimelineReportSelId:
  308. rc = timeline_report(&ctx, timelineFn, timelinePrefix, rptFn );
  309. break;
  310. case kAudioReportSelId:
  311. rc = audio_file_report(&ctx, audioFn, rptFn );
  312. break;
  313. default:
  314. rc = cmErrMsg(&ctx.err, kNoActionIdSelectedCtRC,"No action selector was selected.");
  315. }
  316. }
  317. errLabel:
  318. cmPgmOptFinalize(&poH);
  319. cmTsFinalize();
  320. cmFsFinalize();
  321. cmMdReport( kIgnoreNormalMmFl );
  322. cmMdFinalize();
  323. return rc;
  324. }