Pārlūkot izejas kodu

cmXScore.h/c : Began tie processing.

master
kevin 8 gadus atpakaļ
vecāks
revīzija
5c27c2455f
2 mainītis faili ar 227 papildinājumiem un 23 dzēšanām
  1. 218
    19
      app/cmXScore.c
  2. 9
    4
      app/cmXScore.h

+ 218
- 19
app/cmXScore.c Parādīt failu

29
   kEvenXsFl      = 0x0080,
29
   kEvenXsFl      = 0x0080,
30
   kTempoXsFl     = 0x0100,
30
   kTempoXsFl     = 0x0100,
31
   kHeelXsFl      = 0x0200,
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
 typedef struct cmXsNote_str
43
 typedef struct cmXsNote_str
40
 {
44
 {
42
   unsigned             pitch;    // midi pitch
46
   unsigned             pitch;    // midi pitch
43
   unsigned             tick;     // 
47
   unsigned             tick;     // 
44
   unsigned             duration; // duration in ticks
48
   unsigned             duration; // duration in ticks
49
+  unsigned             pticks;   // play ticks (0 for non-sounding notes)
45
   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, ...)
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
   const cmChar_t*      tvalue;   // text value
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
   struct cmXsNote_str* mlink;    // measure note list 
57
   struct cmXsNote_str* mlink;    // measure note list 
48
   struct cmXsNote_str* slink;    // time sorted event list
58
   struct cmXsNote_str* slink;    // time sorted event list
59
+  
49
 } cmXsNote_t;
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
 typedef struct cmXsVoice_str
71
 typedef struct cmXsVoice_str
52
 {
72
 {
53
   unsigned              id;    // Voice id
73
   unsigned              id;    // Voice id
81
   cmXmlH_t    xmlH;
101
   cmXmlH_t    xmlH;
82
   cmLHeapH_t  lhH;
102
   cmLHeapH_t  lhH;
83
   cmXsPart_t* partL;
103
   cmXsPart_t* partL;
84
-  cmCsvH_t    csvH;  
104
+  cmCsvH_t    csvH;
105
+  
106
+  cmXsConnect_t*  slurL;
107
+  cmXsConnect_t*  tieL;
85
 } cmXScore_t;
108
 } cmXScore_t;
86
 
109
 
87
 cmXScore_t* _cmXScoreHandleToPtr( cmXsH_t h )
110
 cmXScore_t* _cmXScoreHandleToPtr( cmXsH_t h )
165
     n->mlink = note;
188
     n->mlink = note;
166
   }
189
   }
167
 
190
 
191
+  note->voice = v;
192
+
168
   return kOkXsRC;
193
   return kOkXsRC;
169
 }
194
 }
170
 
195
 
234
   return rc;  
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
 cmXsRC_t  _cmXScoreParseNoteRValue( cmXScore_t* p, const cmXmlNode_t* nnp, const cmChar_t* label, double* rvalueRef )
420
 cmXsRC_t  _cmXScoreParseNoteRValue( cmXScore_t* p, const cmXmlNode_t* nnp, const cmChar_t* label, double* rvalueRef )
238
 {
421
 {
239
   typedef struct map_str
422
   typedef struct map_str
356
   cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1);
539
   cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1);
357
   unsigned    voiceId;
540
   unsigned    voiceId;
358
 
541
 
542
+  note->meas    = meas;
543
+  note->xmlNode = nnp;
544
+
359
   // get the voice id for this node
545
   // get the voice id for this node
360
   if( cmXmlNodeUInt(nnp,&voiceId,"voice",NULL) != kOkXmlRC )
546
   if( cmXmlNodeUInt(nnp,&voiceId,"voice",NULL) != kOkXmlRC )
361
     return _cmXScoreMissingNode(p,nnp,"voice");
547
     return _cmXScoreMissingNode(p,nnp,"voice");
384
   if( cmXmlNodeHasChild(nnp,"chord",NULL) )
570
   if( cmXmlNodeHasChild(nnp,"chord",NULL) )
385
     note->flags |= kChordXsFl;
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
   // has 'heel' mark
577
   // has 'heel' mark
388
   if( cmXmlNodeHasChild(nnp,"notations","technical","heel",NULL) )
578
   if( cmXmlNodeHasChild(nnp,"notations","technical","heel",NULL) )
389
     note->flags |= kHeelXsFl;
579
     note->flags |= kHeelXsFl;
404
   return _cmXScorePushNote(p, meas, voiceId, note );
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
   cmXsNote_t* note    = cmLhAllocZ(p->lhH,cmXsNote_t,1);
599
   cmXsNote_t* note    = cmLhAllocZ(p->lhH,cmXsNote_t,1);
410
   unsigned    voiceId = 0;    // non-note's are always assigned to voiceId=0;
600
   unsigned    voiceId = 0;    // non-note's are always assigned to voiceId=0;
414
   note->rvalue   = rvalue;
604
   note->rvalue   = rvalue;
415
   note->tvalue   = tvalue;
605
   note->tvalue   = tvalue;
416
   note->duration = duration;
606
   note->duration = duration;
607
+  note->meas     = meas;
608
+  note->xmlNode  = noteXmlNode;
417
   
609
   
418
   return _cmXScorePushNote(p, meas, voiceId, note );
610
   return _cmXScorePushNote(p, meas, voiceId, note );
419
 }
611
 }
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
   }
707
   }
516
   
708
   
517
   // store the bar line
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
     return rc;
711
     return rc;
520
 
712
 
521
   
713
   
661
   // CSV output initialize failed.
853
   // CSV output initialize failed.
662
   if( cmCsvInitialize(&p->csvH,ctx) != kOkCsvRC )
854
   if( cmCsvInitialize(&p->csvH,ctx) != kOkCsvRC )
663
     rc = cmErrMsg(&p->err,kCsvFailXsRC,"CSV output object create failed.");
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
  errLabel:
861
  errLabel:
666
   if( rc != kOkXsRC )
862
   if( rc != kOkXsRC )
694
 
890
 
695
 void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note )
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
   P = cmIsFlag(note->flags,kPedalUpXsFl)   ? "^" : P;
905
   P = cmIsFlag(note->flags,kPedalUpXsFl)   ? "^" : P;
707
   P = cmIsFlag(note->flags,kPedalUpDnXsFl) ? "X" : P;
906
   P = cmIsFlag(note->flags,kPedalUpDnXsFl) ? "X" : P;
708
   const cmChar_t* N = note->pitch==0 ? " " : cmMidiToSciPitch( note->pitch, NULL, 0 );
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
   if( cmIsFlag(note->flags,kSectionXsFl) )
910
   if( cmIsFlag(note->flags,kSectionXsFl) )
712
-    cmRptPrintf(rpt," %i",cmStringNullGuard(note->tvalue));
911
+    cmRptPrintf(rpt," %s",cmStringNullGuard(note->tvalue));
713
 
912
 
714
   printf("\n");
913
   printf("\n");
715
   
914
   

+ 9
- 4
app/cmXScore.h Parādīt failu

11
     kXmlFailXsRC,
11
     kXmlFailXsRC,
12
     kLHeapFailXsRC,
12
     kLHeapFailXsRC,
13
     kSyntaxErrorXsRC,
13
     kSyntaxErrorXsRC,
14
-    kCsvFailXsRC
14
+    kCsvFailXsRC,
15
+    kUnterminatedTieXsRC,
16
+    kUnterminatedSlurXsRC
15
   };
17
   };
16
 
18
 
17
   typedef cmRC_t     cmXsRC_t;
19
   typedef cmRC_t     cmXsRC_t;
24
   // 1) Convert XML to UTF-8:
26
   // 1) Convert XML to UTF-8:
25
   //       a. Change: encoding='UTF-16' to encoding='UTF-8'
27
   //       a. Change: encoding='UTF-16' to encoding='UTF-8'
26
   //       b. Emacs C-x <RET> f utf-8 <RET>
28
   //       b. Emacs C-x <RET> f utf-8 <RET>
29
+  //       c. Change: <?xml ... encoding='UTF-16' to encoding='UTF-8' ...?>
27
   //
30
   //
28
   // 2) Replace "DoletSibelius Unknown Symbol Index" with "DoletSibelius unknownSymIdx"
31
   // 2) Replace "DoletSibelius Unknown Symbol Index" with "DoletSibelius unknownSymIdx"
29
   //
32
   //
32
   // 5) Heel is being parsed but not used. 
35
   // 5) Heel is being parsed but not used. 
33
   // 6) Sostenuto pedal events are not being parsed because they are not pedal events.
36
   // 6) Sostenuto pedal events are not being parsed because they are not pedal events.
34
   // 7) What is a 'pedal-change' event vs. a 'pedal-stop' event.
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
   //10) Need to assign section targets (always default to next section)
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
   cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn );
45
   cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn );
41
   cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );
46
   cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );

Notiek ielāde…
Atcelt
Saglabāt