Selaa lähdekoodia

cmXScore.h/c : Began tie processing.

master
kevin 8 vuotta sitten
vanhempi
commit
5c27c2455f
2 muutettua tiedostoa jossa 227 lisäystä ja 23 poistoa
  1. 218
    19
      app/cmXScore.c
  2. 9
    4
      app/cmXScore.h

+ 218
- 19
app/cmXScore.c Näytä tiedosto

@@ -29,12 +29,16 @@ enum
29 29
   kEvenXsFl      = 0x0080,
30 30
   kTempoXsFl     = 0x0100,
31 31
   kHeelXsFl      = 0x0200,
32
-  kPedalDnXsFl   = 0x0400,
33
-  kPedalUpXsFl   = 0x0800,
34
-  kPedalUpDnXsFl = 0x1000,
35
-  kMetronomeXsFl = 0x2000  // duration holds BPM 
32
+  kTieBegXsFl    = 0x0400,
33
+  kTieEndXsFl    = 0x0800,
34
+  kPedalDnXsFl   = 0x1000,
35
+  kPedalUpXsFl   = 0x2000,
36
+  kPedalUpDnXsFl = 0x4000,
37
+  kMetronomeXsFl = 0x8000  // duration holds BPM
36 38
 };
37 39
 
40
+struct cmXsMeas_str;
41
+struct cmXsVoice_str;
38 42
 
39 43
 typedef struct cmXsNote_str
40 44
 {
@@ -42,12 +46,28 @@ typedef struct cmXsNote_str
42 46
   unsigned             pitch;    // midi pitch
43 47
   unsigned             tick;     // 
44 48
   unsigned             duration; // duration in ticks
49
+  unsigned             pticks;   // play ticks (0 for non-sounding notes)
45 50
   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, ...)
46 51
   const cmChar_t*      tvalue;   // text value
52
+
53
+  const struct cmXsVoice_str* voice;    // voice this note belongs to 
54
+  const struct cmXsMeas_str*  meas;     // measure this note belongs to
55
+  const cmXmlNode_t*   xmlNode;  // note xml ptr
56
+
47 57
   struct cmXsNote_str* mlink;    // measure note list 
48 58
   struct cmXsNote_str* slink;    // time sorted event list
59
+  
49 60
 } cmXsNote_t;
50 61
 
62
+typedef struct cmXsConnect_str
63
+{
64
+  bool                    doneFl; // this tie has been completed (slurs only occur in pairs)
65
+  bool                    closeFl;// this tie was properly closed
66
+  const cmXsNote_t*       note;   // associated
67
+  struct cmXsConnect_str* nlink;  // next connected note
68
+  struct cmXsConnect_str* link;   // p->tieL,p->slurL links
69
+} cmXsConnect_t;
70
+
51 71
 typedef struct cmXsVoice_str
52 72
 {
53 73
   unsigned              id;    // Voice id
@@ -81,7 +101,10 @@ typedef struct
81 101
   cmXmlH_t    xmlH;
82 102
   cmLHeapH_t  lhH;
83 103
   cmXsPart_t* partL;
84
-  cmCsvH_t    csvH;  
104
+  cmCsvH_t    csvH;
105
+  
106
+  cmXsConnect_t*  slurL;
107
+  cmXsConnect_t*  tieL;
85 108
 } cmXScore_t;
86 109
 
87 110
 cmXScore_t* _cmXScoreHandleToPtr( cmXsH_t h )
@@ -165,6 +188,8 @@ cmXsRC_t _cmXScorePushNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned voiceId, c
165 188
     n->mlink = note;
166 189
   }
167 190
 
191
+  note->voice = v;
192
+
168 193
   return kOkXsRC;
169 194
 }
170 195
 
@@ -234,6 +259,164 @@ cmXsRC_t  _cmXScoreParsePitch( cmXScore_t* p, const cmXmlNode_t* nnp, unsigned*
234 259
   return rc;  
235 260
 }
236 261
 
262
+cmXsConnect_t* _cmXScoreFindTie( const cmXScore_t* p, unsigned pitch )
263
+{
264
+  cmXsConnect_t* c = p->tieL;
265
+  for(; c!=NULL; c=c->link)
266
+  {
267
+    assert( c->note != NULL );
268
+    if( c->doneFl == false && c->note->pitch == pitch )
269
+      return c;
270
+  }
271
+  return NULL;
272
+}
273
+
274
+cmXsRC_t _cmXScoreNewTie( cmXScore_t* p, const cmXsNote_t* note )
275
+{
276
+  cmXsConnect_t* c;
277
+
278
+  // check that an open tie with the same pitch does not exist
279
+  if((c = _cmXScoreFindTie(p,note->pitch)) != NULL )
280
+  {
281
+    cmErrWarnMsg(&p->err,kUnterminatedTieXsRC,"The tie begun from note on line %i was not terminated. (pitch=%i)",c->note->xmlNode->line,c->note->pitch);
282
+    c->doneFl = true; // close the unterminated tie
283
+  }
284
+  
285
+  // allocate a new connection record
286
+  c  = cmLhAllocZ(p->lhH,cmXsConnect_t,1);
287
+
288
+  // set the first note in the connection
289
+  c->note = note;
290
+
291
+  // append the new record to the end of the tie list
292
+  if(p->tieL == NULL )
293
+    p->tieL = c;
294
+  else
295
+  {
296
+    cmXsConnect_t* cp = p->tieL;
297
+    while( cp->link != NULL )
298
+      cp = cp->link;
299
+    
300
+    cp->link = c;
301
+  }
302
+  
303
+  return kOkXsRC;
304
+}
305
+
306
+cmXsRC_t _cmXScoreContinueTie( cmXScore_t* p, const cmXsNote_t* note, unsigned measNumb )
307
+{
308
+  cmXsConnect_t* c;
309
+
310
+  // find an open tie with the same pitch
311
+  if((c = _cmXScoreFindTie(p,note->pitch)) == NULL )
312
+  {
313
+    cmErrWarnMsg(&p->err,kUnterminatedTieXsRC,"The tie ending on the note on line %i does not have an associated starting note. (pitch=%i)",note->xmlNode->line,note->pitch);
314
+    return kOkXsRC;
315
+  }
316
+  
317
+  // allocate a new connection record
318
+  cmXsConnect_t* nc  = cmLhAllocZ(p->lhH,cmXsConnect_t,1);
319
+  nc->note = note;
320
+
321
+  // add the note to the end of the tie list
322
+  if( c->nlink == NULL )
323
+    c->nlink = nc;
324
+  else
325
+  {
326
+    cmXsConnect_t* cp = c->nlink;
327
+    while( cp->nlink != NULL )
328
+      cp=cp->nlink;
329
+    cp->nlink = nc;      
330
+  }
331
+    
332
+  // if this is the last note in the tie ...
333
+  if( cmIsFlag(note->flags,kTieEndXsFl) && cmIsNotFlag(note->flags,kTieBegXsFl) )
334
+  {
335
+    c->doneFl = true;  // ... mark the tie list as complete ...
336
+    c->closeFl= true;  // ... and properly closed
337
+    printf("tie done: meas=%i line=%i pitch=%i\n",measNumb,note->xmlNode->line,note->pitch);
338
+  }
339
+  return kOkXsRC;
340
+}
341
+
342
+cmXsRC_t _cmXScoreProcessTie( cmXScore_t* p, const cmXmlNode_t* np, cmXsNote_t* note, unsigned measNumb )
343
+{
344
+  cmXsRC_t rc = kOkXsRC;
345
+  
346
+  // is this is first note in a tied pair
347
+  if( cmXmlNodeHasChildWithAttrAndValue(np,"tie","type","start",NULL) )
348
+    note->flags |= kTieBegXsFl;
349
+
350
+  // is this is second note in a tied pair
351
+  if( cmXmlNodeHasChildWithAttrAndValue(np,"tie","type","stop",NULL) )
352
+    note->flags |= kTieEndXsFl;
353
+
354
+  // if this is a tie start (and not a tie continue) 
355
+  if( cmIsFlag(note->flags,kTieBegXsFl) && cmIsNotFlag(note->flags,kTieEndXsFl) )
356
+    rc = _cmXScoreNewTie(p,note);
357
+  else
358
+    // if this is a tie continue or end
359
+    if( cmIsFlag(note->flags,kTieEndXsFl) )
360
+      rc = _cmXScoreContinueTie(p,note,measNumb); // this is a tie end or continue
361
+      
362
+  return rc;
363
+}
364
+
365
+const cmXsNote_t*  _cmXScoreResolveTie( const cmXsNote_t* note )
366
+{
367
+  const cmXsMeas_t* m = note->meas;
368
+  const cmXsNote_t* n = note->slink;
369
+
370
+  while( n!=NULL )
371
+  {    
372
+    for(; n!=NULL; n=n->slink)
373
+      if( note->pitch==n->pitch && note->voice==n->voice )
374
+        return n;
375
+
376
+    if( m->link == NULL )
377
+      break;
378
+
379
+    // got to next measure
380
+    if((m = m->link) == NULL )
381
+      break;
382
+    
383
+    n = m->noteL;
384
+  }
385
+
386
+  return NULL;
387
+}
388
+
389
+cmXsRC_t  _cmXScoreResolveTies( cmXScore_t* p )
390
+{
391
+  cmXsRC_t rc = kOkXsRC;
392
+  
393
+  cmXsPart_t* pp = p->partL;
394
+  for(; pp!=NULL; pp=pp->link)
395
+  {
396
+    cmXsMeas_t* mp = pp->measL;
397
+    for(; mp!=NULL; mp=mp->link)
398
+    {
399
+      cmXsNote_t* np = mp->noteL;
400
+      for(; np!=NULL; np=np->slink)
401
+        if( cmIsFlag(np->flags,kTieBegXsFl) )
402
+        {
403
+          const cmXsNote_t* tnp;
404
+          if((tnp = _cmXScoreResolveTie(np)) == NULL)
405
+          {
406
+            
407
+          }
408
+          else
409
+          {
410
+          }
411
+        }
412
+    }
413
+  }
414
+
415
+  return rc;
416
+}
417
+
418
+
419
+
237 420
 cmXsRC_t  _cmXScoreParseNoteRValue( cmXScore_t* p, const cmXmlNode_t* nnp, const cmChar_t* label, double* rvalueRef )
238 421
 {
239 422
   typedef struct map_str
@@ -356,6 +539,9 @@ cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t*
356 539
   cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1);
357 540
   unsigned    voiceId;
358 541
 
542
+  note->meas    = meas;
543
+  note->xmlNode = nnp;
544
+
359 545
   // get the voice id for this node
360 546
   if( cmXmlNodeUInt(nnp,&voiceId,"voice",NULL) != kOkXmlRC )
361 547
     return _cmXScoreMissingNode(p,nnp,"voice");
@@ -384,6 +570,10 @@ cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t*
384 570
   if( cmXmlNodeHasChild(nnp,"chord",NULL) )
385 571
     note->flags |= kChordXsFl;
386 572
 
573
+  // process ties attached to this note
574
+  if((rc = _cmXScoreProcessTie(p,nnp,note,meas->number)) != kOkXsRC )
575
+    return rc;
576
+  
387 577
   // has 'heel' mark
388 578
   if( cmXmlNodeHasChild(nnp,"notations","technical","heel",NULL) )
389 579
     note->flags |= kHeelXsFl;
@@ -404,7 +594,7 @@ cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t*
404 594
   return _cmXScorePushNote(p, meas, voiceId, note );
405 595
 }
406 596
 
407
-cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned tick, unsigned duration, double rvalue, const cmChar_t* tvalue, unsigned flags )
597
+cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t* noteXmlNode, unsigned tick, unsigned duration, double rvalue, const cmChar_t* tvalue, unsigned flags )
408 598
 {
409 599
   cmXsNote_t* note    = cmLhAllocZ(p->lhH,cmXsNote_t,1);
410 600
   unsigned    voiceId = 0;    // non-note's are always assigned to voiceId=0;
@@ -414,6 +604,8 @@ cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned tick, u
414 604
   note->rvalue   = rvalue;
415 605
   note->tvalue   = tvalue;
416 606
   note->duration = duration;
607
+  note->meas     = meas;
608
+  note->xmlNode  = noteXmlNode;
417 609
   
418 610
   return _cmXScorePushNote(p, meas, voiceId, note );
419 611
 }
@@ -477,7 +669,7 @@ cmXsRC_t  _cmXScoreParseDirection(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNo
477 669
     }
478 670
   }
479 671
 
480
-  return _cmXScorePushNonNote(p,meas,tick+offset,duration,rvalue,tvalue,flags);            
672
+  return _cmXScorePushNonNote(p,meas,dnp,tick+offset,duration,rvalue,tvalue,flags);            
481 673
       
482 674
 }
483 675
 
@@ -515,7 +707,7 @@ cmXsRC_t _cmXScoreParseMeasure(cmXScore_t* p, cmXsPart_t* pp, const cmXmlNode_t*
515 707
   }
516 708
   
517 709
   // store the bar line
518
-  if((rc = _cmXScorePushNonNote(p,meas,tick,0,0,NULL,kBarXsFl)) != kOkXsRC )
710
+  if((rc = _cmXScorePushNonNote(p,meas,mnp,tick,0,0,NULL,kBarXsFl)) != kOkXsRC )
519 711
     return rc;
520 712
 
521 713
   
@@ -661,6 +853,10 @@ cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn )
661 853
   // CSV output initialize failed.
662 854
   if( cmCsvInitialize(&p->csvH,ctx) != kOkCsvRC )
663 855
     rc = cmErrMsg(&p->err,kCsvFailXsRC,"CSV output object create failed.");
856
+
857
+  cmXsConnect_t* c = p->tieL;
858
+  for(; c!=NULL; c=c->link)
859
+    cmErrWarnMsg(&p->err,kUnterminatedTieXsRC,"The tie begun from note on line %i was not terminated. (pitch=%i)",c->note->xmlNode->line,c->note->pitch);
664 860
   
665 861
  errLabel:
666 862
   if( rc != kOkXsRC )
@@ -694,22 +890,25 @@ bool     cmXScoreIsValid( cmXsH_t h )
694 890
 
695 891
 void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note )
696 892
 {
697
-  const cmChar_t* B = cmIsFlag(note->flags,kBarXsFl)       ? "|" : "-";
698
-  const cmChar_t* R = cmIsFlag(note->flags,kRestXsFl)      ? "R" : "-";
699
-  const cmChar_t* G = cmIsFlag(note->flags,kGraceXsFl)     ? "G" : "-";
700
-  const cmChar_t* D = cmIsFlag(note->flags,kDotXsFl)       ? "D" : "-";
701
-  const cmChar_t* C = cmIsFlag(note->flags,kChordXsFl)     ? "C" : "-";
702
-  const cmChar_t* e = cmIsFlag(note->flags,kEvenXsFl)      ? "e" : "-";
703
-  const cmChar_t* d = cmIsFlag(note->flags,kDynXsFl)       ? "d" : "-";
704
-  const cmChar_t* t = cmIsFlag(note->flags,kTempoXsFl)     ? "t" : "-";
705
-  const cmChar_t* P = cmIsFlag(note->flags,kPedalDnXsFl)   ? "V" : "-";
893
+  const cmChar_t* B  = cmIsFlag(note->flags,kBarXsFl)       ? "|" : "-";
894
+  const cmChar_t* R  = cmIsFlag(note->flags,kRestXsFl)      ? "R" : "-";
895
+  const cmChar_t* G  = cmIsFlag(note->flags,kGraceXsFl)     ? "G" : "-";
896
+  const cmChar_t* D  = cmIsFlag(note->flags,kDotXsFl)       ? "D" : "-";
897
+  const cmChar_t* C  = cmIsFlag(note->flags,kChordXsFl)     ? "C" : "-";
898
+  const cmChar_t* e  = cmIsFlag(note->flags,kEvenXsFl)      ? "e" : "-";
899
+  const cmChar_t* d  = cmIsFlag(note->flags,kDynXsFl)       ? "d" : "-";
900
+  const cmChar_t* t  = cmIsFlag(note->flags,kTempoXsFl)     ? "t" : "-";
901
+  const cmChar_t* P  = cmIsFlag(note->flags,kPedalDnXsFl)   ? "V" : "-";
902
+  const cmChar_t* H  = cmIsFlag(note->flags,kHeelXsFl)      ? "H" : "-";
903
+  const cmChar_t* T0 = cmIsFlag(note->flags,kTieBegXsFl)    ? "T" : "-";
904
+  const cmChar_t* T1 = cmIsFlag(note->flags,kTieEndXsFl)    ? "_" : "-";
706 905
   P = cmIsFlag(note->flags,kPedalUpXsFl)   ? "^" : P;
707 906
   P = cmIsFlag(note->flags,kPedalUpDnXsFl) ? "X" : P;
708 907
   const cmChar_t* N = note->pitch==0 ? " " : cmMidiToSciPitch( note->pitch, NULL, 0 );
709
-  cmRptPrintf(rpt,"      %5i %5i %4.1f %3s %s%s%s%s%s%s%s%s%s",note->tick,note->duration,note->rvalue,N,B,R,G,D,C,e,d,t,P);
908
+  cmRptPrintf(rpt,"      %5i %5i %4.1f %3s %s%s%s%s%s%s%s%s%s%s%s%s",note->tick,note->duration,note->rvalue,N,B,R,G,D,C,e,d,t,P,H,T0,T1);
710 909
 
711 910
   if( cmIsFlag(note->flags,kSectionXsFl) )
712
-    cmRptPrintf(rpt," %i",cmStringNullGuard(note->tvalue));
911
+    cmRptPrintf(rpt," %s",cmStringNullGuard(note->tvalue));
713 912
 
714 913
   printf("\n");
715 914
   

+ 9
- 4
app/cmXScore.h Näytä tiedosto

@@ -11,7 +11,9 @@ extern "C" {
11 11
     kXmlFailXsRC,
12 12
     kLHeapFailXsRC,
13 13
     kSyntaxErrorXsRC,
14
-    kCsvFailXsRC
14
+    kCsvFailXsRC,
15
+    kUnterminatedTieXsRC,
16
+    kUnterminatedSlurXsRC
15 17
   };
16 18
 
17 19
   typedef cmRC_t     cmXsRC_t;
@@ -24,6 +26,7 @@ extern "C" {
24 26
   // 1) Convert XML to UTF-8:
25 27
   //       a. Change: encoding='UTF-16' to encoding='UTF-8'
26 28
   //       b. Emacs C-x <RET> f utf-8 <RET>
29
+  //       c. Change: <?xml ... encoding='UTF-16' to encoding='UTF-8' ...?>
27 30
   //
28 31
   // 2) Replace "DoletSibelius Unknown Symbol Index" with "DoletSibelius unknownSymIdx"
29 32
   //
@@ -32,10 +35,12 @@ extern "C" {
32 35
   // 5) Heel is being parsed but not used. 
33 36
   // 6) Sostenuto pedal events are not being parsed because they are not pedal events.
34 37
   // 7) What is a 'pedal-change' event vs. a 'pedal-stop' event.
35
-  // 8) Verify the colors.
36
-  // 9) Remove blank bars at end.
38
+  // 8) Verify the colors. (done)
39
+  // 9) Remove blank bars at end (done in xml - do in score)
37 40
   //10) Need to assign section targets (always default to next section)
38
-  //11) Mark tied notes for skip.
41
+  //11) Mark tied notes for skip. (done)
42
+  //12) Determine note off locations based on ties and slurs - defer 'pedal' to player
43
+  
39 44
  
40 45
   cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn );
41 46
   cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );

Loading…
Peruuta
Tallenna