Browse Source

cmScore.h/c Many changes added cmScoreLoc_t based data struct and functions.

The cmScoreLoc_t based functions still need to be debugged. See note on
_cmScoreInitLocArray().
master
kpl 11 years ago
parent
commit
c80368a549
2 changed files with 269 additions and 19 deletions
  1. 244
    14
      app/cmScore.c
  2. 25
    5
      app/cmScore.h

+ 244
- 14
app/cmScore.c View File

37
 
37
 
38
 enum
38
 enum
39
 {
39
 {
40
+  kMidiFileIdColScIdx= 0,  
40
   kTypeLabelColScIdx = 3,
41
   kTypeLabelColScIdx = 3,
41
-  kDSecsColScIdx     = 5,
42
+  kDSecsColScIdx     = 4,
43
+  kSecsColScIdx      = 5,
42
   kPitchColScIdx     = 11,
44
   kPitchColScIdx     = 11,
43
   kBarColScIdx       = 13,
45
   kBarColScIdx       = 13,
44
   kSkipColScIdx      = 14,
46
   kSkipColScIdx      = 14,
63
   cmScCb_t      cbFunc;
65
   cmScCb_t      cbFunc;
64
   void*         cbArg;
66
   void*         cbArg;
65
   cmChar_t*     fn;
67
   cmChar_t*     fn;
68
+  cmScoreLoc_t* loc;
69
+  unsigned      locCnt;
66
 } cmSc_t;
70
 } cmSc_t;
67
 
71
 
68
 cmScEvtRef_t _cmScEvtRefArray[] = 
72
 cmScEvtRef_t _cmScEvtRefArray[] = 
176
   if( cmCsvFinalize(&p->cH) != kOkCsvRC )
180
   if( cmCsvFinalize(&p->cH) != kOkCsvRC )
177
     return rc;
181
     return rc;
178
 
182
 
183
+  unsigned i;
184
+  for(i=0; i<p->locCnt; ++i)
185
+    cmMemFree(p->loc[i].evtArray);
186
+  cmMemFree(p->loc);
187
+
179
   cmMemFree(p->fn);
188
   cmMemFree(p->fn);
180
   cmMemFree(p->array);
189
   cmMemFree(p->array);
181
   cmMemFree(p);
190
   cmMemFree(p);
188
     return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to parse the bar number.");
197
     return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to parse the bar number.");
189
 
198
 
190
   s->type    = kBarEvtScId;
199
   s->type    = kBarEvtScId;
191
-  s->dsecs   = 0;
200
+  s->secs   = 0;
192
   s->barNumb = *barNumb;
201
   s->barNumb = *barNumb;
193
   return kOkScRC;
202
   return kOkScRC;
194
 }
203
 }
201
   const cmChar_t* sciPitch;
210
   const cmChar_t* sciPitch;
202
   cmMidiByte_t    midiPitch;
211
   cmMidiByte_t    midiPitch;
203
   const cmChar_t* attr;
212
   const cmChar_t* attr;
204
-  double          dsecs;
213
+  double          secs;
214
+  double          durSecs;
205
 
215
 
206
   if((sciPitch = cmCsvCellText(p->cH,rowIdx,kPitchColScIdx)) == NULL )
216
   if((sciPitch = cmCsvCellText(p->cH,rowIdx,kPitchColScIdx)) == NULL )
207
     return cmErrMsg(&p->err,kSyntaxErrScRC,"Expected a scientific pitch value");
217
     return cmErrMsg(&p->err,kSyntaxErrScRC,"Expected a scientific pitch value");
210
    return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to convert the scientific pitch '%s' to a MIDI value. ");
220
    return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to convert the scientific pitch '%s' to a MIDI value. ");
211
 
221
 
212
   // it is possible that note delta-secs field is empty - so default to 0
222
   // it is possible that note delta-secs field is empty - so default to 0
213
-  if((dsecs =  cmCsvCellDouble(p->cH, rowIdx, kDSecsColScIdx )) == DBL_MAX) // Returns DBL_MAX on error.
214
-    dsecs = 0;
223
+  if((secs =  cmCsvCellDouble(p->cH, rowIdx, kSecsColScIdx )) == DBL_MAX) // Returns DBL_MAX on error.
224
+    flags += kInvalidScFl;
215
 
225
 
216
   if((attr = cmCsvCellText(p->cH,rowIdx,kSkipColScIdx)) != NULL && *attr == 's' )
226
   if((attr = cmCsvCellText(p->cH,rowIdx,kSkipColScIdx)) != NULL && *attr == 's' )
217
     flags += kSkipScFl;
227
     flags += kSkipScFl;
230
     flags += kDynScFl;
240
     flags += kDynScFl;
231
   }
241
   }
232
 
242
 
243
+  // Returns DBL_MAX on error.
244
+  if((durSecs =  cmCsvCellDouble(p->cH, rowIdx, kDSecsColScIdx )) == DBL_MAX) 
245
+    durSecs = 0.25;
246
+
247
+
233
   s->type       = kNonEvtScId;
248
   s->type       = kNonEvtScId;
234
-  s->dsecs      = dsecs;
249
+  s->secs       = secs;
235
   s->pitch      = midiPitch;
250
   s->pitch      = midiPitch;
236
   s->flags      = flags;
251
   s->flags      = flags;
237
   s->dynVal     = dynVal; 
252
   s->dynVal     = dynVal; 
238
   s->barNumb    = barNumb;
253
   s->barNumb    = barNumb;
239
   s->barNoteIdx = barNoteIdx;
254
   s->barNoteIdx = barNoteIdx;
240
-
255
+  s->durSecs    = durSecs;
241
   return rc;
256
   return rc;
242
 }
257
 }
243
 
258
 
248
   int      barEvtIdx = cmInvalidIdx;
263
   int      barEvtIdx = cmInvalidIdx;
249
   int      barNumb   = 0;
264
   int      barNumb   = 0;
250
   double   secs;
265
   double   secs;
266
+  double   cur_secs = 0;
251
 
267
 
252
   if( cmCsvInitialize(&p->cH, ctx ) != kOkCsvRC )
268
   if( cmCsvInitialize(&p->cH, ctx ) != kOkCsvRC )
253
   {
269
   {
295
 
311
 
296
     switch(tid)
312
     switch(tid)
297
     {
313
     {
298
-      case kBarEvtScId:
299
-        // parse bar lines
314
+      case kBarEvtScId: // parse bar lines        
300
         if((rc = _cmScParseBar(p,i,p->array+j,&barNumb)) == kOkScRC )
315
         if((rc = _cmScParseBar(p,i,p->array+j,&barNumb)) == kOkScRC )
301
         {
316
         {
302
           barNoteIdx = 0;
317
           barNoteIdx = 0;
303
           barEvtIdx  = j;
318
           barEvtIdx  = j;
319
+          p->array[j].index = j;
304
           ++j;
320
           ++j;
305
         }
321
         }
306
         break;
322
         break;
307
 
323
 
308
-      case kNonEvtScId:
309
-        // parse note-on events
324
+      case kNonEvtScId:  // parse note-on events
310
         if((rc =  _cmScParseNoteOn(p, i, p->array + j, barNumb, barNoteIdx )) == kOkScRC )
325
         if((rc =  _cmScParseNoteOn(p, i, p->array + j, barNumb, barNoteIdx )) == kOkScRC )
311
         {
326
         {
312
-          secs = p->array[j].dsecs;
327
+          secs =  p->array[j].secs;
328
+
329
+          if( p->array[j].secs == DBL_MAX )
330
+            p->array[j].secs = cur_secs;
331
+
313
           if( cmIsFlag(p->array[j].flags,kSkipScFl) == false )
332
           if( cmIsFlag(p->array[j].flags,kSkipScFl) == false )
333
+          {
334
+            p->array[j].index = j;
314
             ++j;
335
             ++j;
336
+          }
315
 
337
 
316
           ++barNoteIdx;
338
           ++barNoteIdx;
317
         }
339
         }
319
 
341
 
320
       default:
342
       default:
321
         // Returns DBL_MAX on error.
343
         // Returns DBL_MAX on error.
322
-        secs =  cmCsvCellDouble(p->cH, i, kDSecsColScIdx );
344
+        secs =  cmCsvCellDouble(p->cH, i, kSecsColScIdx );
323
         break;
345
         break;
324
     }
346
     }
325
     
347
     
348
+    if( secs != DBL_MAX )
349
+      cur_secs = secs;
350
+
326
     // the bar lines don't have times so set the time of the bar line to the
351
     // the bar lines don't have times so set the time of the bar line to the
327
     // time of the first event in the bar.
352
     // time of the first event in the bar.
328
     if( barEvtIdx != cmInvalidIdx && secs != DBL_MAX )
353
     if( barEvtIdx != cmInvalidIdx && secs != DBL_MAX )
329
     {
354
     {
330
       assert( p->array[ barEvtIdx ].type == kBarEvtScId );
355
       assert( p->array[ barEvtIdx ].type == kBarEvtScId );
331
-      p->array[ barEvtIdx ].dsecs = secs;
356
+      p->array[ barEvtIdx ].secs = secs;
357
+
358
+      // handle the case where the previous bar had no events
359
+      if( p->array[ barEvtIdx-1].type == kBarEvtScId )
360
+        p->array[ barEvtIdx-1].secs = secs;
361
+
332
       barEvtIdx = cmInvalidIdx;
362
       barEvtIdx = cmInvalidIdx;
333
     }
363
     }
334
     
364
     
347
   return rc;
377
   return rc;
348
 }
378
 }
349
 
379
 
380
+// This function does not currently work because there is no
381
+// guarantee that all the time values (secs field) have been filled in 
382
+/// with valid times and that all event records have a valid 'type' id.
383
+cmScRC_t _cmScoreInitLocArray( cmSc_t* p )
384
+{
385
+  cmScRC_t rc       = kOkScRC;
386
+  double   minDSecs = 0;
387
+  unsigned barNumb  = 0;
388
+
389
+  if( p->cnt==0)
390
+    return rc;
391
+
392
+  p->locCnt = 1;
393
+
394
+  // count the number of unique time locations in the score
395
+  int i,j,k;
396
+  double secs = p->array[0].secs;
397
+  for(i=0; i<p->cnt; ++i)
398
+  {
399
+    assert( p->array[i].secs >= secs );
400
+
401
+    if( p->array[i].secs - secs <= minDSecs )
402
+    {
403
+      p->locCnt += 1;
404
+      secs = p->array[i].secs;
405
+    }
406
+  }
407
+
408
+  // allocate the loc. array
409
+  p->loc = cmMemAllocZ(cmScoreLoc_t,p->locCnt);
410
+
411
+  
412
+
413
+  // fill in the location array
414
+  for(i=0,k=0; i<p->cnt; ++k)
415
+  {
416
+    j = i+1;
417
+
418
+    assert(p->array[j].secs > p->array[i].secs );
419
+
420
+    // get the count of events at this location
421
+    while( j<p->cnt && p->array[j].secs - p->array[i].secs < minDSecs )
422
+      ++j;
423
+
424
+    assert(k<p->locCnt);
425
+
426
+    p->loc[k].evtCnt   = j-i;
427
+    p->loc[k].evtArray = cmMemAllocZ(cmScoreEvt_t*,p->loc[k].evtCnt);
428
+
429
+    // fill in the location record event pointers
430
+    for(j=0; j<p->loc[k].evtCnt; ++j)
431
+    {
432
+      p->loc[k].evtArray[j] = p->array + (i + j);
433
+
434
+      if( p->array[i+j].type == kBarEvtScId )
435
+        barNumb = p->array[i+j].barNumb;
436
+    }
437
+
438
+    // fill in the location record
439
+    p->loc[k].secs     = p->array[i].secs;
440
+    p->loc[k].evtIdx   = i;
441
+    p->loc[k].barNumb  = barNumb;
442
+
443
+    i += p->loc[k].evtCnt;
444
+
445
+  }
446
+
447
+  return rc;
448
+}
449
+
350
 cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, cmScCb_t cbFunc, void* cbArg )
450
 cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, cmScCb_t cbFunc, void* cbArg )
351
 {
451
 {
352
   cmScRC_t rc = kOkScRC;
452
   cmScRC_t rc = kOkScRC;
360
   if((rc = _cmScParseFile(p,ctx,fn)) != kOkScRC )
460
   if((rc = _cmScParseFile(p,ctx,fn)) != kOkScRC )
361
     goto errLabel;
461
     goto errLabel;
362
 
462
 
463
+  // See note at function
464
+  //if((rc = _cmScoreInitLocArray(p)) != kOkScRC )
465
+  //  goto errLabel;
466
+
363
   p->cbFunc = cbFunc;
467
   p->cbFunc = cbFunc;
364
   p->cbArg  = cbArg;
468
   p->cbArg  = cbArg;
365
   p->fn     = cmMemAllocStr(fn);
469
   p->fn     = cmMemAllocStr(fn);
416
   return p->array + idx;
520
   return p->array + idx;
417
 }
521
 }
418
 
522
 
523
+unsigned      cmScoreLocCount( cmScH_t h )
524
+{
525
+  cmSc_t* p = _cmScHandleToPtr(h);
526
+  return p->locCnt;
527
+}
528
+
529
+cmScoreLoc_t* cmScoreLoc( cmScH_t h, unsigned idx )
530
+{
531
+  cmSc_t* p = _cmScHandleToPtr(h);
532
+  if( idx >= p->locCnt )
533
+  {
534
+    cmErrMsg(&p->err,kInvalidIdxScRC,"%i is an invalid index for %i location records.",idx,p->locCnt);
535
+    return NULL;
536
+  }
537
+  return p->loc + idx;
538
+}
539
+
540
+
419
 cmScRC_t      cmScoreSeqNotify( cmScH_t h )
541
 cmScRC_t      cmScoreSeqNotify( cmScH_t h )
420
 {
542
 {
421
   cmScRC_t  rc = kOkScRC;
543
   cmScRC_t  rc = kOkScRC;
707
 
829
 
708
   cmScoreFinalize(&h);
830
   cmScoreFinalize(&h);
709
 }
831
 }
832
+
833
+// 1. Fix absolute message time which was incorrect on original score file.
834
+// 2. 
835
+void cmScoreFix( cmCtx_t* ctx )
836
+{
837
+  const cmChar_t*          mfn  = "/home/kevin/src/cmgv/src/gv/data/ImaginaryThemes.mid";
838
+  const cmChar_t*          crfn = "/home/kevin/src/cmgv/src/gv/data/mod0a.txt";
839
+  const cmChar_t*          cwfn = "/home/kevin/src/cmgv/src/gv/data/mod1.csv";
840
+  cmMidiFileH_t            mfH  = cmMidiFileNullHandle;
841
+  cmCsvH_t                 csvH = cmCsvNullHandle;
842
+  const cmMidiTrackMsg_t** msg  = NULL;
843
+  double                   secs = 0.0;
844
+  int                      ci,mi,crn,mn;
845
+  bool                     errFl = true;
846
+  unsigned                 handCnt = 0;
847
+  unsigned                 midiMissCnt = 0;
848
+
849
+  if( cmCsvInitialize(&csvH,ctx) != kOkCsvRC )
850
+    goto errLabel;
851
+
852
+  if( cmCsvLexRegisterMatcher(csvH, cmCsvLexNextAvailId(csvH), _cmScLexSciPitchMatcher ) != kOkCsvRC )
853
+    goto errLabel;
854
+
855
+  if( cmCsvParseFile(csvH, crfn, 0 ) != kOkCsvRC )
856
+    goto errLabel;
857
+
858
+  if( cmMidiFileOpen(mfn,&mfH,ctx) != kOkMfRC )
859
+    goto errLabel;
860
+
861
+  cmMidiFileTickToMicros(mfH);
862
+
863
+  cmMidiFileCalcNoteDurations(mfH);
864
+
865
+  mn = cmMidiFileMsgCount(mfH);
866
+
867
+  msg = cmMidiFileMsgArray(mfH);
868
+
869
+  crn = cmCsvRowCount(csvH);
870
+
871
+  // for each row in the score file
872
+  for(ci=1,mi=0; ci<crn && cmCsvLastRC(csvH)==kOkCsvRC; ++ci)
873
+  {
874
+    unsigned  id;
875
+
876
+    // zero the duration column 
877
+    if( cmCsvCellPtr(csvH, ci, kDSecsColScIdx ) != NULL )
878
+      cmCsvSetCellUInt(   csvH, ci, kDSecsColScIdx, 0 );
879
+
880
+    // get the MIDI file event id for this row
881
+    if((id = cmCsvCellUInt(csvH,ci,kMidiFileIdColScIdx)) == UINT_MAX)
882
+    {
883
+      // this is a hand-entered event -  so it has no event id
884
+      ++handCnt;
885
+      
886
+    }
887
+    else
888
+    {
889
+      for(; mi<mn; ++mi)
890
+      {
891
+        const cmMidiTrackMsg_t* m = msg[mi];
892
+
893
+        assert( mi+1 <= id );
894
+        secs += m->dtick/1000000.0;
895
+
896
+        if( mi+1 != id )
897
+        {
898
+          if( m->status == kNoteOnMdId && m->u.chMsgPtr->d1>0 )
899
+          {
900
+            // this MIDI note-on does not have a corresponding score event
901
+            ++midiMissCnt;
902
+          }
903
+        }
904
+        else
905
+        {
906
+          cmCsvSetCellDouble( csvH, ci, kSecsColScIdx, secs );
907
+          ++mi;
908
+
909
+          if( m->status == kNoteOnMdId )
910
+            cmCsvSetCellDouble(   csvH, ci, kDSecsColScIdx, m->u.chMsgPtr->durTicks/1000000.0 );
911
+          break;
912
+        }
913
+        
914
+        
915
+      }
916
+
917
+      if( mi==mn)
918
+        printf("done on row:%i\n",ci);
919
+    }
920
+  }
921
+
922
+  if( cmCsvLastRC(csvH) != kOkCsvRC )
923
+    goto errLabel;
924
+
925
+  if( cmCsvWrite(csvH,cwfn) != kOkCsvRC )
926
+    goto errLabel;
927
+
928
+  errFl = false;
929
+
930
+ errLabel:
931
+  if( errFl )
932
+    printf("Score fix failed.\n");
933
+  else
934
+    printf("Score fix done! hand:%i miss:%i\n",handCnt,midiMissCnt);
935
+  cmMidiFileClose(&mfH);
936
+
937
+  cmCsvFinalize(&csvH);
938
+
939
+}

+ 25
- 5
app/cmScore.h View File

34
 
34
 
35
   enum
35
   enum
36
   {
36
   {
37
-    kEvenScFl  = 0x01,  // This note is marked for evenness measurement
38
-    kDynScFl   = 0x02,  // This note is marked for dynamics measurement
39
-    kTempoScFl = 0x03,  // This note is marked for tempo measurement
40
-    kSkipScFl  = 0x04   // this isn't a real event (e.g. tied note) skip over it
37
+    kEvenScFl  = 0x01,   // This note is marked for evenness measurement
38
+    kDynScFl   = 0x02,   // This note is marked for dynamics measurement
39
+    kTempoScFl = 0x03,   // This note is marked for tempo measurement
40
+    kSkipScFl  = 0x04,   // This isn't a real event (e.g. tied note) skip over it
41
+    kInvalidScFl = 0x08  // This note has a calculated time
41
   };
42
   };
42
 
43
 
43
   typedef struct
44
   typedef struct
44
   {
45
   {
45
     unsigned     type;         // Event type
46
     unsigned     type;         // Event type
46
-    double       dsecs;        // 
47
+    double       secs;         // Time location in seconds 
48
+    double       durSecs;      // Duration in seconds
49
+    unsigned     index;        // index of this event
47
     cmMidiByte_t pitch;        // MIDI pitch of this note
50
     cmMidiByte_t pitch;        // MIDI pitch of this note
48
     unsigned     flags;        // Attribute flags for this event
51
     unsigned     flags;        // Attribute flags for this event
49
     unsigned     dynVal;       // Dynamcis value pppp to ffff (1 to 11) for this note.
52
     unsigned     dynVal;       // Dynamcis value pppp to ffff (1 to 11) for this note.
51
     unsigned     barNoteIdx;   // index of this note in this bar
54
     unsigned     barNoteIdx;   // index of this note in this bar
52
   } cmScoreEvt_t;
55
   } cmScoreEvt_t;
53
 
56
 
57
+  typedef struct
58
+  {
59
+    double         secs;     // Time of this location
60
+    unsigned       evtCnt;   // Count of events in evtArray[].
61
+    cmScoreEvt_t** evtArray; // Events which occur at this time.
62
+    unsigned       evtIdx;   // Index into the master event array 
63
+                             // (p->array[]) of the first event in this loc.
64
+    unsigned       barNumb;  // Bar number this event is contained by.
65
+                            
66
+  } cmScoreLoc_t;
67
+
54
   typedef void (*cmScCb_t)( void* arg, const void* data, unsigned byteCnt );
68
   typedef void (*cmScCb_t)( void* arg, const void* data, unsigned byteCnt );
55
 
69
 
56
   typedef cmRC_t     cmScRC_t;
70
   typedef cmRC_t     cmScRC_t;
77
   unsigned      cmScoreEvtCount( cmScH_t h );
91
   unsigned      cmScoreEvtCount( cmScH_t h );
78
   cmScoreEvt_t* cmScoreEvt( cmScH_t h, unsigned idx );
92
   cmScoreEvt_t* cmScoreEvt( cmScH_t h, unsigned idx );
79
 
93
 
94
+  // Access the score location data
95
+  unsigned      cmScoreLocCount( cmScH_t h );
96
+  cmScoreLoc_t* cmScoreLoc( cmScH_t h, unsigned idx );
97
+
80
 
98
 
81
   cmScRC_t      cmScoreSeqNotify( cmScH_t h );
99
   cmScRC_t      cmScoreSeqNotify( cmScH_t h );
82
   
100
   
104
 
122
 
105
   void          cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn );
123
   void          cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn );
106
 
124
 
125
+  void          cmScoreFix( cmCtx_t* ctx );
126
+
107
 #ifdef __cplusplus
127
 #ifdef __cplusplus
108
 }
128
 }
109
 #endif
129
 #endif

Loading…
Cancel
Save