Browse Source

cmXScore.h : Added cmXScoreMergedEditFiles().

master
kevin 3 years ago
parent
commit
033204dd04
2 changed files with 578 additions and 63 deletions
  1. 574
    62
      src/app/cmXScore.c
  2. 4
    1
      src/app/cmXScore.h

+ 574
- 62
src/app/cmXScore.c View File

@@ -110,12 +110,14 @@ typedef struct cmXsNote_str
110 110
   unsigned                    locIdx;   // location index (chords share the same location index)
111 111
   double                      rvalue;   // 1/rvalue = rythmic value (1/0.5 double whole 1/1 whole 1/2 half 1/4=quarter note, 1/8=eighth note, ...)
112 112
   const cmChar_t*             tvalue;   // text value
113
+  const cmChar_t*             editStr;  // merged manual edit string
113 114
 
114 115
   unsigned                    evenGroupId;   // eveness group id
115 116
   unsigned                    dynGroupId;    // dynamics group id
116 117
   unsigned                    tempoGroupId;  // tempo group id
117 118
   unsigned                    graceGroupId;  // grace note group id
118 119
 
120
+
119 121
   struct cmXsVoice_str*       voice;    // voice this note belongs to
120 122
   struct cmXsMeas_str*        meas;     // measure this note belongs to
121 123
 
@@ -230,6 +232,33 @@ cmXsVoice_t* _cmXScoreIdToVoice( cmXsMeas_t* meas, unsigned voiceId )
230 232
   return NULL;
231 233
 }
232 234
 
235
+cmXsMeas_t* _cmXsFindMeas( cmXsPart_t* part, unsigned measNumb )
236
+{
237
+  cmXsMeas_t* m = part->measL;
238
+  for(; m!=NULL; m=m->link)
239
+    if( m->number == measNumb )
240
+      return m;
241
+
242
+  return NULL;
243
+}
244
+
245
+cmXsNote_t* _cmXsFindNote( cmXsMeas_t* m, unsigned idx, unsigned midi, double rval, unsigned durtn, unsigned* idxRef )
246
+{
247
+  unsigned i;
248
+  cmXsNote_t* np = m->noteL;
249
+  for(i=0; np!=NULL; np=np->slink,++i)
250
+  {
251
+    //printf("idx:%i %i midi:%i %i rval:%f %f durtn:%i %i\n", i,idx, np->pitch,midi, np->rvalue,rval, np->tied_dur,durtn);
252
+    if( i>=idx && np->pitch==midi && np->rvalue==rval && np->tied_dur==durtn )
253
+    {
254
+      *idxRef = i;
255
+      return np;
256
+    }
257
+  }
258
+  
259
+  return NULL;  
260
+}
261
+
233 262
 cmXsRC_t _cmXScorePushNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned voiceId, cmXsNote_t* note )
234 263
 {
235 264
   cmXsVoice_t* v;
@@ -612,6 +641,7 @@ cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t*
612 641
   cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1);
613 642
   unsigned    voiceId;
614 643
 
644
+  note->pitch   = kInvalidMidiPitch;
615 645
   note->meas    = meas;
616 646
   note->xmlNode = nnp;
617 647
 
@@ -686,6 +716,7 @@ cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_
686 716
   cmXsNote_t* note    = cmLhAllocZ(p->lhH,cmXsNote_t,1);
687 717
   unsigned    voiceId = 0;    // non-note's are always assigned to voiceId=0;
688 718
 
719
+  note->pitch    = kInvalidMidiPitch;
689 720
   note->tick     = tick;
690 721
   note->staff    = staff;
691 722
   note->flags    = flags;
@@ -798,6 +829,11 @@ cmXsRC_t  _cmXScoreParseDirection(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNo
798 829
 
799 830
       flags = kSectionXsFl;
800 831
     }
832
+    else
833
+    {
834
+      // we only care about 'words' in 'enclosures'
835
+      pushFl = false;
836
+    }
801 837
   }
802 838
   else
803 839
 
@@ -2028,7 +2064,7 @@ cmXsRC_t _cmXScoreProcessDynamicForks( cmXScore_t* p )
2028 2064
 //-------------------------------------------------------------------------------------------
2029 2065
 
2030 2066
 
2031
-typedef struct
2067
+typedef struct _cmXsReorder_str
2032 2068
 {
2033 2069
   unsigned    idx;      // Fields from the reordering input file which are
2034 2070
   unsigned    voice;    // used to match the reorder record to 
@@ -2046,8 +2082,26 @@ typedef struct
2046 2082
   unsigned    graceFlags;   // 0=ignore See kXXXGraceXsFl
2047 2083
   unsigned    graceGroupId; // 0=ignore >0=grace note group id
2048 2084
   unsigned    pitch;        // 0=ignore >0 new pitch
2085
+
2086
+  const char* editStr;
2087
+
2088
+  struct _cmXsReorder_str* link;
2049 2089
 } cmXsReorder_t;
2050 2090
 
2091
+typedef struct _cmXsReorderMeas_str
2092
+{
2093
+  unsigned                     measNumb;
2094
+  cmXsReorder_t*               beg;
2095
+  cmXsReorder_t*               end;
2096
+  struct _cmXsReorderMeas_str* link;
2097
+} cmXsReorderMeas_t;
2098
+
2099
+typedef struct
2100
+{
2101
+  cmXsReorderMeas_t* beg;
2102
+  cmXsReorderMeas_t* end;
2103
+} cmXsReorderFile_t;
2104
+
2051 2105
 typedef struct _cmXScoreDynMark_str
2052 2106
 {
2053 2107
   const cmChar_t* mark;   //
@@ -2088,6 +2142,90 @@ _cmXScoreDynMark_t _cmXScoreDynMarkArray[] =
2088 2142
   
2089 2143
 };
2090 2144
 
2145
+cmXsReorderMeas_t* _cmXsReorderFileAllocMeas( cmXScore_t* p, cmXsReorderFile_t* rfp, unsigned measNumb )
2146
+{
2147
+  cmXsReorderMeas_t* m = cmLhAllocZ(p->lhH,cmXsReorderMeas_t,1);
2148
+  m->measNumb          = measNumb;
2149
+            
2150
+  if( rfp->end == NULL )
2151
+  {
2152
+    rfp->beg = m;
2153
+    rfp->end = m;
2154
+  }
2155
+  else
2156
+  {
2157
+    rfp->end->link = m;
2158
+    rfp->end = m;
2159
+  }
2160
+  return m;
2161
+}
2162
+
2163
+cmXsReorderMeas_t* _cmXsReorderFileFindMeas( cmXsReorderFile_t* rfp, unsigned measNumb )
2164
+{
2165
+  cmXsReorderMeas_t* m = rfp->beg;
2166
+  for(; m!=NULL; m=m->link)
2167
+    if( m->measNumb == measNumb )
2168
+      return m;
2169
+
2170
+  return NULL;
2171
+}
2172
+
2173
+
2174
+cmXsReorder_t* _cmXsReorderMeasAllocEvent( cmXScore_t* p, cmXsReorderMeas_t* m )
2175
+{
2176
+  cmXsReorder_t* r = cmLhAllocZ(p->lhH, cmXsReorder_t,1);
2177
+
2178
+  r->midi = kInvalidMidiPitch;
2179
+  
2180
+  if( m->end == NULL )
2181
+  {
2182
+    m->beg = r;
2183
+    m->end = r;
2184
+  }
2185
+  else
2186
+  {
2187
+    m->end->link = r;
2188
+    m->end = r;
2189
+  }
2190
+
2191
+  return r;
2192
+}
2193
+
2194
+// find key in meas (m) by searching after event idx0.
2195
+cmXsReorder_t* _cmXsReorderFindEvent( cmXsReorderMeas_t* m, unsigned idx0, cmXsReorder_t* key )
2196
+{
2197
+  cmXsReorder_t* r;
2198
+  for(r=m->beg; r!=NULL; r=r->link)
2199
+    if( r->idx >= idx0 && r->midi==key->midi && r->rval==key->rval && r->durtn==key->durtn )
2200
+      return r;
2201
+
2202
+  return NULL;
2203
+}
2204
+
2205
+cmXsReorder_t* _cmXsReorderMeasPop( cmXsReorderMeas_t* m )
2206
+{
2207
+  cmXsReorder_t* r0 = NULL;
2208
+  cmXsReorder_t* r  = NULL;
2209
+  for(r=m->beg; r!=NULL; r=r->link)
2210
+  {
2211
+    if( r == m->end )
2212
+      break;
2213
+    r0 = r;
2214
+  }
2215
+
2216
+  if( r0 == NULL )
2217
+  {
2218
+    m->beg = NULL;
2219
+    m->end = NULL;
2220
+  }
2221
+  else
2222
+  {
2223
+    m->end       = r0;
2224
+    m->end->link = NULL;
2225
+  }
2226
+
2227
+  return r;
2228
+}
2091 2229
 
2092 2230
 cmXsNote_t*  _cmXsReorderFindNote( cmXScore_t* p, unsigned measNumb, const cmXsReorder_t* r, unsigned iii )
2093 2231
 {
@@ -2138,7 +2276,8 @@ void _cmXScoreInsertPedalEvent( cmXScore_t* p, const cmXsReorder_t* r, unsigned
2138 2276
 {
2139 2277
   // Create a new score event record
2140 2278
   cmXsNote_t* nn = cmLhAllocZ(p->lhH,cmXsNote_t,1);
2141
-  
2279
+
2280
+  nn->pitch = kInvalidMidiPitch;
2142 2281
   nn->uid   = p->nextUid++;
2143 2282
   nn->voice = r->note->voice;
2144 2283
   nn->meas  = r->note->meas;
@@ -2165,7 +2304,108 @@ void _cmXScoreInsertPedalEvent( cmXScore_t* p, const cmXsReorder_t* r, unsigned
2165 2304
   
2166 2305
 }
2167 2306
 
2168
-cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t* rV, unsigned rN )
2307
+cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, cmXsReorderMeas_t* m )
2308
+{
2309
+  unsigned i;
2310
+  cmXsReorder_t* r;
2311
+  
2312
+  if( m->beg == NULL )
2313
+    return kOkXsRC;
2314
+
2315
+  // set the 'note' field on each cmXsReorder_t record
2316
+  for(r=m->beg,i=0; r!=NULL; r=r->link,++i)
2317
+    if((r->note = _cmXsReorderFindNote(p,m->measNumb,r,i)) == NULL )
2318
+      return kSyntaxErrorXsRC;
2319
+
2320
+  // remove deleted notes
2321
+  for(r=m->beg; r!=NULL; r=r->link)
2322
+    if( cmIsFlag(r->newFlags,kDeleteXsFl) )
2323
+      if( _cmXScoreRemoveNote( r->note ) != kOkXsRC )
2324
+        return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Event marked to skip was not found in measure: %i",m->measNumb);
2325
+      
2326
+  cmXsMeas_t* mp  = m->beg->note->meas;
2327
+  cmXsNote_t* n0p = NULL;
2328
+
2329
+  assert( mp->number == m->measNumb );
2330
+
2331
+  // Reassign the slink of the cmXsNote_t records in this measure
2332
+  // according to their order in rV[].
2333
+  for(r=m->beg; r!=NULL; r=r->link)
2334
+  {
2335
+    
2336
+    if( cmIsFlag(r->newFlags,kDeleteXsFl) )
2337
+      continue;
2338
+    
2339
+    if( n0p == NULL )
2340
+      mp->noteL = r->note;
2341
+    else
2342
+      n0p->slink = r->note;
2343
+
2344
+    // if a new tick was specified 
2345
+    if( r->newTick != 0 )
2346
+      r->note->tick = r->newTick;
2347
+
2348
+    // if a dynamic or velocity mark was included
2349
+    if( r->dynIdx != cmInvalidIdx )
2350
+    {
2351
+      r->note->dynamics = _cmXScoreDynMarkArray[ r->dynIdx ].dyn;
2352
+      r->note->vel      = _cmXScoreDynMarkArray[ r->dynIdx ].vel;
2353
+    }
2354
+
2355
+    // Set the dynamic fork begin/end flags for later _cmXScoreProcessDynamicForks()
2356
+    if( cmIsFlag(r->newFlags,kDynBegForkXsFl) )
2357
+      r->note->flags = cmSetFlag(r->note->flags,kDynBegForkXsFl); 
2358
+
2359
+    if( cmIsFlag(r->newFlags,kDynEndForkXsFl) )
2360
+      r->note->flags = cmSetFlag(r->note->flags,kDynEndForkXsFl); 
2361
+
2362
+    
2363
+    // if the tie end flag was set
2364
+    if( cmIsFlag(r->newFlags,kTieEndXsFl) )
2365
+    {
2366
+      r->note->flags |= kTieEndXsFl;
2367
+      r->note->flags  = cmClrFlag( r->note->flags, kOnsetXsFl );
2368
+      r->newFlags     = cmClrFlag( r->newFlags,    kTieEndXsFl);
2369
+    }
2370
+
2371
+    // if a new note value was specified
2372
+    if( r->pitch != 0 )
2373
+      r->note->pitch = r->pitch;
2374
+    
2375
+    r->note->flags        |= r->graceFlags;
2376
+    r->note->graceGroupId  = r->graceGroupId;
2377
+
2378
+
2379
+    
2380
+    n0p        = r->note;
2381
+    n0p->slink = NULL;
2382
+  }
2383
+
2384
+  
2385
+  // Insert new note records for pedal up/dn events.
2386
+  for(r=m->beg; r!=NULL; r=r->link)    
2387
+  {
2388
+    if( r->newFlags != 0 )
2389
+    {
2390
+      if( cmIsFlag(r->newFlags,kDampDnXsFl ) )
2391
+        _cmXScoreInsertPedalEvent(p,r,kDampDnXsFl);
2392
+
2393
+      if( cmIsFlag(r->newFlags,kSostDnXsFl ) )
2394
+        _cmXScoreInsertPedalEvent(p,r,kSostDnXsFl);
2395
+      
2396
+      if( cmIsFlag(r->newFlags,kDampUpXsFl ) )
2397
+        _cmXScoreInsertPedalEvent(p,r,kDampUpXsFl);
2398
+
2399
+      if( cmIsFlag(r->newFlags,kSostUpXsFl ) )
2400
+        _cmXScoreInsertPedalEvent(p,r,kSostUpXsFl);      
2401
+    }
2402
+  }
2403
+
2404
+  return kOkXsRC;
2405
+
2406
+}
2407
+
2408
+cmXsRC_t _cmXScoreReorderMeas0( cmXScore_t* p, unsigned measNumb, cmXsReorder_t* rV, unsigned rN )
2169 2409
 {
2170 2410
   unsigned i;
2171 2411
 
@@ -2266,19 +2506,22 @@ cmXsRC_t _cmXScoreReorderMeas( cmXScore_t* p, unsigned measNumb, cmXsReorder_t*
2266 2506
 
2267 2507
 }
2268 2508
 
2269
-cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lineNumb, unsigned* dynIdxRef, unsigned* flagsRef, int measNumb )
2509
+
2510
+cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lineNumb, char** s0, unsigned* dynIdxRef, unsigned* flagsRef, int measNumb )
2270 2511
 {
2271
-  cmXsRC_t        rc        = kOkXsRC;
2272
-  const cmChar_t* s         = NULL;
2273
-  bool            begForkFl = false;
2274
-  bool            endForkFl = false;
2512
+  cmXsRC_t  rc        = kOkXsRC;
2513
+  cmChar_t* s         = NULL;
2514
+  bool      begForkFl = false;
2515
+  bool      endForkFl = false;
2275 2516
     
2276
-
2277 2517
   *dynIdxRef = cmInvalidIdx;
2278 2518
 
2279 2519
   // locate the '!' which indicates the start of a dynamic marking
2280 2520
   if( (s = strchr(b,'!')) == NULL )
2281 2521
     return rc;
2522
+
2523
+  if( *s0==NULL || s<*s0 )    
2524
+    *s0 = s;
2282 2525
   
2283 2526
   ++s; // increment past the '!'
2284 2527
   
@@ -2373,19 +2616,22 @@ cmXsRC_t _cmXScoreReorderParseDyn(cmXScore_t* p, const cmChar_t* b, unsigned lin
2373 2616
 }
2374 2617
 
2375 2618
 
2376
-cmXsRC_t  _cmXScoreReorderParseFlags(cmXScore_t* p, const cmChar_t* b, unsigned line, unsigned* newFlagsRef )
2619
+cmXsRC_t  _cmXScoreReorderParseFlags(cmXScore_t* p, const cmChar_t* b, unsigned line, char** s0, unsigned* newFlagsRef )
2377 2620
 {
2378
-  cmXsRC_t rc = kOkXsRC;
2379
-  const cmChar_t* s;
2380
-  bool doneFl = false;
2381
-  unsigned i = 0;
2382
-  
2621
+  cmXsRC_t  rc     = kOkXsRC;
2622
+  cmChar_t* s;
2623
+  bool      doneFl = false;
2624
+  unsigned  i      = 0;
2625
+
2383 2626
   *newFlagsRef = 0;
2384 2627
   
2385 2628
   // tilde indicates a pedal event
2386 2629
   if((s = strchr(b,'~')) == NULL )
2387 2630
     return rc;
2388 2631
 
2632
+  if( *s0==NULL || s<*s0)
2633
+    *s0 = s;
2634
+  
2389 2635
   do
2390 2636
   {
2391 2637
     ++s;
@@ -2434,14 +2680,17 @@ cmXsRC_t  _cmXScoreReorderParseFlags(cmXScore_t* p, const cmChar_t* b, unsigned
2434 2680
   return rc;
2435 2681
 }
2436 2682
 
2437
-cmXsRC_t  _cmXScoreReorderParseTick(cmXScore_t* p, const cmChar_t* b, unsigned line, unsigned* tickRef )
2683
+cmXsRC_t  _cmXScoreReorderParseTick(cmXScore_t* p, const cmChar_t* b, unsigned line, char** s0, unsigned* tickRef )
2438 2684
 {
2439 2685
   cmXsRC_t rc = kOkXsRC;
2440
-  const cmChar_t* s;
2686
+  cmChar_t* s;
2441 2687
 
2442 2688
   if((s = strchr(b,'@')) == NULL )
2443 2689
     return rc;
2444 2690
 
2691
+  if( *s0 == NULL || s<*s0 )
2692
+    *s0 = s;
2693
+  
2445 2694
   ++s;
2446 2695
 
2447 2696
   if(!isdigit(*s))
@@ -2453,14 +2702,17 @@ cmXsRC_t  _cmXScoreReorderParseTick(cmXScore_t* p, const cmChar_t* b, unsigned l
2453 2702
   return rc;
2454 2703
 }
2455 2704
 
2456
-cmXsRC_t  _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned line, cmXsReorder_t* r, unsigned* graceGroupIdRef )
2705
+cmXsRC_t  _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned line, char** s0, cmXsReorder_t* r, unsigned* graceGroupIdRef )
2457 2706
 {
2458
-  cmXsRC_t        rc = kOkXsRC;
2459
-  const cmChar_t* s;
2707
+  cmXsRC_t  rc = kOkXsRC;
2708
+  cmChar_t* s;
2460 2709
 
2461 2710
   if((s = strchr(b,'%')) == NULL )
2462 2711
     return rc;
2463 2712
 
2713
+  if( *s0==NULL || s<*s0 )
2714
+    *s0 = s;
2715
+  
2464 2716
   ++s;
2465 2717
 
2466 2718
   r->graceGroupId = *graceGroupIdRef;
@@ -2502,12 +2754,12 @@ cmXsRC_t  _cmXScoreReorderParseGrace(cmXScore_t* p, const cmChar_t* b, unsigned
2502 2754
   
2503 2755
 }
2504 2756
 
2505
-cmXsRC_t  _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned line, unsigned* pitchRef )
2757
+cmXsRC_t  _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned line, char** s0, unsigned* pitchRef )
2506 2758
 {
2507
-  cmXsRC_t rc = kOkXsRC;
2759
+  cmXsRC_t  rc = kOkXsRC;
2508 2760
   cmChar_t* s;
2509
-  cmChar_t buf[4];
2510
-  unsigned i,j;
2761
+  cmChar_t  buf[4];
2762
+  unsigned  i,j;
2511 2763
   memset(buf,0,sizeof(buf));
2512 2764
 
2513 2765
   *pitchRef = 0;
@@ -2515,6 +2767,9 @@ cmXsRC_t  _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned
2515 2767
   if((s = strchr(b,'$')) == NULL )
2516 2768
     return rc;
2517 2769
 
2770
+  if( *s0==NULL || s<*s0)
2771
+    *s0 = s;
2772
+  
2518 2773
   ++s;
2519 2774
 
2520 2775
   j=2;
@@ -2546,8 +2801,233 @@ cmXsRC_t  _cmXScoreReorderParsePitch(cmXScore_t* p, const cmChar_t* b, unsigned
2546 2801
   return rc;  
2547 2802
 }
2548 2803
 
2804
+cmXsRC_t _cmXsReadEditFile( cmXScore_t* p, const cmChar_t* fn, unsigned* graceGroupIdPtr, cmXsReorderFile_t* rfp )
2805
+{
2806
+  typedef enum { kFindMeasStId, kFindEventStId, kReadEventStId } stateId_t;
2807
+
2808
+  cmXsRC_t           rc           = kOkXsRC;
2809
+  cmFileH_t          fH           = cmFileNullHandle;
2810
+  cmChar_t*          b            = NULL;
2811
+  unsigned           bN           = 0;
2812
+  unsigned           ln           = 0;
2813
+  stateId_t          stateId      = kFindMeasStId;
2814
+  cmXsReorderMeas_t* curMeas      = NULL;
2815
+  
2816
+  *graceGroupIdPtr = 1;
2817
+  
2818
+  if( cmFileOpen(&fH,fn,kReadFileFl,p->err.rpt) != kOkFileRC )
2819
+  {
2820
+    rc = cmErrMsg(&p->err,kFileFailXsRC,"The reordering file '%s' could not be opened.",cmStringNullGuard(fn));
2821
+    return rc;
2822
+  }
2823
+
2824
+  for(; cmFileGetLineAuto(fH,&b,&bN) == kOkFileRC; ++ln)
2825
+  {
2826
+    switch( stateId )
2827
+    {
2828
+      case kFindEventStId:      // scanning past labels to an event line
2829
+        {
2830
+          unsigned voice,loc;
2831
+          if( sscanf(b,"%i %i",&voice,&loc) != 2 )
2832
+            continue;
2833
+
2834
+          stateId = kReadEventStId;
2835
+        }
2836
+        // fall through
2837
+
2838
+      case kReadEventStId:
2839
+        {
2840
+          cmXsReorder_t* r = _cmXsReorderMeasAllocEvent(p, curMeas );
2841
+          char           pitchStr[4];
2842
+          char*          s0 = NULL;
2843
+
2844
+          // parse an event line
2845
+          if( sscanf(b,"%i %i %i %i %i %f",&r->idx,&r->voice,&r->locIdx,&r->tick,&r->durtn,&r->rval) == 6 )
2846
+          {
2847
+            assert( strlen(b)>=52);
2848
+            int PC = 39; // text file column where first pitch char occurs
2849
+            
2850
+            if( b[PC] == ' ')
2851
+              r->midi = kInvalidMidiPitch;
2852
+            else
2853
+            {
2854
+              pitchStr[0] = b[PC+0];
2855
+              pitchStr[1] = b[PC+1];
2856
+              pitchStr[2] = b[PC+2];              
2857
+              pitchStr[3] = 0;
2858
+              
2859
+              if( !isdigit(pitchStr[2]) )
2860
+                r->midi = kInvalidMidiPitch;
2861
+              else
2862
+              {
2863
+                if( pitchStr[1] == ' ')
2864
+                {
2865
+                  pitchStr[1] = pitchStr[2];
2866
+                  pitchStr[2] = 0;
2867
+                }
2868
+
2869
+                r->midi = cmSciPitchToMidi(pitchStr);
2870
+
2871
+                //printf("%i %i %s %s\n",curMeas->measNumb,r->midi,pitchStr,fn);
2872
+              }
2873
+            }
2874
+            
2875
+            // parse the flag edits following a '~'
2876
+            if((rc = _cmXScoreReorderParseFlags(p,b,ln+1, &s0, &r->newFlags)) != kOkXsRC )
2877
+              goto errLabel;
2878
+
2879
+            // parse the dynamic marking following a '!'
2880
+            if((rc = _cmXScoreReorderParseDyn(p,b,ln+1, &s0, &r->dynIdx, &r->newFlags, curMeas->measNumb)) != kOkXsRC )
2881
+              goto errLabel;
2882
+                        
2883
+            // parse the @newtick marker
2884
+            if((rc = _cmXScoreReorderParseTick(p, b, ln+1, &s0, &r->newTick)) != kOkXsRC )
2885
+              goto errLabel;
2886
+
2887
+            // parse the %grace note marker
2888
+            if((rc = _cmXScoreReorderParseGrace(p, b, ln+1, &s0, r, graceGroupIdPtr)) != kOkXsRC )
2889
+              goto errLabel;
2890
+
2891
+            // parse the $pitch marker
2892
+            if((rc =  _cmXScoreReorderParsePitch(p, b, ln+1, &s0, &r->pitch )) != kOkXsRC )
2893
+              goto errLabel;
2894
+
2895
+            if( s0 != NULL )
2896
+              r->editStr = cmTextTrimEnd(cmLhAllocStrN( p->lhH, s0, strlen(s0)+1 ));
2897
+            
2898
+            continue;
2899
+          }
2900
+
2901
+          // remove the last reorder record because it was not filled
2902
+          _cmXsReorderMeasPop(curMeas);
2903
+          
2904
+          stateId = kFindMeasStId;
2905
+          // fall through
2906
+        }
2907
+
2908
+      case kFindMeasStId:  // scanning for a bar-line
2909
+        {
2910
+          char     colon;
2911
+          unsigned measNumb = 0;
2912
+
2913
+          if( sscanf(b,"%i %c",&measNumb,&colon) == 2 && colon == ':' )
2914
+          {
2915
+            curMeas = _cmXsReorderFileAllocMeas( p, rfp, measNumb );
2916
+            stateId = kFindEventStId;
2917
+          }
2918
+        }
2919
+        break;
2920
+    }
2921
+
2922
+  }
2923
+ errLabel:
2924
+  cmMemFree(b);
2925
+  cmFileClose(&fH);
2926
+  return rc;  
2927
+}
2928
+
2549 2929
 cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
2550 2930
 {
2931
+  cmXsRC_t           rc           = kOkXsRC;
2932
+  unsigned           graceGroupId = 1;
2933
+  cmXsReorderFile_t  rf;
2934
+  cmXsReorderMeas_t* m;
2935
+  memset(&rf,0,sizeof(rf));
2936
+  
2937
+  if((rc = _cmXsReadEditFile( p, fn, &graceGroupId, &rf )) != kOkXsRC )
2938
+    return rc;
2939
+
2940
+  // reorder each measure
2941
+  for(m=rf.beg; m!=NULL; m=m->link)
2942
+    if((rc =  _cmXScoreReorderMeas(p, m)) != kOkXsRC )
2943
+      goto errLabel;
2944
+  
2945
+  // the ticks may have changed so the 'secs' and 'dsecs' must be updated
2946
+  _cmXScoreSetAbsoluteTime( p );
2947
+
2948
+  // the bar lines should be the first event in the measure
2949
+  _cmXScoreFixBarLines(p);
2950
+
2951
+  // resort to force the links to be correct 
2952
+  _cmXScoreSort(p);
2953
+
2954
+  // process the grace notes.
2955
+  _cmXScoreProcessGraceNotes( p, graceGroupId );
2956
+
2957
+  // inserting grace notes may have left the score unsorted
2958
+  _cmXScoreSort(p);
2959
+  
2960
+  // process the dynamic forks
2961
+  _cmXScoreProcessDynamicForks(p);
2962
+
2963
+  //_cmXScoreReport(p, NULL, true );
2964
+
2965
+ errLabel:
2966
+  return rc;
2967
+}
2968
+
2969
+
2970
+
2971
+cmXsRC_t _cmXsMergeEditFiles( cmXScore_t* p, unsigned measNumb0, const cmChar_t* keyEditFn, unsigned keyMeasNumb, const cmChar_t* outFn )
2972
+{
2973
+  cmXsRC_t           rc            = kOkXsRC;
2974
+  unsigned           graceGroup1Id = 1;
2975
+  unsigned           measNumb1     = keyMeasNumb;
2976
+  cmXsReorderFile_t  rf1;
2977
+  memset(&rf1,0,sizeof(rf1));
2978
+
2979
+  if((rc = _cmXsReadEditFile( p, keyEditFn, &graceGroup1Id, &rf1 )) != kOkXsRC )
2980
+    return rc;
2981
+
2982
+  while(1)
2983
+  {
2984
+    cmXsMeas_t*        m0   = _cmXsFindMeas( p->partL, measNumb0 );
2985
+    cmXsReorderMeas_t* m1   = _cmXsReorderFileFindMeas( &rf1, measNumb1 );
2986
+    cmXsReorder_t*     key  = NULL;
2987
+    unsigned           idx0 = 0;
2988
+    
2989
+    if( m1==NULL )
2990
+    {
2991
+      rc = cmErrMsg(&p->err,kEventNotFoundXsRC,"The measure %i was not found in the key edit file '%s'.",keyMeasNumb,cmStringNullGuard(keyEditFn));
2992
+      break;
2993
+    }
2994
+    
2995
+    key  = m1->beg;
2996
+    
2997
+    for(; key!=NULL; key=key->link)
2998
+    {
2999
+      unsigned    idx1 = cmInvalidIdx;
3000
+      cmXsNote_t* np   = _cmXsFindNote( m0, idx0, key->midi, key->rval, key->durtn, &idx1);
3001
+      
3002
+      if( np==NULL )
3003
+      {
3004
+        if( key->editStr != NULL )
3005
+        {
3006
+          const char* sciPitch = key->midi!=kInvalidMidiPitch ? cmMidiToSciPitch(key->midi,NULL,0) : "<non-pitch>";
3007
+          cmErrWarnMsg(&p->err,kEventNotFoundXsRC,"Sync error: meas: ref:%i key:%i index:%i %s (midi:%i) edit:%s did not match to the reference edit file.", measNumb0,m1->measNumb,key->idx, sciPitch, key->midi, key->editStr);
3008
+        }
3009
+      }
3010
+      else
3011
+      {
3012
+        np->editStr = key->editStr;
3013
+        
3014
+        if( key->editStr != NULL )
3015
+          idx0        = idx1;
3016
+      }
3017
+    }
3018
+    
3019
+    ++measNumb0;
3020
+    ++measNumb1;
3021
+
3022
+  }
3023
+  
3024
+  return rc;
3025
+}
3026
+
3027
+
3028
+
3029
+cmXsRC_t _cmXsApplyEditFile0( cmXScore_t* p, const cmChar_t* fn )
3030
+{
2551 3031
   typedef enum { kFindMeasStId, kFindEventStId, kReadEventStId } stateId_t;
2552 3032
 
2553 3033
   cmXsRC_t      rc       = kOkXsRC;
@@ -2586,6 +3066,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
2586 3066
         {
2587 3067
           cmXsReorder_t r;
2588 3068
           char     pitchStr[4];
3069
+          char* s0 = NULL;
2589 3070
 
2590 3071
           memset(&r,0,sizeof(r));
2591 3072
           
@@ -2596,7 +3077,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
2596 3077
             int PC = 39; // text file column where first pitch char occurs
2597 3078
             
2598 3079
             if( b[PC] == ' ')
2599
-              r.midi = 0;
3080
+              r.midi = kInvalidMidiPitch;
2600 3081
             else
2601 3082
             {
2602 3083
               pitchStr[0] = b[PC+0];
@@ -2605,7 +3086,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
2605 3086
               pitchStr[3] = 0;
2606 3087
               
2607 3088
               if( !isdigit(pitchStr[2]) )
2608
-                r.midi = 0;
3089
+                r.midi = kInvalidMidiPitch;
2609 3090
               else
2610 3091
               {
2611 3092
                 if( pitchStr[1] == ' ')
@@ -2621,40 +3102,24 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
2621 3102
 
2622 3103
             
2623 3104
             // parse the flag edits following a '~'
2624
-            if((rc = _cmXScoreReorderParseFlags(p,b,ln+1, &r.newFlags)) != kOkXsRC )
3105
+            if((rc = _cmXScoreReorderParseFlags(p,b,ln+1, &s0, &r.newFlags)) != kOkXsRC )
2625 3106
               goto errLabel;
2626 3107
 
2627 3108
             // parse the dynamic marking following a '!'
2628
-            if((rc = _cmXScoreReorderParseDyn(p,b,ln+1,&r.dynIdx, &r.newFlags, measNumb)) != kOkXsRC )
3109
+            if((rc = _cmXScoreReorderParseDyn(p,b,ln+1,&s0, &r.dynIdx, &r.newFlags, measNumb)) != kOkXsRC )
2629 3110
               goto errLabel;
2630 3111
                         
2631 3112
             // parse the @newtick marker
2632
-            if((rc = _cmXScoreReorderParseTick(p, b, ln+1, &r.newTick)) != kOkXsRC )
3113
+            if((rc = _cmXScoreReorderParseTick(p, b, ln+1, &s0, &r.newTick)) != kOkXsRC )
2633 3114
               goto errLabel;
2634 3115
 
2635 3116
             // parse the %grace note marker
2636
-            if((rc = _cmXScoreReorderParseGrace(p, b, ln+1, &r, &graceGroupId)) != kOkXsRC )
3117
+            if((rc = _cmXScoreReorderParseGrace(p, b, ln+1, &s0, &r, &graceGroupId)) != kOkXsRC )
2637 3118
               goto errLabel;
2638 3119
 
2639 3120
             // parse the $pitch marker
2640
-            if((rc =  _cmXScoreReorderParsePitch(p, b, ln+1, &r.pitch )) != kOkXsRC )
3121
+            if((rc =  _cmXScoreReorderParsePitch(p, b, ln+1, &s0, &r.pitch )) != kOkXsRC )
2641 3122
               goto errLabel;
2642
-
2643
-            // process grace notes - these need to be processed separate from
2644
-            // the _cmXScoreReorderMeas() because grace notes may cross measure boundaries.
2645
-            /*
2646
-            if( r.graceType != 0 )
2647
-            {
2648
-              r.graceGroupId = graceGroupId;
2649
-
2650
-              // if this is an end of a grace note group
2651
-              if( r.graceType != 'g' && r.graceType != 'b' )
2652
-              {
2653
-                graceGroupId += 1;
2654
-              }
2655
-              
2656
-            }
2657
-            */
2658 3123
             
2659 3124
             // store the record
2660 3125
             assert( ri < rN );
@@ -2666,7 +3131,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
2666 3131
 
2667 3132
           // the end of the measure was encountered -
2668 3133
           // reorder the measure based on the cmXsReorder_t in rV[ri]
2669
-          if((rc =  _cmXScoreReorderMeas(p, measNumb, rV, ri )) != kOkXsRC )
3134
+          if((rc =  _cmXScoreReorderMeas0(p, measNumb, rV, ri )) != kOkXsRC )
2670 3135
             goto errLabel;
2671 3136
 
2672 3137
           ri = 0;
@@ -2692,7 +3157,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
2692 3157
 
2693 3158
   // If reorder records remain to be processed
2694 3159
   if( ri > 0 )
2695
-    if((rc =  _cmXScoreReorderMeas(p, measNumb, rV, ri )) != kOkXsRC )
3160
+    if((rc =  _cmXScoreReorderMeas0(p, measNumb, rV, ri )) != kOkXsRC )
2696 3161
       goto errLabel;
2697 3162
     
2698 3163
   
@@ -2724,8 +3189,7 @@ cmXsRC_t _cmXsApplyEditFile( cmXScore_t* p, const cmChar_t* fn )
2724 3189
 }
2725 3190
 
2726 3191
 
2727
-
2728
-cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn, bool damperRptFl )
3192
+cmXsRC_t cmXScoreAlloc( cmCtx_t* ctx, cmXsH_t* hp )
2729 3193
 {
2730 3194
   cmXsRC_t rc = kOkXsRC;
2731 3195
 
@@ -2740,6 +3204,21 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, c
2740 3204
   if( cmLHeapIsValid( p->lhH = cmLHeapCreate(8196,ctx)) == false )
2741 3205
     return cmErrMsg(&p->err,kLHeapFailXsRC,"Lheap create failed.");
2742 3206
 
3207
+  hp->h = p;
3208
+  
3209
+  return rc;
3210
+}
3211
+
3212
+cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, const cmChar_t* editFn, bool damperRptFl )
3213
+{
3214
+  cmXsRC_t rc;
3215
+  cmXScore_t* p = NULL;
3216
+  
3217
+  if((rc = cmXScoreAlloc(ctx,hp)) != kOkXsRC )
3218
+    goto errLabel;
3219
+
3220
+  p  = _cmXScoreHandleToPtr(*hp);
3221
+    
2743 3222
   // open the music xml file
2744 3223
   if( cmXmlAlloc(ctx, &p->xmlH, xmlFn) != kOkXmlRC )
2745 3224
   {
@@ -2798,9 +3277,8 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn, c
2798 3277
   
2799 3278
  errLabel:
2800 3279
   if( rc != kOkXsRC )
2801
-    _cmXScoreFinalize(p);
2802
-  else
2803
-    hp->h = p;
3280
+    cmXScoreFinalize(hp);
3281
+  
2804 3282
 
2805 3283
   return rc;
2806 3284
 }
@@ -3321,6 +3799,9 @@ void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note,unsigned index )
3321 3799
 
3322 3800
   if( note->dynamics != 0)
3323 3801
     cmRptPrintf(rpt," dyn=%i %i",note->dynamics,note->vel);
3802
+
3803
+  if( note->editStr != NULL )
3804
+    cmRptPrintf(rpt, " %s", note->editStr );
3324 3805
   
3325 3806
   /*
3326 3807
   if( cmIsFlag(note->flags,kBegGraceXsFl) )
@@ -3371,6 +3852,7 @@ void  _cmXScoreReport( cmXScore_t* p, cmRpt_t* rpt, bool sortFl )
3371 3852
 
3372 3853
           t1 = note->slink==NULL ? note->tick : note->slink->tick;
3373 3854
 
3855
+          // check that this note is in tick order
3374 3856
           if( !(t0 <= note->tick && note->tick <= t1) )
3375 3857
           {
3376 3858
             cmRptPrintf(rpt," +");
@@ -3427,32 +3909,41 @@ void _cmXScoreGenEditFileWrite( void* arg, const cmChar_t* text )
3427 3909
   }
3428 3910
 }
3429 3911
 
3430
-cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn, bool damperRptFl )
3912
+cmXsRC_t _cmXScoreEditFileRpt( cmCtx_t* ctx, cmXScore_t* p, const cmChar_t* outFn, bool damperRptFl )
3431 3913
 {
3432
-  cmXsH_t   xsH = cmXsNullHandle;
3433
-  cmFileH_t fH  = cmFileNullHandle;
3434 3914
   cmXsRC_t  rc  = kOkXsRC;
3435 3915
   cmErr_t   err;
3436 3916
   cmRpt_t   rpt;
3917
+  cmFileH_t fH  = cmFileNullHandle;
3437 3918
 
3438 3919
   cmErrSetup(&err,&ctx->rpt,"cmXScoreGenEditFile");
3439 3920
   cmRptSetup(&rpt,_cmXScoreGenEditFileWrite,_cmXScoreGenEditFileWrite,&fH);
3440
-
3441
-  if((rc = cmXScoreInitialize(ctx,&xsH,xmlFn,NULL,damperRptFl)) != kOkXsRC )
3442
-    return rc;
3443
-
3921
+  
3444 3922
   if( cmFileOpen(&fH,outFn,kWriteFileFl,&ctx->rpt) != kOkFileRC )
3445 3923
   {
3446 3924
     cmErrMsg(&err,kFileFailXsRC,"Unable to open the output file '%s'.",cmStringNullGuard(outFn));
3447 3925
     goto errLabel;
3448 3926
   }
3449 3927
   
3450
-  cmXScoreReport(xsH,&rpt,true);
3928
+  _cmXScoreReport(p,&rpt,true);
3451 3929
   
3452 3930
  errLabel:
3453 3931
   
3454 3932
   if( cmFileClose(&fH) != kOkFileRC )
3455 3933
     rc = cmErrMsg(&err,kFileFailXsRC,"File close failed on '%s'.",cmStringNullGuard(outFn));
3934
+
3935
+  return rc;
3936
+}
3937
+
3938
+cmXsRC_t cmXScoreGenEditFile( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* outFn, bool damperRptFl )
3939
+{
3940
+  cmXsH_t   xsH = cmXsNullHandle;
3941
+  cmXsRC_t  rc  = kOkXsRC;
3942
+
3943
+  if((rc = cmXScoreInitialize(ctx,&xsH,xmlFn,NULL,damperRptFl)) != kOkXsRC )
3944
+    return rc;
3945
+
3946
+  rc = _cmXScoreEditFileRpt( ctx, _cmXScoreHandleToPtr(xsH), outFn, damperRptFl );
3456 3947
   
3457 3948
   cmXScoreFinalize(&xsH);
3458 3949
 
@@ -4148,3 +4639,24 @@ cmXsRC_t cmXScoreTest(
4148 4639
   return cmXScoreFinalize(&h);
4149 4640
 
4150 4641
 }
4642
+
4643
+
4644
+cmXsRC_t cmXScoreMergeEditFiles( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* refEditFn,  unsigned refBegMeasNumb, const cmChar_t* editFn, unsigned keyMeasNumb, const cmChar_t* outFn )
4645
+{
4646
+  cmXsH_t  h           = cmXsNullHandle;
4647
+  cmXsRC_t rc;
4648
+  bool     damperRptFl = false;
4649
+  
4650
+  if((rc = cmXScoreInitialize(ctx, &h, xmlFn, refEditFn, damperRptFl )) == kOkXsRC )
4651
+  {
4652
+    cmXScore_t* p  = _cmXScoreHandleToPtr(h);
4653
+    
4654
+    if((rc = _cmXsMergeEditFiles(p, refBegMeasNumb, editFn, keyMeasNumb, outFn )) == kOkXsRC )
4655
+      rc = _cmXScoreEditFileRpt( ctx, p, outFn, damperRptFl );
4656
+    
4657
+
4658
+    cmXScoreFinalize(&h);
4659
+  }
4660
+
4661
+  return rc;
4662
+}

+ 4
- 1
src/app/cmXScore.h View File

@@ -20,7 +20,8 @@ extern "C" {
20 20
     kFileFailXsRC,
21 21
     kSvgFailXsRC,
22 22
     kOverlapWarnXsRC,
23
-    kZeroLengthEventXsRC
23
+    kZeroLengthEventXsRC,
24
+    kEventNotFoundXsRC
24 25
   };
25 26
 
26 27
   typedef cmRC_t     cmXsRC_t;
@@ -73,6 +74,8 @@ extern "C" {
73 74
   // Set begMeasNumb to the first measure the to be written to the output csv, MIDI and SVG files.
74 75
   // Set begBPM to 0 to use the tempo from the score otherwise set it to the tempo at begMeasNumb.
75 76
   cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* reorderFn, const cmChar_t* csvOutFn, const cmChar_t* midiOutFn, const cmChar_t* svgOutFn, bool reportFl, int begMeasNumb, int begBPM, bool svgStandAloneFl, bool svgPanZoomFl, bool damperRptFl );
77
+
78
+  cmXsRC_t cmXScoreMergeEditFiles( cmCtx_t* ctx, const cmChar_t* xmlFn, const cmChar_t* refEditFn,  unsigned refBegMeasNumb, const cmChar_t* editFn, unsigned keyMeasNumb, const cmChar_t* outFn );
76 79
   
77 80
 #ifdef __cplusplus
78 81
 }

Loading…
Cancel
Save