Browse Source

cmTakeSeqBldr.c : Completed cmTakeSeqBldrLoadTake() and cmTakeSeqBldrUnloadTake().

master
Kevin Larke 9 years ago
parent
commit
d60eb3c0da
1 changed files with 190 additions and 97 deletions
  1. 190
    97
      app/cmTakeSeqBldr.c

+ 190
- 97
app/cmTakeSeqBldr.c View File

@@ -31,9 +31,11 @@ typedef struct cmScTrkMidiTsb_str
31 31
 // Score Tracking info. from a single take (time-line marker)
32 32
 typedef struct cmScTrkTakeTsb_str
33 33
 {
34
-  unsigned          markerUid;  // marker time line uid assoc'd with this take
34
+  unsigned          tlMarkerUid;  // marker time line uid assoc'd with this take
35 35
   cmScTrkMidiTsb_t* midiV;      // midiV[midiN] score to midi file map recd. array.
36
-  unsigned          midiN;  
36
+  unsigned          midiN; 
37
+  unsigned          minMuid;    // min MIDI muid in midiV[]
38
+  unsigned          maxMuid;    // max MIDI muid in midiV[]
37 39
   bool              failFl;
38 40
 } cmScTrkTakeTsb_t;
39 41
 
@@ -45,35 +47,28 @@ enum
45 47
 };
46 48
 
47 49
 // 
48
-typedef struct cmMidiEvt_str
50
+typedef struct cmMidiTsb_str
49 51
 {  
50 52
   unsigned              srcId;     // marker uid or -1 if this event was manually inserted
53
+  unsigned              scEvtIdx;  // score event assocd with this midi event
51 54
   unsigned              flags;     // note | pedal | enable  
52
-  struct cmMidiEvt_str* ref;       // previous MIDI event in time
55
+  struct cmMidiTsb_str* ref;       // previous MIDI event in time
53 56
   unsigned              offsetSmp; // time offset from *ref
54 57
   unsigned              durSmp;    // duration of this MIDI event
55 58
   unsigned              d0;        // d0 MIDI channel msg data.
56 59
   unsigned              d1;        // d1 MIDI channel msg data
57
-  struct cmMidiEvt_str* link;      // pointer to next MIDI event in list
58
-} cmMidiEvt_t;
59
-
60
-// This record represents a note or pedal score event 
61
-typedef struct cmScEvtTsb_str
62
-{
63
-  unsigned     flags;    // note | pedal
64
-  unsigned     scEvtIdx; // score event index (into scH)
65
-  cmMidiEvt_t* evtList;  // list of alternate MIDI events which may render this event
66
-} cmScEvtTsb_t;
60
+  struct cmMidiTsb_str* link;      // pointer to next MIDI event in list
61
+} cmMidiTsb_t;
67 62
 
68 63
 // This record contains all the score events and and score synchronized MIDI events
69 64
 // associated with a given take.  Each call to cmTakeSeqBldrLoadTake() creates
70 65
 // one of these records.
71
-typedef struct cmTakeScEvtArrayTsb_str
66
+typedef struct cmTakeTsb_str
72 67
 {
73
-  unsigned      tlMarkerUid; // time-line marker uid associated with this take
74
-  cmScEvtTsb_t* scEvtV;      // scEvtV[scEvtN] array of score events contained by this take  
75
-  unsigned      scEvtN;      // count of score events in this take 
76
-} cmTakeScEvtArrayTsb_t;
68
+  unsigned              tlMarkerUid; // time-line marker uid associated with this take
69
+  cmMidiTsb_t*          midi;        // midi events contained by this take  
70
+  struct cmTakeTsb_str* link;
71
+} cmTakeTsb_t;
77 72
 
78 73
 typedef struct
79 74
 {
@@ -89,10 +84,10 @@ typedef struct
89 84
   cmScTrkTakeTsb_t*  scTrkTakeV;  // score tracker scTrkTakeV[ scTrkTakeN ]
90 85
   unsigned           scTrkTakeN;  
91 86
   
92
-  cmTakeScEvtArrayTsb_t* takes;   // list of scEvt arrays used by this sequence 
93
-  cmTakeScEvtArrayTsb_t* manual;  // list of manually inserted MIDI events
87
+  cmTakeTsb_t* takes;   // list of loaded takes 
88
+  cmTakeTsb_t* manual;  // list of manually inserted MIDI events
94 89
   
95
-  cmTakeScEvtArrayTsb_t* out;     // render list
90
+  cmTakeTsb_t* out;     // render list
96 91
 
97 92
 } cmTsb_t;
98 93
 
@@ -134,6 +129,44 @@ cmTsbRC_t _cmTsbScoreTrkFree( cmTsb_t* p )
134 129
 }
135 130
 
136 131
 
132
+// Free a take record. Note that the record must be unlinked
133
+// unlinked from p->takes (See _cmTakeTsbUnlink().) prior to calling this function.
134
+void _cmTsbTakeFree( cmTsb_t* p, cmTakeTsb_t* t )
135
+{
136
+  cmMidiTsb_t* m  = t->midi;
137
+    
138
+  while( m != NULL )
139
+  {
140
+    cmMidiTsb_t* nm = m->link;
141
+    cmMemFree(m);
142
+    m = nm;
143
+  }
144
+  
145
+  cmMemFree(t);
146
+}
147
+
148
+// Unlink a 'take' record from p->takes.
149
+cmTakeTsb_t*  _cmTsbTakeUnlink( cmTsb_t* p, cmTakeTsb_t* t )
150
+{
151
+  cmTakeTsb_t* t0 = NULL;
152
+  cmTakeTsb_t* t1 = p->takes;
153
+
154
+  while( t1 != NULL )
155
+  {
156
+    if( t1 == t )
157
+    {
158
+      if( t0 == NULL )
159
+        p->takes = t->link;
160
+      else
161
+        t0->link = t1->link;
162
+
163
+      return t;
164
+    }
165
+  }
166
+  return NULL;
167
+}
168
+
169
+
137 170
 cmTsbRC_t _cmTsbFree( cmTsb_t* p )
138 171
 {
139 172
   cmTsbRC_t rc     = kOkTsbRC;
@@ -141,12 +174,39 @@ cmTsbRC_t _cmTsbFree( cmTsb_t* p )
141 174
   if((rc = _cmTsbScoreTrkFree(p)) != kOkTsbRC )
142 175
     goto errLabel;
143 176
 
177
+  cmTakeTsb_t* t = p->takes;
178
+  
179
+  while( t != NULL )
180
+  {
181
+    cmTakeTsb_t* nt = t->link;
182
+    _cmTsbTakeFree(p,t);
183
+    t = nt;
184
+  }
185
+
144 186
   cmMemFree(p);
145 187
 
146 188
  errLabel:
147 189
   return rc;
148 190
 }
149 191
 
192
+cmScTrkTakeTsb_t* _cmTsbMarkerIdToScTrkTake( cmTsb_t* p, unsigned markerUid )
193
+{
194
+  unsigned i;
195
+  for(i=0; p->scTrkTakeN; ++i)
196
+    if( p->scTrkTakeV[i].tlMarkerUid == markerUid )
197
+      return p->scTrkTakeV + i;
198
+  return NULL;
199
+}
200
+
201
+cmScTrkMidiTsb_t* _cmTsbMuidToScTrkMidi( cmScTrkTakeTsb_t* t, unsigned muid )
202
+{
203
+  unsigned i;
204
+  for(i=0; i<t->midiN; ++i)
205
+    if( t->midiV[i].muid == muid )
206
+      return t->midiV + i;
207
+  return NULL;
208
+}
209
+
150 210
 
151 211
 cmTsbRC_t _cmTsbLoadScoreTrkFile( cmTsb_t* p, const cmChar_t* scoreTrkFn )
152 212
 {
@@ -188,9 +248,10 @@ cmTsbRC_t _cmTsbLoadScoreTrkFile( cmTsb_t* p, const cmChar_t* scoreTrkFn )
188 248
   // for each take record
189 249
   for(i=0; i<p->scTrkTakeN; ++i)
190 250
   {
191
-    cmJsonNode_t* takeObj    = NULL;
192
-    cmJsonNode_t* noteArrObj = NULL;
193
-    unsigned      j;
251
+    cmJsonNode_t*     takeObj    = NULL;
252
+    cmJsonNode_t*     noteArrObj = NULL;
253
+    cmScTrkTakeTsb_t* t          = p->scTrkTakeV + i;
254
+    unsigned          j;
194 255
 
195 256
     // get a pointer to the take record JSON object
196 257
     if((takeObj = cmJsonArrayElement(tkArrObj,i)) == NULL )
@@ -201,8 +262,8 @@ cmTsbRC_t _cmTsbLoadScoreTrkFile( cmTsb_t* p, const cmChar_t* scoreTrkFn )
201 262
 
202 263
     // parse the take record
203 264
     if((jsRC = cmJsonMemberValues( takeObj, &errMsg,
204
-          "markerUid",kIntTId,   &p->scTrkTakeV[i].markerUid,
205
-          "failFl",   kIntTId,   &p->scTrkTakeV[i].failFl,
265
+          "markerUid",kIntTId,   &t->tlMarkerUid,
266
+          "failFl",   kIntTId,   &t->failFl,
206 267
           "array",    kArrayTId, &noteArrObj,
207 268
           NULL)) != kOkJsRC )
208 269
     {
@@ -215,13 +276,15 @@ cmTsbRC_t _cmTsbLoadScoreTrkFile( cmTsb_t* p, const cmChar_t* scoreTrkFn )
215 276
     }
216 277
 
217 278
     // get the count of note records
218
-    p->scTrkTakeV[i].midiN = cmJsonChildCount(noteArrObj);
279
+    t->midiN = cmJsonChildCount(noteArrObj);
219 280
     
220 281
     // allocate a note record array for this take
221
-    p->scTrkTakeV[i].midiV = cmMemAllocZ(cmScTrkMidiTsb_t, p->scTrkTakeV[i].midiN);
282
+    t->midiV = cmMemAllocZ(cmScTrkMidiTsb_t, t->midiN);
283
+    t->minMuid =  INT_MAX;
284
+    t->maxMuid =  0;
222 285
 
223 286
     // for each note record
224
-    for(j=0; j<p->scTrkTakeV[i].midiN; ++j)
287
+    for(j=0; j<t->midiN; ++j)
225 288
     {
226 289
       cmJsonNode_t* noteObj = NULL;
227 290
       
@@ -234,10 +297,10 @@ cmTsbRC_t _cmTsbLoadScoreTrkFile( cmTsb_t* p, const cmChar_t* scoreTrkFn )
234 297
 
235 298
       // parse the note record
236 299
       if((jsRC = cmJsonMemberValues( noteObj, &errMsg,
237
-            "mni",      kIntTId, &p->scTrkTakeV[i].midiV[j].mni,
238
-            "muid",     kIntTId, &p->scTrkTakeV[i].midiV[j].muid,
239
-            "scEvtIdx", kIntTId, &p->scTrkTakeV[i].midiV[j].scEvtIdx,
240
-            "flags",    kIntTId, &p->scTrkTakeV[i].midiV[j].flags,
300
+            "mni",      kIntTId, &t->midiV[j].mni,
301
+            "muid",     kIntTId, &t->midiV[j].muid,
302
+            "scEvtIdx", kIntTId, &t->midiV[j].scEvtIdx,
303
+            "flags",    kIntTId, &t->midiV[j].flags,
241 304
             NULL)) != kOkJsRC )
242 305
       {
243 306
         if( jsRC == kNodeNotFoundJsRC && errMsg != NULL )
@@ -247,6 +310,13 @@ cmTsbRC_t _cmTsbLoadScoreTrkFile( cmTsb_t* p, const cmChar_t* scoreTrkFn )
247 310
 
248 311
         goto errLabel;
249 312
       }
313
+
314
+      if( t->midiV[j].muid < t->minMuid )
315
+        t->minMuid = t->midiV[j].muid;
316
+
317
+      if( t->midiV[j].muid > t->maxMuid )
318
+        t->maxMuid = t->midiV[j].muid;
319
+
250 320
     }
251 321
   }
252 322
 
@@ -257,31 +327,6 @@ cmTsbRC_t _cmTsbLoadScoreTrkFile( cmTsb_t* p, const cmChar_t* scoreTrkFn )
257 327
   return rc;
258 328
 }
259 329
 
260
-// Return the count of score events inside a given marker.
261
-unsigned _cmTsbScoreTrkMarkerEventCount( cmTsb_t* p, unsigned markUid )
262
-{
263
-  unsigned i,j;
264
-  unsigned minScEvtIdx = INT_MAX;
265
-  unsigned maxScEvtIdx = 0;
266
-
267
-  for(i=0; i<p->scTrkTakeN; ++i)
268
-    for(j=0; j<p->scTrkTakeV[i].midiN; ++j)
269
-      if( p->scTrkTakeV[i].midiV[j].scEvtIdx != cmInvalidIdx )
270
-      {
271
-        if( p->scTrkTakeV[i].midiV[j].scEvtIdx < minScEvtIdx )
272
-          minScEvtIdx = p->scTrkTakeV[i].midiV[j].scEvtIdx;
273
-        
274
-        if( p->scTrkTakeV[i].midiV[j].scEvtIdx > maxScEvtIdx )
275
-          maxScEvtIdx = p->scTrkTakeV[i].midiV[j].scEvtIdx;
276
-      }
277
-
278
-  if( maxScEvtIdx < minScEvtIdx )
279
-    return 0;
280
-
281
-  return (maxScEvtIdx - minScEvtIdx) + 1;
282
-  
283
-}
284
-
285 330
 cmTsbRC_t cmTakeSeqBldrAlloc( cmCtx_t* ctx, cmTakeSeqBldrH_t* hp )
286 331
 {
287 332
   cmTsbRC_t rc;
@@ -359,6 +404,15 @@ cmTsbRC_t cmTakeSeqBldrInitialize( cmTakeSeqBldrH_t h, const cmChar_t* scoreTrkF
359 404
   return rc;
360 405
 }
361 406
 
407
+cmTakeTsb_t* _cmTsbMarkerUidToTake( cmTsb_t* p, unsigned tlMarkerUid )
408
+{
409
+  cmTakeTsb_t* t = p->takes;
410
+  for(; t != NULL; t=t->link)
411
+    if( t->tlMarkerUid == tlMarkerUid )
412
+      return t;
413
+  return NULL;
414
+}
415
+
362 416
 cmTsbRC_t cmTakeSeqBldrLoadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool overwriteFL )
363 417
 {
364 418
   cmTsbRC_t       rc   = kOkTsbRC;
@@ -366,26 +420,28 @@ cmTsbRC_t cmTakeSeqBldrLoadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool ov
366 420
   cmTlMarker_t*   mark = NULL;
367 421
   cmTlMidiFile_t* mf   = NULL;
368 422
   cmMidiFileH_t   mfH  = cmMidiFileNullHandle;
369
-  unsigned        scEvtN = 0; 
370
-  cmScEvtTsb_t*   scEvtV = NULL;
423
+  cmScTrkTakeTsb_t* stt = NULL;
371 424
 
372
-  // get a pointer to the time-line marker object
373
-  if((mark = cmTlMarkerObjPtr( p->tlH, cmTimeLineIdToObj( p->tlH, cmInvalidId, tlMarkUid))) == NULL )
425
+  // verify that the requested take has not already been loaded
426
+  if( _cmTsbMarkerUidToTake( p, tlMarkUid ) != NULL )
374 427
   {
375
-    rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The time-line marker uid '%i' is not valid.",tlMarkUid);
428
+    rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The take indicated by marker id %i has already been loaded.",tlMarkUid );
376 429
     goto errLabel;
377 430
   }
378 431
 
379
-  // get the count of score events in the take marker
380
-  if((scEvtN = _cmTsbScoreTrkMarkerEventCount(p,tlMarkUid)) == 0 )
432
+  // find the score tracked take for the requested marker
433
+  if((stt = _cmTsbMarkerIdToScTrkTake(p,tlMarkUid )) == NULL )
381 434
   {
382
-    rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The selected take marker does not appear to contain any score events.");
435
+    rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The score tracked take indicated by marker id %i could not be found.", tlMarkUid );
383 436
     goto errLabel;
384 437
   }
385 438
 
386
-  // allocate a score event array
387
-  scEvtV = cmMemAllocZ(cmScEvtTsb_t,scEvtN);
388
-  
439
+  // get a pointer to the time-line marker object
440
+  if((mark = cmTlMarkerObjPtr( p->tlH, cmTimeLineIdToObj( p->tlH, cmInvalidId, tlMarkUid))) == NULL )
441
+  {
442
+    rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"The time-line marker uid '%i' is not valid.",tlMarkUid);
443
+    goto errLabel;
444
+  }
389 445
 
390 446
   // get the name of the MIDI file which contains the marker
391 447
   if((mf = cmTimeLineMidiFileAtTime( p->tlH, mark->obj.seqId, mark->obj.seqSmpIdx )) == NULL )
@@ -407,56 +463,93 @@ cmTsbRC_t cmTakeSeqBldrLoadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid, bool ov
407 463
   // calculate MIDI note and pedal durations (see cmMidiChMsg_t.durTicks)
408 464
   cmMidiFileCalcNoteDurations( mfH );
409 465
   
410
-  // convert the marker beg/end sample position to be relative to the MIDI file start time
411
-  unsigned                 bsi = mark->obj.seqSmpIdx - mf->obj.seqSmpIdx;
412
-  unsigned                 esi = mark->obj.seqSmpIdx + mark->obj.durSmpCnt - mf->obj.seqSmpIdx;
413 466
   unsigned                 i   = 0;
414 467
   unsigned                 n   = cmMidiFileMsgCount(mfH);
415 468
   const cmMidiTrackMsg_t** a   = cmMidiFileMsgArray(mfH);
416 469
   
417
-  // seek to the first MIDI msg after sample index bsi in the MIDI file
418
-  for(i=0; i<n; ++i)
419
-    if( a[i]->dtick >= bsi )
420
-      break;
470
+  // allocate and link a new take render record
471
+  cmTakeTsb_t* t = cmMemAllocZ(cmTakeTsb_t,1);
472
+
473
+  t->tlMarkerUid = tlMarkUid;
474
+  if( p->takes != NULL )
475
+    p->takes->link = t;
476
+
477
+  p->takes = t;
421 478
 
422
-  // if bsi is after the file then the MIDI file finished before the marker
423
-  if( i == n )
424
-  {
425
-    rc = cmErrMsg(&p->err,kInvalidArgTsbRC,"No MIDI events were found in the marker.");
426
-    goto errLabel;
427
-  }
428 479
 
429
-  // for each MIDI message between bsi and esi
430
-  for(; i<n && a[i]->dtick < esi; ++i)
480
+  cmMidiTsb_t*            m0  = NULL;
481
+  const cmMidiTrackMsg_t* mf0 = NULL;
482
+
483
+  // for each MIDI message in the file 
484
+  for(i=0; i<n; ++i)
431 485
   {
432
-    const cmMidiTrackMsg_t* m = a[i];
433
-    switch( m->status )
486
+    const cmMidiTrackMsg_t* mf1 = a[i];
487
+
488
+    // we are only interested in rendering notes and control msgs
489
+    switch( mf1->status )
434 490
     {
435
-      case kNoteOffMdId:
436 491
       case kNoteOnMdId:
437
-      case kCtlMdId:
438
-        
492
+      case kNoteOffMdId:
493
+      case kCtlMdId:        
439 494
         break;
495
+
496
+      default:
497
+        continue;
440 498
     }
441
-  }
499
+    
500
+    // if this MIDI message is inside the tracked region of the take
501
+    if( stt->minMuid > mf1->uid || mf1->uid > stt->maxMuid )
502
+      continue;
442 503
 
504
+    // get a pointer to the tracking map
505
+    cmScTrkMidiTsb_t* stm = _cmTsbMuidToScTrkMidi(stt, mf1->uid );
443 506
 
507
+    // create a MIDI render event 
508
+    cmMidiTsb_t* m1 = cmMemAllocZ(cmMidiTsb_t,1);
509
+      
510
+    m1->srcId     = tlMarkUid;
511
+    m1->scEvtIdx  = stm != NULL ? stm->scEvtIdx : cmInvalidIdx;
512
+    m1->flags     = stm != NULL ? stm->flags    : 0;
513
+    m1->ref       = m0;
514
+    m1->offsetSmp = mf0 == NULL ? 0 : mf1->dtick - mf0->dtick;
515
+    m1->durSmp    = mf1->u.chMsgPtr->durTicks;
516
+    m1->d0        = mf1->u.chMsgPtr->d0;
517
+    m1->d1        = mf1->u.chMsgPtr->d1;
518
+    m1->link      = NULL;
519
+
520
+    if( m0 != NULL )
521
+      m0->link      = m1;
522
+    
523
+    if( t->midi == NULL )
524
+      t->midi = m1;
525
+
526
+    m0  = m1;
527
+    mf0 = mf1;
528
+
529
+  }
444 530
   
445 531
  errLabel:
446 532
   if( cmMidiFileClose(&mfH) != kOkMfRC )
447 533
     rc = cmErrMsg(&p->err,kMidiFileFailTsbRC,"MIDI file close failed.");
448 534
   
449
-  if( rc != kOkTsbRC )
450
-  {
451
-    cmMemFree(scEvtV);
452
-  }
453
-
454 535
   return rc;
455 536
 }
456 537
 
457 538
 cmTsbRC_t cmTakeSeqBldrUnloadTake( cmTakeSeqBldrH_t h, unsigned tlMarkUid )
458 539
 {
459
-  cmTsbRC_t rc = kOkTsbRC;
540
+  cmTsbRC_t    rc = kOkTsbRC;
541
+  cmTsb_t*     p  = _cmTsbHandleToPtr(h);
542
+  cmTakeTsb_t* t;
543
+
544
+  if((t = _cmTsbMarkerUidToTake(p, tlMarkUid )) == NULL )
545
+    return cmErrMsg(&p->err,kInvalidArgTsbRC,"The take indicated by marker id %i could not be found.",tlMarkUid);
546
+  
547
+  t = _cmTsbTakeUnlink(p,t);
548
+
549
+  assert( t != NULL );
550
+
551
+  _cmTsbTakeFree(p,t);
552
+    
460 553
   return rc;
461 554
 }
462 555
   

Loading…
Cancel
Save