Browse Source

cmXScore.h/c : Completed note, metronome, section label, color, and pedal parsing. Added per measure time sorted note list.

master
Kevin Larke 8 years ago
parent
commit
304ff25285
2 changed files with 375 additions and 106 deletions
  1. 369
    102
      app/cmXScore.c
  2. 6
    4
      app/cmXScore.h

+ 369
- 102
app/cmXScore.c View File

17
 
17
 
18
 enum
18
 enum
19
 {
19
 {
20
-  kRestXsFl    = 0x0001,
21
-  kGraceXsFl   = 0x0002,
22
-  kDotXsFl     = 0x0004
20
+  kSectionXsFl   = 0x0001,  // rvalue holds section number
21
+  kBarXsFl       = 0x0002,
22
+  kRestXsFl      = 0x0004,
23
+  kGraceXsFl     = 0x0008,
24
+  kDotXsFl       = 0x0010,
25
+  kChordXsFl     = 0x0020,
26
+  kDynXsFl       = 0x0040,
27
+  kEvenXsFl      = 0x0080,
28
+  kTempoXsFl     = 0x0100,
29
+  kPedalDnXsFl   = 0x0200,
30
+  kPedalUpXsFl   = 0x0400,
31
+  kPedalUpDnXsFl = 0x0800,
32
+  kMetronomeXsFl = 0x1000  // duration holds BPM 
23
 };
33
 };
24
 
34
 
25
 
35
 
36
+
26
 typedef struct cmXsNote_str
37
 typedef struct cmXsNote_str
27
 {
38
 {
28
-  unsigned flags;
29
-  unsigned pitch;     // midi pitch
30
-  unsigned duration;  // duration in ticks
31
-  unsigned rvalue;    // 1/type = rythmic value (1/4=quarter note, 1/8=eighth note, ...)
32
-  struct cmXsNote_str* link;
33
-  
39
+  unsigned             flags;    // See k???XsFl 
40
+  unsigned             pitch;    // midi pitch
41
+  unsigned             tick;     // 
42
+  unsigned             duration; // duration in ticks
43
+  unsigned             rvalue;   // 1/type = rythmic value (1/4=quarter note, 1/8=eighth note, ...)
44
+  struct cmXsNote_str* mlink;    // measure note list 
45
+  struct cmXsNote_str* slink;    // time sorted event list
34
 } cmXsNote_t;
46
 } cmXsNote_t;
35
 
47
 
48
+
36
 typedef struct cmXsVoice_str
49
 typedef struct cmXsVoice_str
37
 {
50
 {
38
   unsigned              id;    // Voice id
51
   unsigned              id;    // Voice id
49
   unsigned             beat_type;
62
   unsigned             beat_type;
50
   
63
   
51
   cmXsVoice_t*         voiceL;  // List of voices in this measure   
64
   cmXsVoice_t*         voiceL;  // List of voices in this measure   
65
+  cmXsNote_t*          noteL;   // List of time sorted notes in this measure
52
   
66
   
53
   struct cmXsMeas_str* link;    // Link to other measures in this part.
67
   struct cmXsMeas_str* link;    // Link to other measures in this part.
54
 } cmXsMeas_t;
68
 } cmXsMeas_t;
92
   return rc;
106
   return rc;
93
 }
107
 }
94
 
108
 
95
-cmXsRC_t _cmXScoreMissingNode( cmXScore_t* p, const cmChar_t* label, const cmXmlAttr_t* attr )
109
+cmXsRC_t _cmXScoreMissingNode( cmXScore_t* p, const cmXmlNode_t* parent, const cmChar_t* label )
96
 {
110
 {
97
-  if( attr == NULL )
98
-    return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Missing XML node '%s'.",label);
99
-
100
-  return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Missing XML node '%s' - Attribute:%s=%s",label,attr->label,attr->value);
111
+  return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Missing XML node '%s'. Parent line:%i",label,parent->line);
101
 }
112
 }
102
 
113
 
103
 cmXsRC_t _cmXScoreMissingAttribute( cmXScore_t* p, const cmXmlNode_t* np, const cmChar_t* attrLabel )
114
 cmXsRC_t _cmXScoreMissingAttribute( cmXScore_t* p, const cmXmlNode_t* np, const cmChar_t* attrLabel )
105
   return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Missing XML attribute '%s' from node '%s'.",attrLabel,np->label);
116
   return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Missing XML attribute '%s' from node '%s'.",attrLabel,np->label);
106
 }
117
 }
107
 
118
 
119
+cmXsVoice_t* _cmXScoreIdToVoice( cmXsMeas_t* meas, unsigned voiceId )
120
+{
121
+  cmXsVoice_t* v = meas->voiceL;
122
+  for(; v!=NULL; v=v->link)
123
+    if( v->id == voiceId )
124
+      return v;
125
+
126
+  return NULL;
127
+}
128
+
129
+cmXsRC_t _cmXScorePushNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned voiceId, cmXsNote_t* note )
130
+{
131
+  cmXsVoice_t* v;
132
+
133
+  // get the voice recd
134
+  if((v = _cmXScoreIdToVoice(meas,voiceId)) == NULL)
135
+  {
136
+    // the voice recd doesn't exist for this voiceId - allocate one
137
+    v = cmLhAllocZ(p->lhH,cmXsVoice_t,1);
138
+    v->id = voiceId;
139
+
140
+    // add the voice record to the meas->voiceL
141
+    if( meas->voiceL == NULL )
142
+      meas->voiceL = v;
143
+    else
144
+    {
145
+      cmXsVoice_t* vp =  meas->voiceL;
146
+      while( vp->link!=NULL )
147
+        vp = vp->link;
148
+
149
+      vp->link = v;      
150
+    }
151
+  }
152
+
153
+  // add the note record to the end of meas->voiceL
154
+  if( v->noteL == NULL )
155
+    v->noteL = note;
156
+  else
157
+  {
158
+    cmXsNote_t* n = v->noteL;
159
+    while( n->mlink != NULL )
160
+      n = n->mlink;
161
+
162
+    n->mlink = note;
163
+  }
164
+
165
+  return kOkXsRC;
166
+}
167
+
108
 cmXsRC_t _cmXScoreParsePartList( cmXScore_t* p )
168
 cmXsRC_t _cmXScoreParsePartList( cmXScore_t* p )
109
 {
169
 {
110
   cmXsRC_t           rc          = kOkXsRC;
170
   cmXsRC_t           rc          = kOkXsRC;
113
 
173
 
114
   // find the 'part-list'
174
   // find the 'part-list'
115
   if((xnp = cmXmlSearch( cmXmlRoot(p->xmlH), "part-list", NULL, 0)) == NULL )
175
   if((xnp = cmXmlSearch( cmXmlRoot(p->xmlH), "part-list", NULL, 0)) == NULL )
116
-    return _cmXScoreMissingNode(p,"part-list",NULL);
176
+    return _cmXScoreMissingNode(p,cmXmlRoot(p->xmlH),"part-list");
117
   
177
   
118
   const cmXmlNode_t* cnp = xnp->children;
178
   const cmXmlNode_t* cnp = xnp->children;
119
 
179
 
152
   const cmChar_t* step   = NULL;
212
   const cmChar_t* step   = NULL;
153
 
213
 
154
   if((step = cmXmlNodeValue(nnp,"pitch","step",NULL)) == NULL )
214
   if((step = cmXmlNodeValue(nnp,"pitch","step",NULL)) == NULL )
155
-    return _cmXScoreMissingNode(p,"step",NULL);
215
+    return _cmXScoreMissingNode(p,nnp,"step");
156
   
216
   
157
   if((rc = cmXmlNodeUInt( nnp,&octave,"pitch","octave",NULL)) != kOkXmlRC )
217
   if((rc = cmXmlNodeUInt( nnp,&octave,"pitch","octave",NULL)) != kOkXmlRC )
158
-    return _cmXScoreMissingNode(p,"octave",NULL);
218
+    return _cmXScoreMissingNode(p,nnp,"octave");
159
   
219
   
160
   cmXmlNodeDouble( nnp,&alter,"pitch","alter",NULL);
220
   cmXmlNodeDouble( nnp,&alter,"pitch","alter",NULL);
161
 
221
 
171
   return rc;  
231
   return rc;  
172
 }
232
 }
173
 
233
 
174
-unsigned _cmXScoreParseNoteType( const cmXmlNode_t* nnp )
234
+unsigned _cmXScoreParseNoteRValue( cmXScore_t* p, const cmXmlNode_t* nnp, const cmChar_t* label )
175
 {
235
 {
176
   typedef struct map_str
236
   typedef struct map_str
177
   {
237
   {
181
 
241
 
182
   map_t mapV[] =
242
   map_t mapV[] =
183
   {
243
   {
184
-    { 1, "whole" },
185
-    { 2, "half"  },
186
-    { 4, "quarter" },
187
-    { 8, "eighth" },
188
-    { 16,"16th"},
189
-    { 32,"32nd"},
190
-    { 64,"64th"},
191
-    {128,"128th"},
192
-    {0,""}
244
+    {   1, "whole"   },
245
+    {   2, "half"    },
246
+    {   4, "quarter" },
247
+    {   8, "eighth"  },
248
+    {  16, "16th"    },
249
+    {  32, "32nd"    },
250
+    {  64, "64th"    },
251
+    { 128, "128th"   },
252
+    {   0, ""        }
193
   };
253
   };
194
 
254
 
195
-  if( cmXmlNodeHasChild(nnp,"type") )
196
-  {
197
-    const cmChar_t* str;
198
-    if((str = cmXmlNodeValue(nnp,"type",NULL)) == NULL)
199
-    {
200
-      unsigned i;
201
-      for(i=0; mapV[i].rvalue!=0; ++i)
202
-        if( cmTextCmp(mapV[i].label,str) == 0 )
203
-          return mapV[i].rvalue;
204
-    }
205
-
206
-  }
207
-
255
+  const cmChar_t* str;
256
+  if((str = cmXmlNodeValue(nnp,label,NULL)) == NULL)
257
+    return 0;
258
+  
259
+  unsigned i;
260
+  for(i=0; mapV[i].rvalue!=0; ++i)
261
+    if( cmTextCmp(mapV[i].label,str) == 0 )
262
+      return mapV[i].rvalue;
263
+  
208
   return 0;
264
   return 0;
209
 }
265
 }
210
 
266
 
211
-cmXsVoice_t* _cmXScoreIdToVoice( cmXsMeas_t* meas, unsigned voiceId )
267
+cmXsRC_t  _cmXScoreParseColor( cmXScore_t* p, const cmXmlNode_t* nnp, cmXsNote_t* note )
212
 {
268
 {
213
-  cmXsVoice_t* v = meas->voiceL;
214
-  for(; v!=NULL; v=v->link)
215
-    if( v->id == voiceId )
216
-      return v;
217
-
218
-  return NULL;
219
-}
269
+  cmXsRC_t rc = kOkXsRC;
270
+  const cmXmlAttr_t* a;
220
 
271
 
221
-cmXsRC_t _cmXScorePushNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned voiceId, cmXsNote_t* note )
222
-{
223
-  cmXsVoice_t* v;
224
-  if((v = _cmXScoreIdToVoice(meas,voiceId)) == NULL)
272
+   typedef struct map_str
225
   {
273
   {
226
-    v = cmLhAllocZ(p->lhH,cmXsVoice_t,1);
227
-    v->id = voiceId;
228
-    
229
-    if( meas->voiceL == NULL )
230
-      meas->voiceL = v;
231
-    else
232
-    {
233
-      cmXsVoice_t* vp =  meas->voiceL;
234
-      while( vp->link!=NULL )
235
-        vp = vp->link;
236
-
237
-      vp->link = v;      
238
-    }
239
-  }
274
+    unsigned        value;
275
+    const cmChar_t* label;
276
+  } map_t;
240
 
277
 
241
-  if( v->noteL == NULL )
242
-    v->noteL = note;
243
-  else
278
+  map_t mapV[] =
244
   {
279
   {
245
-    cmXsNote_t* n = v->noteL;
246
-    while( n != NULL )
247
-      n = n->link;
280
+    { kEvenXsFl,                         "#0000FF" },
281
+    { kTempoXsFl,                        "#00FF00" },
282
+    { kDynXsFl,                          "#FF0000" },
283
+    { kTempoXsFl | kEvenXsFl,            "#00FFFF" },
284
+    { kDynXsFl   | kEvenXsFl,            "#FF00FF" },    
285
+    { kDynXsFl   | kTempoXsFl,           "#FF7F00" },
286
+    { kTempoXsFl | kEvenXsFl | kDynXsFl, "#996633" },
287
+    { 0, "" }
288
+  };
289
+  
290
+  if((a = cmXmlFindAttrib(nnp, "color" )) != NULL )
291
+  {
292
+    unsigned i;
293
+    for(i=0; mapV[i].value != 0; ++i)
294
+      if( cmTextCmp(a->value,mapV[i].label) == 0 )
295
+      {
296
+        note->flags += mapV[i].value;
297
+        break;
298
+      }
248
 
299
 
249
-    n->link = note;
300
+    if( mapV[i].value == 0 )
301
+      rc = cmErrMsg(&p->err,kSyntaxErrorXsRC,"The note color '%s' was not found.",a->value);
250
   }
302
   }
251
 
303
 
252
-  return kOkXsRC;
304
+  return rc;
253
 }
305
 }
254
 
306
 
255
-cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t* nnp)
307
+cmXsRC_t _cmXScoreParseNote(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t* nnp, unsigned* tickRef )
256
 {
308
 {
257
   cmXsRC_t    rc   = kOkXsRC;
309
   cmXsRC_t    rc   = kOkXsRC;
258
-  
259
   cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1);
310
   cmXsNote_t* note = cmLhAllocZ(p->lhH,cmXsNote_t,1);
260
-  unsigned voiceId;
311
+  unsigned    voiceId;
261
 
312
 
262
   // get the voice id for this node
313
   // get the voice id for this node
263
   if( cmXmlNodeUInt(nnp,&voiceId,"voice",NULL) != kOkXmlRC )
314
   if( cmXmlNodeUInt(nnp,&voiceId,"voice",NULL) != kOkXmlRC )
264
-    return _cmXScoreMissingNode(p,"voice",NULL);
315
+    return _cmXScoreMissingNode(p,nnp,"voice");
265
 
316
 
266
-  
267
   // if this note has a pitch
317
   // if this note has a pitch
268
-  if( cmXmlNodeHasChild(nnp,"pitch") )
318
+  if( cmXmlNodeHasChild(nnp,"pitch",NULL) )
269
     if((rc = _cmXScoreParsePitch(p,nnp,&note->pitch)) != kOkXsRC )
319
     if((rc = _cmXScoreParsePitch(p,nnp,&note->pitch)) != kOkXsRC )
270
       return rc;
320
       return rc;
271
 
321
 
322
+  // get the note duration
323
+  cmXmlNodeUInt(nnp,&note->duration,"duration",NULL);
324
+  
272
   // is 'rest'
325
   // is 'rest'
273
-  if( cmXmlNodeHasChild(nnp,"rest") )
326
+  if( cmXmlNodeHasChild(nnp,"rest",NULL) )
274
     note->flags |= kRestXsFl;
327
     note->flags |= kRestXsFl;
275
 
328
 
276
   // is 'grace'
329
   // is 'grace'
277
-  if( cmXmlNodeHasChild(nnp,"grace") )
330
+  if( cmXmlNodeHasChild(nnp,"grace",NULL) )
278
     note->flags |= kGraceXsFl;
331
     note->flags |= kGraceXsFl;
279
 
332
 
280
   // is 'dot'
333
   // is 'dot'
281
-  if( cmXmlNodeHasChild(nnp,"dot") )
334
+  if( cmXmlNodeHasChild(nnp,"dot",NULL) )
282
     note->flags |= kDotXsFl;
335
     note->flags |= kDotXsFl;
283
 
336
 
284
-  if((note->rvalue =  _cmXScoreParseNoteType(nnp)) == 0 )
285
-    return _cmXScoreMissingNode(nnp,"type",NULL);
337
+  // is 'chord'
338
+  if( cmXmlNodeHasChild(nnp,"chord",NULL) )
339
+    note->flags |= kChordXsFl;
340
+
341
+  // set color coded flags
342
+  if((rc = _cmXScoreParseColor(p, nnp, note )) != kOkXsRC )
343
+    return rc;
344
+  
345
+  // get the note's rythmic value
346
+  if((note->rvalue =  _cmXScoreParseNoteRValue(p,nnp,"type")) == 0 )
347
+    return _cmXScoreMissingNode(p,nnp,"type");
348
+
349
+  note->tick = *tickRef;
350
+
351
+  if( cmIsNotFlag(note->flags,kChordXsFl) )
352
+    *tickRef += note->duration;
353
+  
354
+  return _cmXScorePushNote(p, meas, voiceId, note );
355
+}
356
+
357
+cmXsRC_t _cmXScorePushNonNote( cmXScore_t* p, cmXsMeas_t* meas, unsigned tick, unsigned duration, unsigned rvalue, unsigned flags )
358
+{
359
+  cmXsNote_t* note    = cmLhAllocZ(p->lhH,cmXsNote_t,1);
360
+  unsigned    voiceId = 0;    // non-note's are always assigned to voiceId=0;
361
+  
362
+  note->tick     = tick;
363
+  note->flags    = flags;
364
+  note->rvalue   = rvalue;
365
+  note->duration = duration;
366
+  
367
+  return _cmXScorePushNote(p, meas, voiceId, note );
368
+}
369
+
370
+cmXsRC_t  _cmXScoreParseDirection(cmXScore_t* p, cmXsMeas_t* meas, const cmXmlNode_t* dnp, unsigned tick)
371
+{
372
+  const cmXmlNode_t* np = NULL;
373
+  const cmXmlAttr_t* a = NULL;
374
+  unsigned           flags    = 0;
375
+  int                offset   = 0;
376
+  unsigned           rvalue   = 0;
377
+  unsigned           duration = 0;
378
+
379
+  
380
+  cmXmlNodeInt(dnp, &offset, "offset", NULL );
381
+   
382
+ 
383
+  // if this is a metronome direction
384
+  if((np = cmXmlSearch( dnp, "metronome", NULL, 0)) != NULL )
385
+  {
386
+    
387
+    if( cmXmlNodeUInt(np,&duration,"per-minute",NULL) != kOkXmlRC )
388
+      return cmErrMsg(&p->err,kSyntaxErrorXsRC,"The 'per-minute' metronome value is missing on line %i.",np->line);
389
+
390
+    if((rvalue = _cmXScoreParseNoteRValue(p,np,"beat-unit")) == 0 )
391
+      return cmErrMsg(&p->err,kSyntaxErrorXsRC,"The 'beat-unit' metronome value is missing on line %i.",np->line);
392
+
393
+    flags = kMetronomeXsFl;
394
+  }
395
+  else
396
+
397
+  // if this is a pedal direction
398
+  if((np = cmXmlSearch( dnp, "pedal",NULL,0)) != NULL )
399
+  {
286
     
400
     
401
+    if((a = cmXmlFindAttrib(np,"type")) == NULL )
402
+      return _cmXScoreMissingAttribute(p, np, "type" );
403
+
404
+    if( cmTextCmp(a->value,"start") == 0 )
405
+      flags = kPedalDnXsFl;
406
+    else
407
+      if( cmTextCmp(a->value,"change") == 0 )
408
+        flags = kPedalUpDnXsFl;
409
+      else
410
+        if( cmTextCmp(a->value,"stop") == 0 )
411
+          flags = kPedalUpXsFl;
412
+        else
413
+          return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Unrecognized pedal type:'%s'.",cmStringNullGuard(a->value));
414
+  }
415
+  else
416
+  
417
+  // if this is a 'words' direction
418
+  if((np = cmXmlSearch( dnp, "words", NULL, 0)) != NULL )
419
+  {
420
+    if((a = cmXmlFindAttrib(np,"enclosure")) != NULL && cmTextCmp(a->value,"rectangle")==0 )
421
+    {
422
+      if( cmXmlNodeUInt(np,&rvalue,NULL) != kOkXsRC )
423
+        return cmErrMsg(&p->err,kSyntaxErrorXsRC,"Error reading section number on line %i.",np->line);
424
+
425
+      printf("rvalue=%i\n",rvalue);
426
+      
427
+      flags = kSectionXsFl;
428
+    }
429
+  }
430
+
431
+  return _cmXScorePushNonNote(p,meas,tick+offset,duration,rvalue,flags);            
432
+      
287
 }
433
 }
288
 
434
 
435
+
289
 cmXsRC_t _cmXScoreParseMeasure(cmXScore_t* p, cmXsPart_t* pp, const cmXmlNode_t* mnp)
436
 cmXsRC_t _cmXScoreParseMeasure(cmXScore_t* p, cmXsPart_t* pp, const cmXmlNode_t* mnp)
290
 {
437
 {
291
-  cmXsRC_t rc = kOkXsRC;
438
+  cmXsRC_t           rc   = kOkXsRC;
439
+  const cmXmlNode_t* np   = NULL;  
440
+  unsigned           tick = 0;
292
 
441
 
293
   // allocate the 'measure' record
442
   // allocate the 'measure' record
294
   cmXsMeas_t* meas = cmLhAllocZ(p->lhH,cmXsMeas_t,1);
443
   cmXsMeas_t* meas = cmLhAllocZ(p->lhH,cmXsMeas_t,1);
295
-  const cmXmlNode_t* np;
296
 
444
 
297
   // get measure number
445
   // get measure number
298
   if( cmXmlAttrUInt(mnp,"number", &meas->number) != kOkXmlRC )
446
   if( cmXmlAttrUInt(mnp,"number", &meas->number) != kOkXmlRC )
305
     cmXsMeas_t* m = pp->measL;
453
     cmXsMeas_t* m = pp->measL;
306
     while( m->link != NULL )
454
     while( m->link != NULL )
307
       m = m->link;
455
       m = m->link;
308
-    m->link = meas;
456
+    
457
+    m->link       = meas;
309
   }
458
   }
310
   
459
   
311
   // get measure attributes node
460
   // get measure attributes node
312
   if((np = cmXmlSearch(mnp,"attributes",NULL,0)) == NULL)
461
   if((np = cmXmlSearch(mnp,"attributes",NULL,0)) == NULL)
313
-    return rc; // (this measure does not have any attributes)
462
+    return rc;                  // (this measure does not have any attributes)
463
+
314
 
464
 
315
   cmXmlNodeUInt(np,&meas->divisions,"divisions",NULL);
465
   cmXmlNodeUInt(np,&meas->divisions,"divisions",NULL);
316
-  cmXmlNodeUInt(np,&meas->beats,"time","beats",NULL);
466
+  cmXmlNodeUInt(np,&meas->beats,    "time","beats",NULL);
317
   cmXmlNodeUInt(np,&meas->beat_type,"time","beat-type",NULL);
467
   cmXmlNodeUInt(np,&meas->beat_type,"time","beat-type",NULL);
318
 
468
 
319
-  int tick = 0;
469
+  // store the bar line
470
+  if((rc = _cmXScorePushNonNote(p,meas,tick,0,0,kBarXsFl)) != kOkXsRC )
471
+    return rc;
472
+
320
   
473
   
321
   np = mnp->children;
474
   np = mnp->children;
322
-  for(; np!=NULL; np=np->sibling)
323
-    if( cmTextCmp(np->label,"note") )
475
+
476
+  // for each child of the 'meas' XML node
477
+  for(; rc==kOkXsRC && np!=NULL; np=np->sibling)
478
+  {
479
+    // if this is a 'note' node
480
+    if( cmTextCmp(np->label,"note") == 0 )
324
     {
481
     {
325
-      rc = _cmXScoreParseNote(p,meas,mnp);
482
+      rc = _cmXScoreParseNote(p,meas,np,&tick);
326
     }
483
     }
327
     else
484
     else
328
-      if( cmTextCmp(np->label,"backup") )
485
+      // if this is a 'backup' node
486
+      if( cmTextCmp(np->label,"backup") == 0 )
329
       {
487
       {
488
+        unsigned backup;
489
+        cmXmlNodeUInt(np,&backup,"duration",NULL);
490
+        tick -= backup;
330
       }
491
       }
492
+      else
493
+        // if this is a 'direction' node
494
+        if( cmTextCmp(np->label,"direction") == 0 )
495
+        {
496
+          rc = _cmXScoreParseDirection(p,meas,np,tick);
497
+        }
331
   
498
   
499
+  }
332
   
500
   
333
   return rc;
501
   return rc;
334
 }
502
 }
341
   
509
   
342
   // find the 'part'
510
   // find the 'part'
343
   if((xnp = cmXmlSearch( cmXmlRoot(p->xmlH), "part", &partAttr, 1)) == NULL )
511
   if((xnp = cmXmlSearch( cmXmlRoot(p->xmlH), "part", &partAttr, 1)) == NULL )
344
-    return _cmXScoreMissingNode(p,"part",&partAttr);
512
+    return cmErrMsg(&p->err,kSyntaxErrorXsRC,"The part '%s' was not found.",pp->idStr);
345
 
513
 
346
   // for each child of this part - find each measure
514
   // for each child of this part - find each measure
347
   const cmXmlNode_t* cnp = xnp->children;
515
   const cmXmlNode_t* cnp = xnp->children;
353
   return rc;
521
   return rc;
354
 }
522
 }
355
 
523
 
524
+cmXsNote_t*  _cmXScoreInsertSortedNote( cmXsNote_t* s0, cmXsNote_t* np )
525
+{
526
+  if( s0 == NULL )
527
+    return np;
528
+
529
+  if( np->tick < s0->tick )
530
+  {
531
+    np->slink = s0;
532
+    return np;
533
+  }
534
+
535
+  cmXsNote_t* s1 = s0;
536
+  cmXsNote_t* s2 = s0->slink;
537
+
538
+  while( s2 != NULL )
539
+  {
540
+    if( s2->tick > np->tick )
541
+    {
542
+      s1->slink = np;
543
+      np->slink = s2;
544
+      return s0;
545
+    }
546
+    
547
+    s1 = s2;
548
+    s2 = s2->slink;
549
+  }
550
+
551
+  s1->slink = np;
552
+  
553
+  return s0;
554
+}
555
+
556
+void _cmXScoreSort( cmXScore_t* p )
557
+{
558
+  cmXsPart_t* pp = p->partL;
559
+  for(; pp!=NULL; pp=pp->link)
560
+  {
561
+    cmXsMeas_t* mp = pp->measL;
562
+    for(; mp!=NULL; mp=mp->link)
563
+    {   
564
+      // for each voice in this measure
565
+      cmXsVoice_t* vp = mp->voiceL;
566
+      for(; vp!=NULL; vp=vp->link)
567
+      {
568
+        cmXsNote_t* np = vp->noteL;
569
+        for(; np!=NULL; np=np->mlink)
570
+          mp->noteL = _cmXScoreInsertSortedNote(mp->noteL,np);        
571
+      }      
572
+    }
573
+  }
574
+}
575
+
356
 cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn )
576
 cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn )
357
 {
577
 {
358
   cmXsRC_t rc = kOkXsRC;
578
   cmXsRC_t rc = kOkXsRC;
379
   if((rc = _cmXScoreParsePartList( p )) != kOkXsRC )
599
   if((rc = _cmXScoreParsePartList( p )) != kOkXsRC )
380
     goto errLabel;
600
     goto errLabel;
381
 
601
 
602
+  // parse each score 'part'
382
   cmXsPart_t* pp = p->partL;
603
   cmXsPart_t* pp = p->partL;
383
   for(; pp!=NULL; pp=pp->link)
604
   for(; pp!=NULL; pp=pp->link)
384
     if((rc = _cmXScoreParsePart(p,pp)) != kOkXsRC )
605
     if((rc = _cmXScoreParsePart(p,pp)) != kOkXsRC )
385
       goto errLabel;
606
       goto errLabel;
386
 
607
 
608
+  // fill in the note->slink chain to link the notes in each measure in time order
609
+  _cmXScoreSort(p); 
387
   
610
   
388
  errLabel:
611
  errLabel:
389
   if( rc != kOkXsRC )
612
   if( rc != kOkXsRC )
408
 
631
 
409
   hp->h = NULL;
632
   hp->h = NULL;
410
 
633
 
411
-  return rc;
412
-  
634
+  return rc;  
413
 }
635
 }
414
 
636
 
415
 
637
 
416
 bool     cmXScoreIsValid( cmXsH_t h )
638
 bool     cmXScoreIsValid( cmXsH_t h )
417
 { return h.h != NULL; }
639
 { return h.h != NULL; }
418
 
640
 
419
-void     cmXScoreReport( cmXsH_t h, cmRpt_t* rpt )
641
+void _cmXScoreReportNote( cmRpt_t* rpt, const cmXsNote_t* note )
642
+{
643
+  const cmChar_t* B = cmIsFlag(note->flags,kBarXsFl)       ? "|" : "-";
644
+  const cmChar_t* R = cmIsFlag(note->flags,kRestXsFl)      ? "R" : "-";
645
+  const cmChar_t* G = cmIsFlag(note->flags,kGraceXsFl)     ? "G" : "-";
646
+  const cmChar_t* D = cmIsFlag(note->flags,kDotXsFl)       ? "D" : "-";
647
+  const cmChar_t* C = cmIsFlag(note->flags,kChordXsFl)     ? "C" : "-";
648
+  const cmChar_t* e = cmIsFlag(note->flags,kEvenXsFl)      ? "e" : "-";
649
+  const cmChar_t* d = cmIsFlag(note->flags,kDynXsFl)       ? "d" : "-";
650
+  const cmChar_t* t = cmIsFlag(note->flags,kTempoXsFl)     ? "t" : "-";
651
+  const cmChar_t* P = cmIsFlag(note->flags,kPedalDnXsFl)   ? "V" : "-";
652
+  P = cmIsFlag(note->flags,kPedalUpXsFl)   ? "^" : P;
653
+  P = cmIsFlag(note->flags,kPedalUpDnXsFl) ? "X" : P;
654
+  const cmChar_t* N = note->pitch==0 ? " " : cmMidiToSciPitch( note->pitch, NULL, 0 );
655
+  cmRptPrintf(rpt,"      %5i %5i %2i %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);
656
+
657
+  if( cmIsFlag(note->flags,kSectionXsFl) )
658
+    cmRptPrintf(rpt," %i",note->rvalue);
659
+
660
+  printf("\n");
661
+  
662
+}
663
+
664
+void  cmXScoreReport( cmXsH_t h, cmRpt_t* rpt, bool sortFl )
420
 {
665
 {
421
   cmXScore_t* p = _cmXScoreHandleToPtr(h);
666
   cmXScore_t* p = _cmXScoreHandleToPtr(h);
422
 
667
 
427
 
672
 
428
     const cmXsMeas_t* meas = pp->measL;
673
     const cmXsMeas_t* meas = pp->measL;
429
     for(; meas!=NULL; meas=meas->link)
674
     for(; meas!=NULL; meas=meas->link)
675
+    {
430
       cmRptPrintf(rpt,"  %i : div:%i beat:%i beat-type:%i\n",meas->number,meas->divisions,meas->beats,meas->beat_type);
676
       cmRptPrintf(rpt,"  %i : div:%i beat:%i beat-type:%i\n",meas->number,meas->divisions,meas->beats,meas->beat_type);
431
-  }
432
-  
677
+
678
+      if( sortFl )
679
+      {
680
+        const cmXsNote_t* note = meas->noteL;
681
+        for(; note!=NULL; note=note->slink)
682
+          _cmXScoreReportNote(rpt,note);        
683
+      }
684
+      else
685
+      {
686
+      
687
+        const cmXsVoice_t* v = meas->voiceL;
688
+        for(; v!=NULL; v=v->link)
689
+        {        
690
+          const cmXsNote_t* note = v->noteL;
691
+          
692
+          cmRptPrintf(rpt,"    voice:%i\n",v->id);
693
+          
694
+          for(; note!=NULL; note=note->mlink)
695
+            _cmXScoreReportNote(rpt,note);
696
+        }
697
+      }      
698
+    }
699
+  }  
433
 }
700
 }
434
 
701
 
435
 
702
 
441
   if((rc = cmXScoreInitialize( ctx, &h, fn)) != kOkXsRC )
708
   if((rc = cmXScoreInitialize( ctx, &h, fn)) != kOkXsRC )
442
     return cmErrMsg(&ctx->err,rc,"XScore alloc failed.");
709
     return cmErrMsg(&ctx->err,rc,"XScore alloc failed.");
443
 
710
 
444
-  cmXScoreReport(h,&ctx->rpt);
711
+  cmXScoreReport(h,&ctx->rpt,true);
445
   
712
   
446
   return cmXScoreFinalize(&h);
713
   return cmXScoreFinalize(&h);
447
 
714
 

+ 6
- 4
app/cmXScore.h View File

7
 
7
 
8
   enum
8
   enum
9
   {
9
   {
10
-  kOkXsRC = cmOkRC,
10
+    kOkXsRC = cmOkRC,
11
     kXmlFailXsRC,
11
     kXmlFailXsRC,
12
     kLHeapFailXsRC,
12
     kLHeapFailXsRC,
13
     kSyntaxErrorXsRC
13
     kSyntaxErrorXsRC
14
-    };
14
+  };
15
 
15
 
16
   typedef cmRC_t     cmXsRC_t;
16
   typedef cmRC_t     cmXsRC_t;
17
   typedef cmHandle_t cmXsH_t;
17
   typedef cmHandle_t cmXsH_t;
25
   //       b. Emacs C-x <RET> f utf-8 <RET>
25
   //       b. Emacs C-x <RET> f utf-8 <RET>
26
   //
26
   //
27
   // 2) Replace "DoletSibelius Unknown Symbol Index" with "DoletSibelius unknownSymIdx"
27
   // 2) Replace "DoletSibelius Unknown Symbol Index" with "DoletSibelius unknownSymIdx"
28
-  
28
+  //
29
+  // 3) How to assigned dynamic markings.
30
+  // 4) Tempo syntax is inconsistent.
29
 
31
 
30
   cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn );
32
   cmXsRC_t cmXScoreInitialize( cmCtx_t* ctx, cmXsH_t* hp, const cmChar_t* xmlFn );
31
   cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );
33
   cmXsRC_t cmXScoreFinalize( cmXsH_t* hp );
32
 
34
 
33
   bool     cmXScoreIsValid( cmXsH_t h );
35
   bool     cmXScoreIsValid( cmXsH_t h );
34
 
36
 
35
-  void     cmXScoreReport( cmXsH_t h, cmRpt_t* rpt );
37
+  void     cmXScoreReport( cmXsH_t h, cmRpt_t* rpt, bool sortFl );
36
 
38
 
37
   cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* fn );
39
   cmXsRC_t cmXScoreTest( cmCtx_t* ctx, const cmChar_t* fn );
38
   
40
   

Loading…
Cancel
Save