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,8 +37,10 @@ enum
37 37
 
38 38
 enum
39 39
 {
40
+  kMidiFileIdColScIdx= 0,  
40 41
   kTypeLabelColScIdx = 3,
41
-  kDSecsColScIdx     = 5,
42
+  kDSecsColScIdx     = 4,
43
+  kSecsColScIdx      = 5,
42 44
   kPitchColScIdx     = 11,
43 45
   kBarColScIdx       = 13,
44 46
   kSkipColScIdx      = 14,
@@ -63,6 +65,8 @@ typedef struct
63 65
   cmScCb_t      cbFunc;
64 66
   void*         cbArg;
65 67
   cmChar_t*     fn;
68
+  cmScoreLoc_t* loc;
69
+  unsigned      locCnt;
66 70
 } cmSc_t;
67 71
 
68 72
 cmScEvtRef_t _cmScEvtRefArray[] = 
@@ -176,6 +180,11 @@ cmScRC_t _cmScFinalize( cmSc_t* p )
176 180
   if( cmCsvFinalize(&p->cH) != kOkCsvRC )
177 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 188
   cmMemFree(p->fn);
180 189
   cmMemFree(p->array);
181 190
   cmMemFree(p);
@@ -188,7 +197,7 @@ cmScRC_t _cmScParseBar( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, int* barNum
188 197
     return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to parse the bar number.");
189 198
 
190 199
   s->type    = kBarEvtScId;
191
-  s->dsecs   = 0;
200
+  s->secs   = 0;
192 201
   s->barNumb = *barNumb;
193 202
   return kOkScRC;
194 203
 }
@@ -201,7 +210,8 @@ cmScRC_t _cmScParseNoteOn( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, int barN
201 210
   const cmChar_t* sciPitch;
202 211
   cmMidiByte_t    midiPitch;
203 212
   const cmChar_t* attr;
204
-  double          dsecs;
213
+  double          secs;
214
+  double          durSecs;
205 215
 
206 216
   if((sciPitch = cmCsvCellText(p->cH,rowIdx,kPitchColScIdx)) == NULL )
207 217
     return cmErrMsg(&p->err,kSyntaxErrScRC,"Expected a scientific pitch value");
@@ -210,8 +220,8 @@ cmScRC_t _cmScParseNoteOn( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, int barN
210 220
    return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to convert the scientific pitch '%s' to a MIDI value. ");
211 221
 
212 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 226
   if((attr = cmCsvCellText(p->cH,rowIdx,kSkipColScIdx)) != NULL && *attr == 's' )
217 227
     flags += kSkipScFl;
@@ -230,14 +240,19 @@ cmScRC_t _cmScParseNoteOn( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, int barN
230 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 248
   s->type       = kNonEvtScId;
234
-  s->dsecs      = dsecs;
249
+  s->secs       = secs;
235 250
   s->pitch      = midiPitch;
236 251
   s->flags      = flags;
237 252
   s->dynVal     = dynVal; 
238 253
   s->barNumb    = barNumb;
239 254
   s->barNoteIdx = barNoteIdx;
240
-
255
+  s->durSecs    = durSecs;
241 256
   return rc;
242 257
 }
243 258
 
@@ -248,6 +263,7 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn )
248 263
   int      barEvtIdx = cmInvalidIdx;
249 264
   int      barNumb   = 0;
250 265
   double   secs;
266
+  double   cur_secs = 0;
251 267
 
252 268
   if( cmCsvInitialize(&p->cH, ctx ) != kOkCsvRC )
253 269
   {
@@ -295,23 +311,29 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn )
295 311
 
296 312
     switch(tid)
297 313
     {
298
-      case kBarEvtScId:
299
-        // parse bar lines
314
+      case kBarEvtScId: // parse bar lines        
300 315
         if((rc = _cmScParseBar(p,i,p->array+j,&barNumb)) == kOkScRC )
301 316
         {
302 317
           barNoteIdx = 0;
303 318
           barEvtIdx  = j;
319
+          p->array[j].index = j;
304 320
           ++j;
305 321
         }
306 322
         break;
307 323
 
308
-      case kNonEvtScId:
309
-        // parse note-on events
324
+      case kNonEvtScId:  // parse note-on events
310 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 332
           if( cmIsFlag(p->array[j].flags,kSkipScFl) == false )
333
+          {
334
+            p->array[j].index = j;
314 335
             ++j;
336
+          }
315 337
 
316 338
           ++barNoteIdx;
317 339
         }
@@ -319,16 +341,24 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn )
319 341
 
320 342
       default:
321 343
         // Returns DBL_MAX on error.
322
-        secs =  cmCsvCellDouble(p->cH, i, kDSecsColScIdx );
344
+        secs =  cmCsvCellDouble(p->cH, i, kSecsColScIdx );
323 345
         break;
324 346
     }
325 347
     
348
+    if( secs != DBL_MAX )
349
+      cur_secs = secs;
350
+
326 351
     // the bar lines don't have times so set the time of the bar line to the
327 352
     // time of the first event in the bar.
328 353
     if( barEvtIdx != cmInvalidIdx && secs != DBL_MAX )
329 354
     {
330 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 362
       barEvtIdx = cmInvalidIdx;
333 363
     }
334 364
     
@@ -347,6 +377,76 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn )
347 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 450
 cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, cmScCb_t cbFunc, void* cbArg )
351 451
 {
352 452
   cmScRC_t rc = kOkScRC;
@@ -360,6 +460,10 @@ cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, cmScC
360 460
   if((rc = _cmScParseFile(p,ctx,fn)) != kOkScRC )
361 461
     goto errLabel;
362 462
 
463
+  // See note at function
464
+  //if((rc = _cmScoreInitLocArray(p)) != kOkScRC )
465
+  //  goto errLabel;
466
+
363 467
   p->cbFunc = cbFunc;
364 468
   p->cbArg  = cbArg;
365 469
   p->fn     = cmMemAllocStr(fn);
@@ -416,6 +520,24 @@ cmScoreEvt_t* cmScoreEvt( cmScH_t h, unsigned idx )
416 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 541
 cmScRC_t      cmScoreSeqNotify( cmScH_t h )
420 542
 {
421 543
   cmScRC_t  rc = kOkScRC;
@@ -707,3 +829,111 @@ void cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn )
707 829
 
708 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,16 +34,19 @@ extern "C" {
34 34
 
35 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 44
   typedef struct
44 45
   {
45 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 50
     cmMidiByte_t pitch;        // MIDI pitch of this note
48 51
     unsigned     flags;        // Attribute flags for this event
49 52
     unsigned     dynVal;       // Dynamcis value pppp to ffff (1 to 11) for this note.
@@ -51,6 +54,17 @@ extern "C" {
51 54
     unsigned     barNoteIdx;   // index of this note in this bar
52 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 68
   typedef void (*cmScCb_t)( void* arg, const void* data, unsigned byteCnt );
55 69
 
56 70
   typedef cmRC_t     cmScRC_t;
@@ -77,6 +91,10 @@ extern "C" {
77 91
   unsigned      cmScoreEvtCount( cmScH_t h );
78 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 99
   cmScRC_t      cmScoreSeqNotify( cmScH_t h );
82 100
   
@@ -104,6 +122,8 @@ extern "C" {
104 122
 
105 123
   void          cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn );
106 124
 
125
+  void          cmScoreFix( cmCtx_t* ctx );
126
+
107 127
 #ifdef __cplusplus
108 128
 }
109 129
 #endif

Loading…
Cancel
Save