Selaa lähdekoodia

cmXScore.h/c : Aded reportFl,begMeasNumb and begBPM to cmXScoreTest().

master
kevin 7 vuotta sitten
vanhempi
commit
e3155ce350
2 muutettua tiedostoa jossa 202 lisäystä ja 87 poistoa
  1. 197
    85
      app/cmXScore.c
  2. 5
    2
      app/cmXScore.h

+ 197
- 85
app/cmXScore.c Näytä tiedosto

@@ -69,7 +69,11 @@ enum
69 69
   kNFirstGraceXsFl = 0x08000000,  // (n) grace notes start as soon as possible after first note and add time
70 70
   kDeleteXsFl      = 0x10000000,
71 71
   kDynBegForkXsFl  = 0x20000000,
72
-  kDynEndForkXsFl  = 0x40000000
72
+  kDynEndForkXsFl  = 0x40000000,
73
+
74
+  kDynEndXsFl   = 0x100000000,
75
+  kEvenEndXsFl  = 0x200000000,
76
+  kTempoEndXsFl = 0x400000000
73 77
   
74 78
 };
75 79
 
@@ -90,7 +94,7 @@ typedef struct cmXsComplexity_str
90 94
 typedef struct cmXsNote_str
91 95
 {
92 96
   unsigned                    uid;      // unique id of this note record
93
-  unsigned                    flags;    // See k???XsFl
97
+  unsigned long long          flags;    // See k???XsFl
94 98
   unsigned                    pitch;    // midi pitch
95 99
   unsigned                    dynamics; // dynamic level 1=pppp 9=fff
96 100
   unsigned                    vel;      // score specified MIDI velocity 
@@ -515,33 +519,44 @@ cmXsRC_t  _cmXScoreParseColor( cmXScore_t* p, const cmXmlNode_t* nnp, cmXsNote_t
515 519
 
516 520
    typedef struct map_str
517 521
   {
518
-    unsigned        value;
522
+    unsigned long long        value;
519 523
     const cmChar_t* label;
520 524
   } map_t;
521 525
 
522 526
   map_t mapV[] =
523 527
   {
524
-    { kEvenXsFl,                         "#0000FF" },  // blue (even)
525
-    { kTempoXsFl,                        "#00FF00" },  // green (tempo)
526
-    { kDynXsFl,                          "#FF0000" },  // red   (dynamics)
527
-    { kTempoXsFl | kEvenXsFl,            "#00FFFF" },  // green + blue (turquoise)
528
-    { kDynXsFl   | kEvenXsFl,            "#FF00FF" },  // red   + blue
529
-    { kDynXsFl   | kEvenXsFl,            "#FF0CF7" },  // magenta (even+dyn)
530
-    { kDynXsFl   | kTempoXsFl,           "#FF7F00" },  // red   + green (brown)
531
-    { kTempoXsFl | kEvenXsFl | kDynXsFl, "#996633" },  // (purple)
532
-    { kDynXsFl,                          "#FF6A03" },  //   176 orange  (dynamics)
533
-    { kEvenXsFl,                         "#2F00E8" },  //  1001 blue (even)
534
-    { kTempoXsFl,                        "#01CD1F" },  //  1196 green   (tempo)
535
-    { kEvenXsFl,                         "#3600E8" },  //  1627 blue (even)
536
-    { kDynXsFl | kTempoXsFl,             "#9E8F15" },  //  8827 brown (dyn + tempo)
537
-    { kEvenXsFl,                         "#2E00E6" },  //  5393 blue (even)
538
-    { kEvenXsFl,                         "#2C00DD" },  //  5895 blue (even)
539
-    { kDynXsFl,                          "#FF5B03" },  //  6498 orange (dyn)
540
-    { kDynXsFl,                          "#FF6104" },  //  6896 orange
541
-    { kEvenXsFl,                         "#2A00E6" },  //  7781 blue
542
-    { kEvenXsFl,                         "#2300DD" },  //  8300 blue (even)
543
-    { kTempoXsFl,                        "#03CD22" },  // 10820 green (tempo)
544
-    { kEvenXsFl,                         "#3400DB" },  // 11627 blue (dyn)
528
+    { kEvenXsFl,                                       "#0000FF" },  // blue (even)
529
+    { kEvenXsFl  | kEvenEndXsFl,                       "#0000FE" },  // blue (even end)
530
+    { kEvenXsFl  | kEvenEndXsFl,                       "#0000FD" },  // blue (even end)
531
+    { kTempoXsFl,                                      "#00FF00" },  // green (tempo)
532
+    { kTempoXsFl | kTempoEndXsFl,                      "#00FE00" },  // green (tempo end)
533
+    { kDynXsFl,                                        "#FF0000" },  // red   (dynamics)
534
+    { kDynXsFl   | kDynEndXsFl,                        "#FE0000" },  // red   (dynamics end)
535
+    { kDynXsFl   | kDynEndXsFl,                        "#FD0000" },  // red   (dynamics end)
536
+    { kTempoXsFl | kEvenXsFl,                          "#00FFFF" },  // green + blue (turquoise)
537
+    { kTempoXsFl | kEvenXsFl | kEvenEndXsFl,           "#00FFFE" },  // green + blue (turquoise) (end)    
538
+    { kDynXsFl   | kEvenXsFl,                          "#FF00FF" },  // red   + blue
539
+    { kDynXsFl   | kEvenXsFl | kEvenEndXsFl,           "#FF00FE" },  // red   + blue (end)
540
+    { kDynXsFl   | kEvenXsFl | kEvenEndXsFl,           "#FF00FD" },  // red   + blue (end)    
541
+    { kDynXsFl   | kEvenXsFl,                          "#FF0CF7" },  // magenta (even+dyn)
542
+    { kDynXsFl   | kTempoXsFl,                         "#FF7F00" },  // red   + green (brown)
543
+    { kDynXsFl   | kTempoXsFl,                         "#FE7F00" },  // red   + green (brown)    (end)
544
+    { kDynXsFl   | kTempoXsFl,                         "#FD7F00" },  // red   + green (brown)    (end)
545
+    { kTempoXsFl | kEvenXsFl | kDynXsFl,               "#996633" },  // (purple)
546
+    { kTempoXsFl | kEvenXsFl | kDynXsFl | kDynEndXsFl, "#996632" },  // (purple)
547
+    { kDynXsFl,                                        "#FF6A03" },  //   176 orange  (dynamics)
548
+    { kEvenXsFl,                                       "#2F00E8" },  //  1001 blue (even)
549
+    { kTempoXsFl,                                      "#01CD1F" },  //  1196 green   (tempo)
550
+    { kEvenXsFl,                                       "#3600E8" },  //  1627 blue (even)
551
+    { kDynXsFl | kTempoXsFl,                           "#9E8F15" },  //  8827 brown (dyn + tempo)
552
+    { kEvenXsFl,                                       "#2E00E6" },  //  5393 blue (even)
553
+    { kEvenXsFl,                                       "#2C00DD" },  //  5895 blue (even)
554
+    { kDynXsFl,                                        "#FF5B03" },  //  6498 orange (dyn)
555
+    { kDynXsFl,                                        "#FF6104" },  //  6896 orange
556
+    { kEvenXsFl,                                       "#2A00E6" },  //  7781 blue
557
+    { kEvenXsFl,                                       "#2300DD" },  //  8300 blue (even)
558
+    { kTempoXsFl,                                      "#03CD22" },  // 10820 green (tempo)
559
+    { kEvenXsFl,                                       "#3400DB" },  // 11627 blue (dyn)
545 560
     { -1, "" }
546 561
   };
547 562
 
@@ -1785,7 +1800,7 @@ cmXsRC_t _cmXScoreProcessGraceNotes( cmXScore_t* p, unsigned nextGraceGroupId )
1785 1800
     // grace note groups must have at least 3 members
1786 1801
     if( gN < 3 )
1787 1802
     {
1788
-      rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"The grace not group (groupid=%i) ending in meas %i has fewer than 3 (%i) members.", gn1p->graceGroupId, gn1p->meas->number, gN );
1803
+      rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"The grace note group (groupid=%i) ending in meas %i has fewer than 3 (%i) members.", gn1p->graceGroupId, gn1p->meas->number, gN );
1789 1804
       break;
1790 1805
     }
1791 1806
     
@@ -2214,7 +2229,7 @@ cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t*
2214 2229
 
2215 2230
 }
2216 2231
 
2217
-cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lineNumb, unsigned* dynIdxRef, unsigned* flagsRef )
2232
+cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lineNumb, unsigned* dynIdxRef, unsigned* flagsRef, int measNumb )
2218 2233
 {
2219 2234
   cmXsRC_t        rc        = kOkXsRC;
2220 2235
   const cmChar_t* s         = NULL;
@@ -2239,6 +2254,7 @@ cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lin
2239 2254
 
2240 2255
   if( *s == '!')
2241 2256
   {
2257
+    //printf("E %3i %5i %s\n",measNumb,lineNumb,b);
2242 2258
     endForkFl = true;
2243 2259
     ++s;      
2244 2260
   }   
@@ -2251,7 +2267,11 @@ cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lin
2251 2267
   if( isupper(*s) )
2252 2268
   {
2253 2269
     if( !endForkFl)
2270
+    {
2254 2271
       begForkFl=true;
2272
+      //printf("B %3i %5i %s\n",measNumb,lineNumb,b);
2273
+      
2274
+    }
2255 2275
   }
2256 2276
   else
2257 2277
   {
@@ -2431,7 +2451,11 @@ cmXsRC_t  _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned
2431 2451
         continue;
2432 2452
         
2433 2453
       default:
2434
-        { assert(0); }
2454
+        {
2455
+          return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Unexpected grace note reorder character code %c on line %i.",*s,line);
2456
+
2457
+          assert(0);
2458
+        }
2435 2459
     }
2436 2460
     
2437 2461
     break;
@@ -2457,7 +2481,7 @@ cmXsRC_t  _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned
2457 2481
   ++s;
2458 2482
 
2459 2483
   j=2;
2460
-  for(i=0; i<j && s[i]; ++i,++s)
2484
+  for(i=0; i<j && *s; ++i,++s)
2461 2485
   {
2462 2486
     buf[i] = *s;
2463 2487
     
@@ -2479,8 +2503,9 @@ cmXsRC_t  _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned
2479 2503
   if( pitch<kInvalidMidiByte)
2480 2504
     *pitchRef = pitch;
2481 2505
   else
2506
+  {
2482 2507
     rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"Pitch conversion from '%s' failed on line %i.",buf,line); 
2483
-
2508
+  }
2484 2509
   return rc;  
2485 2510
 }
2486 2511
 
@@ -2563,7 +2588,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
2563 2588
               goto errLabel;
2564 2589
 
2565 2590
             // parse the dynamic marking following a '!'
2566
-            if((rc = _cmXScoreReorderParseDyn(p,b,ln+1,&r.dynIdx, &r.newFlags)) != kOkXsRC )
2591
+            if((rc = _cmXScoreReorderParseDyn(p,b,ln+1,&r.dynIdx, &r.newFlags, measNumb)) != kOkXsRC )
2567 2592
               goto errLabel;
2568 2593
                         
2569 2594
             // parse the @newtick marker
@@ -3062,12 +3087,13 @@ cmXsRC_t _cmXScoreWriteCsvRow(
3062 3087
   return rc;
3063 3088
 }
3064 3089
 
3065
-cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
3090
+cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, int begMeasNumb, const cmChar_t* csvFn )
3066 3091
 {
3067 3092
   cmXsRC_t        rc           = kOkXsRC;
3068 3093
   cmXScore_t*     p            = _cmXScoreHandleToPtr(h);
3069 3094
   unsigned        rowIdx       = 1;
3070 3095
   const cmChar_t* sectionIdStr = NULL;
3096
+  double          baseSecs     = -1;
3071 3097
 
3072 3098
   if( !cmCsvIsValid(p->csvH) )
3073 3099
     return cmErrMsg(&p->err,kCsvFailXsRC,"The CSV output object is not initialized.");
@@ -3079,12 +3105,22 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
3079 3105
   for(; pp!=NULL; pp=pp->link)
3080 3106
   {
3081 3107
     cmXsMeas_t* mp = pp->measL;
3108
+            
3082 3109
     for(; mp!=NULL; mp=mp->link)
3083 3110
     {
3111
+
3112
+      if( mp->number < begMeasNumb)
3113
+        continue;
3114
+      
3084 3115
       cmXsNote_t* np = mp->noteL;
3116
+
3117
+      if( baseSecs == -1 )
3118
+        baseSecs = np->secs;
3119
+      
3085 3120
       for(; np!=NULL; np=np->slink)
3086 3121
       {
3087
-
3122
+        double thisSecs = np->secs - baseSecs;
3123
+        
3088 3124
         // if this is a section event
3089 3125
         if( cmIsFlag(np->flags,kSectionXsFl) )
3090 3126
           sectionIdStr = np->tvalue;
@@ -3092,7 +3128,7 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
3092 3128
         // if this is a bar event
3093 3129
         if( cmIsFlag(np->flags,kBarXsFl)  )
3094 3130
         {
3095
-          _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"bar",np->dsecs,np->secs,0,0,-1,0,"",np->flags,"","");
3131
+          _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"bar",np->dsecs,thisSecs,0,0,-1,0,"",np->flags,"","");
3096 3132
           sectionIdStr = NULL;
3097 3133
         }
3098 3134
         else
@@ -3102,14 +3138,14 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
3102 3138
           {
3103 3139
             unsigned d0 = cmIsFlag(np->flags,kSostDnXsFl |kSostUpXsFl) ? 66 : 64; // pedal MIDI ctl id
3104 3140
             unsigned d1 = cmIsFlag(np->flags,kDampDnXsFl|kSostDnXsFl) ? 64 : 0;  // pedal-dn: d1>=64 pedal-up:<64
3105
-            _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",np->dsecs,np->secs,d0,d1,-1,0,"",np->flags,"","");
3141
+            _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",np->dsecs,thisSecs,d0,d1,-1,0,"",np->flags,"","");
3106 3142
             sectionIdStr = NULL;
3107 3143
             
3108 3144
             if( cmIsFlag(np->flags,kDampUpDnXsFl) )
3109 3145
             {
3110 3146
               rowIdx += 1;
3111 3147
               double millisecond = 0.0;
3112
-              _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",millisecond,np->secs+millisecond,d0,64,-1,0,"",np->flags,"","");
3148
+              _cmXScoreWriteCsvRow(p,rowIdx,-1,mp->number,sectionIdStr,"ctl",millisecond,thisSecs+millisecond,d0,64,-1,0,"",np->flags,"","");
3113 3149
             }
3114 3150
 
3115 3151
           }
@@ -3123,14 +3159,13 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
3123 3159
               cmChar_t ebuf[ bufN+1]; ebuf[bufN] = 0;
3124 3160
               cmChar_t dbuf[ bufN+1]; dbuf[bufN] = 0;
3125 3161
               cmChar_t tbuf[ bufN+1]; tbuf[bufN] = 0;
3126
-              
3127
-              
3162
+                            
3128 3163
               double          frac  = np->rvalue + (cmIsFlag(np->flags,kDotXsFl) ? (np->rvalue/2) : 0);
3129 3164
               const cmChar_t* dyn   = _cmXScoreTranslateDynamics( p,  np, dbuf, bufN );
3130 3165
               unsigned        vel   = np->vel==0 ? 60 : np->vel;
3131 3166
 
3132
-              //
3133
-              _cmXScoreWriteCsvRow(p,rowIdx,np->uid,mp->number,sectionIdStr,"non",np->dsecs,np->secs,np->pitch,vel,np->pitch,frac,dyn,np->flags,
3167
+              // 
3168
+              _cmXScoreWriteCsvRow(p,rowIdx,np->uid,mp->number,sectionIdStr,"non",np->dsecs,thisSecs,np->pitch,vel,np->pitch,frac,dyn,np->flags,
3134 3169
                 cmXsFormatMeasurementCsvField(np->flags, kEvenXsFl, 'e', np->evenGroupId,  ebuf, bufN ),
3135 3170
                 cmXsFormatMeasurementCsvField(np->flags, kTempoXsFl,'t', np->tempoGroupId, tbuf, bufN ));
3136 3171
               
@@ -3157,6 +3192,30 @@ cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn )
3157 3192
   return rc;
3158 3193
 }
3159 3194
 
3195
+bool  _cmXsIsCsvValid(cmCtx_t* ctx, cmXsH_t h, const cmChar_t* outFn)
3196
+{
3197
+  bool        retFl = true;
3198
+  cmScH_t     scH   = cmScNullHandle;
3199
+  double      srate = 44100.0;
3200
+  cmSymTblH_t stH   = cmSymTblCreate(cmSymTblNullHandle, 0, ctx );
3201
+    
3202
+  if( cmScoreInitialize( ctx, &scH, outFn, srate, NULL, 0, NULL, NULL, stH) != kOkScRC )
3203
+  {
3204
+    cmErrMsg(&ctx->err,kFileFailXsRC,"The generated CSV file (%s) could not be parsed.",cmStringNullGuard(outFn));
3205
+    retFl = false;
3206
+  }
3207
+  else
3208
+  {
3209
+    //cmScorePrintSets(scH,&ctx->rpt);
3210
+    //cmScorePrint(scH,&ctx->rpt);
3211
+      
3212
+    cmScoreFinalize(&scH);
3213
+  }
3214
+
3215
+  cmSymTblDestroy(&stH);
3216
+
3217
+  return retFl;
3218
+}
3160 3219
 
3161 3220
 void _cmXScoreReportTitle( cmRpt_t* rpt )
3162 3221
 {
@@ -3171,9 +3230,6 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
3171 3230
   const cmChar_t* G  = cmIsFlag(note->flags,kGraceXsFl)     ? "G" : "-";
3172 3231
   const cmChar_t* D  = cmIsFlag(note->flags,kDotXsFl)       ? "." : "-";
3173 3232
   const cmChar_t* C  = cmIsFlag(note->flags,kChordXsFl)     ? "C" : "-";
3174
-  const cmChar_t* e  = cmIsFlag(note->flags,kEvenXsFl)      ? "e" : "-";
3175
-  const cmChar_t* d  = cmIsFlag(note->flags,kDynXsFl)       ? "d" : "-";
3176
-  const cmChar_t* t  = cmIsFlag(note->flags,kTempoXsFl)     ? "t" : "-";
3177 3233
   const cmChar_t* P  = cmIsFlag(note->flags,kDampDnXsFl)    ? "V" : "-";
3178 3234
   const cmChar_t* s  = cmIsFlag(note->flags,kSostDnXsFl)    ? "{" : "-";
3179 3235
   const cmChar_t* S  = cmIsFlag(note->flags,kSectionXsFl)   ? "S" : "-";
@@ -3181,6 +3237,15 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
3181 3237
   const cmChar_t* T0 = cmIsFlag(note->flags,kTieBegXsFl)    ? "T" : "-";
3182 3238
   const cmChar_t* T1 = cmIsFlag(note->flags,kTieEndXsFl)    ? "_" : "-";
3183 3239
   const cmChar_t* O  = cmIsFlag(note->flags,kOnsetXsFl)     ? "*" : "-";
3240
+
3241
+  const cmChar_t* e  = cmIsFlag(note->flags,kEvenXsFl)      ? "e" : "-";
3242
+  const cmChar_t* d  = cmIsFlag(note->flags,kDynXsFl)       ? "d" : "-";
3243
+  const cmChar_t* t  = cmIsFlag(note->flags,kTempoXsFl)     ? "t" : "-";
3244
+
3245
+  if( cmIsFlag(note->flags,kEvenEndXsFl) )  e="E";
3246
+  if( cmIsFlag(note->flags,kDynEndXsFl) )   d="D";
3247
+  if( cmIsFlag(note->flags,kTempoEndXsFl) ) t="T";
3248
+  
3184 3249
   P = cmIsFlag(note->flags,kDampUpXsFl)   ? "^" : P;
3185 3250
   P = cmIsFlag(note->flags,kDampUpDnXsFl) ? "X" : P;
3186 3251
   s = cmIsFlag(note->flags,kSostUpXsFl)    ? "}" : s;
@@ -3547,7 +3612,7 @@ cmXsRC_t _cmXsMeasComplexity( cmXsH_t h, double wndSecs )
3547 3612
   return rc;
3548 3613
 }
3549 3614
 
3550
-cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
3615
+cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, int beginMeasNumb, int beginBPM, const cmChar_t* dir, const cmChar_t* fn )
3551 3616
 {
3552 3617
   cmXsRC_t rc = kOkXsRC;
3553 3618
   cmXScore_t* p = _cmXScoreHandleToPtr(h);
@@ -3559,9 +3624,11 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
3559 3624
   unsigned        trkN       = 2;
3560 3625
   unsigned        ticksPerQN = p->partL->measL->divisions;
3561 3626
   const cmChar_t* outFn      = cmFsMakeFn(dir,fn,"mid",NULL);
3627
+  unsigned        baseTick   = -1;
3628
+  unsigned        bpm        = beginBPM==0 ? 60 : beginBPM;
3562 3629
 
3563
-  if( cmMidiFileCreate( ctx, &mfH, trkN, ticksPerQN ) != kOkMfRC )
3564
-    return cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
3630
+  //if( cmMidiFileCreate( ctx, &mfH, trkN, ticksPerQN ) != kOkMfRC )
3631
+  //  return cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
3565 3632
   
3566 3633
   cmXsPart_t* pp = p->partL;
3567 3634
 
@@ -3573,8 +3640,33 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
3573 3640
     // for each measure
3574 3641
     for(; mp!=NULL; mp=mp->link)
3575 3642
     {
3643
+
3644
+      // skip all measures until we reach the first measure to output
3645
+      if(mp->number < beginMeasNumb)
3646
+        continue;
3647
+
3648
+      // if the MIDI file has not yet been created 
3649
+      if( !cmMidiFileIsValid(mfH) )
3650
+      {
3651
+        ticksPerQN = mp->divisions;
3652
+
3653
+        // create the MIDI file
3654
+        if( cmMidiFileCreate( ctx, &mfH, trkN, ticksPerQN ) != kOkMfRC )
3655
+        {
3656
+          rc = cmErrMsg(&p->err,kMidiFailXsRC,"Unable to create the MIDI file object.");
3657
+          goto errLabel;
3658
+        }
3659
+
3660
+        // set the starting tempo
3661
+        cmMidFileInsertTrackTempoMsg(mfH, 0, 0, bpm );
3662
+        
3663
+      }
3664
+      
3576 3665
       cmXsNote_t* np = mp->noteL;
3577 3666
 
3667
+      if( baseTick == -1 )
3668
+        baseTick = np->tick;
3669
+
3578 3670
       if( mp->divisions != ticksPerQN )
3579 3671
         cmErrWarnMsg(&p->err,kMidiFailXsRC,"The 'tick per quarter note' (divisions) field in measure %i does not match the value in the first measure (%i).",mp->divisions,ticksPerQN);
3580 3672
 
@@ -3582,12 +3674,15 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
3582 3674
       // for each note in this measure
3583 3675
       for(; np!=NULL; np=np->slink,++ni)
3584 3676
       {
3677
+        unsigned thisTick = np->tick - baseTick;
3678
+        
3585 3679
         switch( np->flags & (kOnsetXsFl|kMetronomeXsFl|kDampDnXsFl|kDampUpDnXsFl|kSostDnXsFl) )
3586 3680
         {
3587 3681
           case kOnsetXsFl:
3682
+            if( cmMidiFileIsValid(mfH) )
3588 3683
             {
3589 3684
               if( np->tied_dur <= 0 )
3590
-                cmErrWarnMsg(&p->err,kOkXsRC,"A zero length note was encountered bar:%i tick:%i %s",np->meas->number,np->tick,cmMidiToSciPitch(np->pitch,NULL,0));
3685
+                cmErrWarnMsg(&p->err,kOkXsRC,"A zero length note was encountered bar:%i tick:%i (%i) %s",np->meas->number,np->tick,thisTick,cmMidiToSciPitch(np->pitch,NULL,0));
3591 3686
 
3592 3687
               /*
3593 3688
               if( mp->number == 20 )
@@ -3596,9 +3691,12 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
3596 3691
                 cmRptPrintf(ctx->err.rpt,"\n");
3597 3692
               }
3598 3693
               */
3599
-              
3600
-              if( cmMidiFileInsertTrackChMsg(mfH, 1, np->tick,                kNoteOnMdId,  np->pitch, np->vel ) != kOkMfRC
3601
-                ||cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->tied_dur, kNoteOffMdId, np->pitch, 0 )       != kOkMfRC )
3694
+
3695
+              if( np->vel == 0 )
3696
+                cmErrWarnMsg(&p->err,kOkXsRC,"A sounding note with zero velocity was encountered at bar:%i tick:%i pitch:%s.",np->meas->number,np->tick,cmMidiToSciPitch(np->pitch,NULL,0));
3697
+                            
3698
+              if( cmMidiFileInsertTrackChMsg(mfH, 1, thisTick,                kNoteOnMdId,  np->pitch, np->vel ) != kOkMfRC
3699
+                ||cmMidiFileInsertTrackChMsg(mfH, 1, thisTick + np->tied_dur, kNoteOffMdId, np->pitch, 0 )       != kOkMfRC )
3602 3700
               {
3603 3701
                 rc = kMidiFailXsRC;
3604 3702
               }
@@ -3608,13 +3706,14 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
3608 3706
           case kDampDnXsFl:
3609 3707
           case kDampUpDnXsFl:
3610 3708
           case kSostDnXsFl:
3709
+            if( cmMidiFileIsValid(mfH) )
3611 3710
             {
3612 3711
               if( np->duration <= 0 )
3613
-                cmErrWarnMsg(&p->err,kOkXsRC,"A zero length pedal event was encountered bar:%i tick:%i",np->meas->number,np->tick);
3712
+                cmErrWarnMsg(&p->err,kOkXsRC,"A zero length pedal event was encountered bar:%i tick:%i (%i)",np->meas->number,np->tick,thisTick);
3614 3713
               
3615 3714
               cmMidiByte_t d0     = cmIsFlag(np->flags,kSostDnXsFl) ? kSostenutoCtlMdId : kSustainCtlMdId;              
3616
-              if( (cmMidiFileInsertTrackChMsg(mfH, 1, np->tick,                kCtlMdId, d0, 127 ) != kOkMfRC )
3617
-                ||(cmMidiFileInsertTrackChMsg(mfH, 1, np->tick + np->duration, kCtlMdId, d0,   0 ) != kOkMfRC ) )
3715
+              if( (cmMidiFileInsertTrackChMsg(mfH, 1, thisTick,                kCtlMdId, d0, 127 ) != kOkMfRC )
3716
+                ||(cmMidiFileInsertTrackChMsg(mfH, 1, thisTick + np->duration, kCtlMdId, d0,   0 ) != kOkMfRC ) )
3618 3717
               {
3619 3718
                 rc = kMidiFailXsRC;
3620 3719
               }
@@ -3622,8 +3721,10 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
3622 3721
             break;
3623 3722
 
3624 3723
           case kMetronomeXsFl:
3625
-            if( cmMidFileInsertTrackTempoMsg(mfH, 0, np->tick, np->duration ) != kOkMfRC )
3626
-              rc = kMidiFailXsRC;            
3724
+            bpm = np->duration;
3725
+            if( cmMidiFileIsValid(mfH) )
3726
+              if( cmMidFileInsertTrackTempoMsg(mfH, 0, thisTick, bpm ) != kOkMfRC )
3727
+                rc = kMidiFailXsRC;            
3627 3728
             break;
3628 3729
             
3629 3730
           case 0:
@@ -3641,12 +3742,13 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
3641 3742
       }
3642 3743
     }
3643 3744
   }
3644
-  
3645
-  if( cmMidiFileWrite(mfH,outFn) != kOkMfRC )
3646
-  {
3647
-    rc = cmErrMsg(&p->err,kMidiFailXsRC,"MIDI file write failed on '%s'.",cmStringNullGuard(outFn));
3648
-    goto errLabel;
3649
-  }
3745
+
3746
+  if( cmMidiFileIsValid(mfH) )
3747
+    if( cmMidiFileWrite(mfH,outFn) != kOkMfRC )
3748
+    {
3749
+      rc = cmErrMsg(&p->err,kMidiFailXsRC,"MIDI file write failed on '%s'.",cmStringNullGuard(outFn));
3750
+      goto errLabel;
3751
+    }
3650 3752
   
3651 3753
  errLabel:
3652 3754
   cmFsFreeFn(outFn);
@@ -3659,6 +3761,23 @@ cmXsRC_t _cmXsWriteMidiFile( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const
3659 3761
   return rc;
3660 3762
 }
3661 3763
 
3764
+bool _cmXsIsMidiFileValid( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
3765
+{
3766
+  const cmChar_t* midiFn = cmFsMakeFn(dir,fn,"mid",NULL);
3767
+  cmMidiFileH_t mfH = cmMidiFileNullHandle;
3768
+  
3769
+  if( cmMidiFileOpen( ctx, &mfH, midiFn ) == kOkMfRC )
3770
+  {
3771
+    cmMidiFileClose(&mfH);
3772
+    return true;
3773
+  }
3774
+
3775
+  cmXScore_t* p = _cmXScoreHandleToPtr(h);
3776
+  cmErrMsg(&p->err,kMidiFailXsRC,"The generated MIDI file '%s' is not valid.", cmStringNullGuard(midiFn));
3777
+  
3778
+  return false;
3779
+}
3780
+
3662 3781
 typedef struct cmXsSvgEvt_str
3663 3782
 {
3664 3783
   unsigned               flags;    // k???XsFl
@@ -3864,7 +3983,7 @@ void _cmXsPushSvgEvent( cmXScore_t* p, cmXsMidiFile_t* mf, unsigned flags, unsig
3864 3983
   mf->eol = e;
3865 3984
 }
3866 3985
 
3867
-cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cmChar_t* fn )
3986
+cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, int beginMeasNumb, const cmChar_t* dir, const cmChar_t* fn )
3868 3987
 {
3869 3988
   cmXScore_t* p  = _cmXScoreHandleToPtr(h);
3870 3989
   cmXsPart_t* pp = p->partL;
@@ -3877,6 +3996,8 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
3877 3996
     const cmXsMeas_t* meas = pp->measL;
3878 3997
     for(; meas!=NULL; meas=meas->link)
3879 3998
     {
3999
+      if( meas->number < beginMeasNumb )
4000
+        continue;
3880 4001
 
3881 4002
       const cmXsNote_t* note = meas->noteL;
3882 4003
       for(; note!=NULL; note=note->slink)
@@ -3929,11 +4050,14 @@ cmXsRC_t _cmXScoreGenSvg( cmCtx_t* ctx, cmXsH_t h, const cmChar_t* dir, const cm
3929 4050
 
3930 4051
 
3931 4052
 cmXsRC_t cmXScoreTest(
3932
-  cmCtx_t* ctx,
4053
+  cmCtx_t*        ctx,
3933 4054
   const cmChar_t* xmlFn,
3934 4055
   const cmChar_t* editFn,
3935 4056
   const cmChar_t* csvOutFn,
3936
-  const cmChar_t* midiOutFn)
4057
+  const cmChar_t* midiOutFn,
4058
+  bool            reportFl,
4059
+  int             beginMeasNumb,
4060
+  int             beginBPM )
3937 4061
 {
3938 4062
   cmXsRC_t rc;
3939 4063
   cmXsH_t h = cmXsNullHandle;
@@ -3952,45 +4076,33 @@ cmXsRC_t cmXScoreTest(
3952 4076
 
3953 4077
   if( csvOutFn != NULL )
3954 4078
   {
3955
-    cmScH_t scH = cmScNullHandle;
3956
-    double srate = 44100.0;
3957
-    
3958
-    cmXScoreWriteCsv(h,csvOutFn);
3959
-
3960
-    cmSymTblH_t stH = cmSymTblCreate(cmSymTblNullHandle, 0, ctx );
3961 4079
     
3962
-    if( cmScoreInitialize( ctx, &scH, csvOutFn, srate, NULL, 0, NULL, NULL, stH) != kOkScRC )
3963
-      cmErrMsg(&ctx->err,kFileFailXsRC,"The generated CSV file could not be parsed.");
3964
-    else
3965
-    {
3966
-      //cmScorePrintSets(scH,&ctx->rpt);
3967
-      //cmScorePrint(scH,&ctx->rpt);
3968
-      
3969
-      cmScoreFinalize(&scH);
3970
-    }
4080
+    cmXScoreWriteCsv(h,beginMeasNumb,csvOutFn);
3971 4081
 
3972
-    cmSymTblDestroy(&stH); 
4082
+    _cmXsIsCsvValid(ctx,h,csvOutFn);
3973 4083
   }
3974 4084
   
3975 4085
   if( midiOutFn != NULL )
3976 4086
   {
3977
-
3978 4087
     // measure the score complexity
3979 4088
     double wndSecs = 1.0;
4089
+    
3980 4090
     _cmXsMeasComplexity(h,wndSecs);
3981
-
3982 4091
     
3983 4092
     cmFileSysPathPart_t* pp = cmFsPathParts(midiOutFn);
3984 4093
 
3985
-    _cmXsWriteMidiFile(ctx, h, pp->dirStr, pp->fnStr );
4094
+    _cmXsWriteMidiFile(ctx, h, beginMeasNumb, beginBPM, pp->dirStr, pp->fnStr );
4095
+    
4096
+    _cmXsIsMidiFileValid(ctx, h, pp->dirStr, pp->fnStr );
3986 4097
     
3987
-    _cmXScoreGenSvg( ctx, h, pp->dirStr, pp->fnStr );
4098
+    _cmXScoreGenSvg( ctx, h, beginMeasNumb, pp->dirStr, pp->fnStr );
3988 4099
 
3989 4100
     cmFsFreePathParts(pp);
3990 4101
     
3991 4102
   }
3992
-  
3993
-  cmXScoreReport(h,&ctx->rpt,true);
4103
+
4104
+  if(reportFl)
4105
+    cmXScoreReport(h,&ctx->rpt,true);
3994 4106
 
3995 4107
   return cmXScoreFinalize(&h);
3996 4108
 

+ 5
- 2
app/cmXScore.h Näytä tiedosto

@@ -53,7 +53,7 @@ extern "C" {
53 53
   
54 54
   bool     cmXScoreIsValid( cmXsH_t h );
55 55
 
56
-  cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, const cmChar_t* csvFn );
56
+  cmXsRC_t cmXScoreWriteCsv( cmXsH_t h, int beginMeasNumb, const cmChar_t* csvFn );
57 57
 
58 58
   void     cmXScoreReport( cmXsH_t h, cmRpt_t* rpt, bool sortFl );
59 59
 
@@ -69,7 +69,10 @@ extern "C" {
69 69
   // internal call to cmXScoreGenEditFile().  This file can then be edited
70 70
   // to include the additional score file information and passed back by a later
71 71
   // call to this same function.
72
-  cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* reorderFn, const cmChar_t* csvOutFn, const cmChar_t* midiOutFn );
72
+  // Set reportFl to true to print a report of the score following processing.
73
+  // Set begMeasNumb to the first measure the to be written to the output csv, MIDI and SVG files.
74
+  // Set begBPM to 0 to use the tempo from the score otherwise set it to the tempo at begMeasNumb.
75
+  cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* reorderFn, const cmChar_t* csvOutFn, const cmChar_t* midiOutFn, bool reportFl, int begMeasNumb, int begBPM );
73 76
   
74 77
 #ifdef __cplusplus
75 78
 }

Loading…
Peruuta
Tallenna