Pārlūkot izejas kodu

cmTimeLine.h/c: Added cmTimeLineGenOnsetMarks() and empty shell code

for cmTimeLineDeleteOnsetMarks(). Added marker typeId field to
cmTlMarkerTl_t.
master
kpl 10 gadus atpakaļ
vecāks
revīzija
63e3713c84
2 mainītis faili ar 209 papildinājumiem un 80 dzēšanām
  1. 187
    77
      app/cmTimeLine.c
  2. 22
    3
      app/cmTimeLine.h

+ 187
- 77
app/cmTimeLine.c Parādīt failu

@@ -7,11 +7,13 @@
7 7
 #include "cmMallocDebug.h"
8 8
 #include "cmLinkedHeap.h"
9 9
 #include "cmJson.h"
10
+#include "cmText.h"
10 11
 #include "cmAudioFile.h"
11 12
 #include "cmMidi.h"
12 13
 #include "cmMidiFile.h"
13 14
 #include "cmFileSys.h"
14 15
 #include "cmTimeLine.h"
16
+#include "cmOnset.h"
15 17
 
16 18
 // id's used to track the type of a serialized object
17 19
 enum
@@ -62,6 +64,7 @@ typedef struct
62 64
   unsigned        seqCnt;
63 65
   _cmTlSeq_t*     seq;          // seq[seqCnt]
64 66
   const cmChar_t* filename;
67
+  cmOnsetCfg_t    onsetCfg;
65 68
 } _cmTl_t;
66 69
 
67 70
 typedef struct
@@ -646,10 +649,7 @@ cmTlRC_t _cmTlProcMidiFile( _cmTl_t* p,  _cmTlObj_t* op, cmMidiFileH_t mfH )
646 649
   unsigned                 mn           = cmMidiFileMsgCount(mfH);
647 650
   const cmMidiTrackMsg_t** mapp         = cmMidiFileMsgArray(mfH);
648 651
   unsigned                 mi           = 0;
649
-  //double                   accum = 0; 
650 652
   _cmTlObj_t*              refOp        = op;
651
-  //bool                     fl           = false;
652
-  unsigned                 dtick        = 0;
653 653
   mfp->noteOnCnt = 0;
654 654
   
655 655
   // for each midi message
@@ -658,18 +658,7 @@ cmTlRC_t _cmTlProcMidiFile( _cmTl_t* p,  _cmTlObj_t* op, cmMidiFileH_t mfH )
658 658
     _cmTlObj_t*             meop = NULL;
659 659
     const cmMidiTrackMsg_t* mp   = mapp[mi];
660 660
 
661
-    dtick = mp->dtick;
662
-
663
-    //if( fl )
664
-    //{
665
-    //  dtick = 0;
666
-    //  fl =  mp->dtick == 0;        
667
-    //}
668
-      
669
-    //accum += dtick * p->srate / 1000000;
670
-
671
-    //int      begSmpIdx         = floor(accum_micros * p->srate / 1000000);
672
-    int      begSmpIdx         = dtick; //floor( dtick * p->srate / 1000000.0 );
661
+    int      begSmpIdx         = mp->dtick;
673 662
     int      durSmpCnt         = 0;
674 663
     unsigned midiTrkMsgByteCnt = cmMidiFilePackTrackMsgBufByteCount( mp );
675 664
     unsigned recdByteCnt       = sizeof(cmTlMidiEvt_t) + midiTrkMsgByteCnt;
@@ -680,7 +669,6 @@ cmTlRC_t _cmTlProcMidiFile( _cmTl_t* p,  _cmTlObj_t* op, cmMidiFileH_t mfH )
680 669
     // count the note-on messages
681 670
     if( mp->status == kNoteOnMdId )
682 671
     {
683
-      //durSmpCnt = floor(mp->u.chMsgPtr->durTicks * p->srate  / 1000000.0 );
684 672
       durSmpCnt = mp->u.chMsgPtr->durTicks;
685 673
       ++mfp->noteOnCnt;
686 674
     }
@@ -712,9 +700,6 @@ cmTlRC_t _cmTlProcMidiFile( _cmTl_t* p,  _cmTlObj_t* op, cmMidiFileH_t mfH )
712 700
     // verify that the memory allocation was calculated correctly
713 701
     assert( cp + recdByteCnt == ((char*)mep->msg) + midiTrkMsgByteCnt);
714 702
 
715
-    // notify any listeners that a new midi event was created by sending a kObjTlId msg.
716
-    //_cmTlNotifyListener(p, kInsertMsgTlId, meop );
717
-    
718 703
     // this midi event is the ref. for the next midi evt
719 704
     refOp = meop;
720 705
   }
@@ -741,7 +726,7 @@ cmTlRC_t _cmTlAllocMidiFileRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmCh
741 726
 
742 727
   unsigned durSmpCnt = floor(cmMidiFileDurSecs(mfH)*p->srate);
743 728
 
744
-  // convert the midi file from ticks to microseconds
729
+  // convert the midi file from delta ticks to delta samples
745 730
   cmMidiFileTickToSamples(mfH,p->srate,false);
746 731
 
747 732
   // assign note durations to all note-on msg's
@@ -768,9 +753,6 @@ cmTlRC_t _cmTlAllocMidiFileRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmCh
768 753
 
769 754
   op->obj->text = mp->fn;
770 755
 
771
-  // notifiy any listeners that a midi file object was created
772
-  //_cmTlNotifyListener(p, kInsertMsgTlId, op );
773
-
774 756
   // insert the events in the midi file as individual time line objects
775 757
   if((rc = _cmTlProcMidiFile(p, op, mfH)) != kOkTlRC )
776 758
     goto errLabel;
@@ -790,7 +772,7 @@ cmTlRC_t _cmTlAllocMidiFileRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmCh
790 772
   return rc;
791 773
 }
792 774
 
793
-cmTlRC_t _cmTlAllocMarkerRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmChar_t* refIdStr, int begSmpIdx, unsigned durSmpCnt, unsigned seqId, const cmChar_t* text, unsigned bar, const cmChar_t* sectionStr )
775
+cmTlRC_t _cmTlAllocMarkerRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmChar_t* refIdStr, int begSmpIdx, unsigned durSmpCnt, unsigned seqId, const cmChar_t* text, unsigned bar, const cmChar_t* sectionStr, unsigned markerTypeId, cmTlObj_t* refObjPtr )
794 776
 {
795 777
   cmTlRC_t        rc      = kOkTlRC;
796 778
   _cmTlObj_t*     op      = NULL;
@@ -800,8 +782,12 @@ cmTlRC_t _cmTlAllocMarkerRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmChar
800 782
   // add memory at the end of the the cmTlMarker_t record to hold the text string.
801 783
   unsigned recdByteCnt = sizeof(cmTlMarker_t) + strlen(textStr) + sizeof(bar) + strlen(sectStr) + 2;
802 784
 
785
+  if(refIdStr == NULL )
786
+    rc = _cmTlAllocRecd2(p,nameStr,(_cmTlObj_t*)refObjPtr->reserved,begSmpIdx,durSmpCnt,kMarkerTlId,seqId,recdByteCnt,&op);
787
+  else
788
+    rc = _cmTlAllocRecd(p,nameStr,refIdStr,begSmpIdx,durSmpCnt,kMarkerTlId,seqId,recdByteCnt,&op);
803 789
 
804
-  if((rc = _cmTlAllocRecd(p,nameStr,refIdStr,begSmpIdx,durSmpCnt,kMarkerTlId,seqId,recdByteCnt,&op)) != kOkTlRC )
790
+  if(rc != kOkTlRC )
805 791
     goto errLabel;
806 792
 
807 793
   assert(op != NULL);
@@ -819,14 +805,16 @@ cmTlRC_t _cmTlAllocMarkerRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmChar
819 805
   cmChar_t* sp = tp + strlen(tp) + 1;
820 806
   strcpy(sp,sectStr);
821 807
 
808
+  // onset markers are generated but not written
809
+  if( markerTypeId != kAudioMarkTlId )
810
+    mp->obj.flags = cmSetFlag(mp->obj.flags,kNoWriteTlFl);
811
+
812
+  mp->typeId     = markerTypeId;
822 813
   mp->text       = tp;
823 814
   mp->sectionStr = sp;
824 815
   mp->bar        = bar;
825 816
   op->obj->text  = tp;
826 817
 
827
-  // notify listeners
828
-  //_cmTlNotifyListener(p, kInsertMsgTlId, op );
829
-  
830 818
  errLabel:
831 819
   if( op != NULL && rc != kOkTlRC )
832 820
     _cmTlDeleteRecd(p,op);
@@ -858,9 +846,6 @@ cmTlRC_t _cmTlAllocAudioEvtRecd( _cmTl_t* p, const cmChar_t* nameStr, const cmCh
858 846
   mp->text = tp;
859 847
   op->obj->text = tp;
860 848
 
861
-  // notify listeners
862
-  //_cmTlNotifyListener(p, kInsertMsgTlId, op );
863
-
864 849
  errLabel:
865 850
   if( op != NULL && rc != kOkTlRC )
866 851
     _cmTlDeleteRecd(p,op);
@@ -877,7 +862,7 @@ cmTlRC_t _cmTlAllocRecdFromJson(_cmTl_t* p,const cmChar_t* nameStr, const cmChar
877 862
   {
878 863
     case kAudioFileTlId: rc = _cmTlAllocAudioFileRecd(p,nameStr,refIdStr,begSmpIdx,          seqId,textStr); break;
879 864
     case kMidiFileTlId:  rc = _cmTlAllocMidiFileRecd( p,nameStr,refIdStr,begSmpIdx,          seqId,textStr); break;
880
-    case kMarkerTlId:    rc = _cmTlAllocMarkerRecd(   p,nameStr,refIdStr,begSmpIdx,durSmpCnt,seqId,textStr,bar,sectionStr); break;
865
+    case kMarkerTlId:    rc = _cmTlAllocMarkerRecd(   p,nameStr,refIdStr,begSmpIdx,durSmpCnt,seqId,textStr,bar,sectionStr,kAudioMarkTlId,NULL); break;
881 866
     case kAudioEvtTlId:  rc = _cmTlAllocAudioEvtRecd( p,nameStr,refIdStr,begSmpIdx,durSmpCnt,seqId,textStr); break;
882 867
     default:
883 868
       rc = cmErrMsg(&p->err,kParseFailTlRC,"'%s' is not a valid 'objArray' record type.",cmStringNullGuard(typeIdStr));
@@ -902,8 +887,6 @@ cmTlRC_t _cmTimeLineFinalize( _cmTl_t* p )
902 887
 
903 888
   cmLHeapDestroy(&p->lH);
904 889
 
905
-  //_cmTlNotifyListener(p, kFinalMsgTlId, NULL );
906
-
907 890
   cmMemPtrFree(&p->tmpBuf);
908 891
 
909 892
   cmMemPtrFree(&p->prefixPath);
@@ -1344,13 +1327,16 @@ cmTlRC_t _cmTlParseErr( cmErr_t* err, const cmChar_t* errLabelPtr, unsigned idx,
1344 1327
 
1345 1328
   return rc;
1346 1329
 }
1330
+
1347 1331
     
1348 1332
 cmTlRC_t cmTimeLineReadJson(  cmTlH_t* hp, const cmChar_t* ifn )
1349 1333
 {
1350 1334
   cmTlRC_t        rc  = kOkTlRC;
1335
+  cmJsRC_t        jsRC = kOkJsRC;
1351 1336
   cmJsonH_t       jsH = cmJsonNullHandle;
1352
-  cmJsonNode_t*   jnp;
1353
-  const cmChar_t* errLabelPtr;
1337
+  cmJsonNode_t*   jnp = NULL;
1338
+  cmJsonNode_t*   cnp = NULL;
1339
+  const cmChar_t* errLabelPtr = NULL;
1354 1340
   int i;
1355 1341
 
1356 1342
   _cmTl_t* p = _cmTlHandleToPtr(*hp);
@@ -1367,10 +1353,36 @@ cmTlRC_t cmTimeLineReadJson(  cmTlH_t* hp, const cmChar_t* ifn )
1367 1353
 
1368 1354
   if( cmJsonMemberValues(jnp,&errLabelPtr,
1369 1355
       "srate",kRealTId,&p->srate,
1356
+      "onset",kObjectTId,&cnp,
1370 1357
       "objArray",kArrayTId,&jnp,
1371 1358
       NULL) != kOkJsRC )
1372 1359
   {
1373
-    rc = cmErrMsg(&p->err,kParseFailTlRC,"The JSON 'time_line' object header parse failed in '%s'.",cmStringNullGuard(ifn));
1360
+    if(jsRC == kNodeNotFoundJsRC )
1361
+      rc = cmErrMsg(&p->err,kParseFailTlRC,"The JSON 'time_line' header required field:'%s' was not found in '%s'.",errLabelPtr,cmStringNullGuard(ifn));
1362
+    else
1363
+      rc = cmErrMsg(&p->err,kParseFailTlRC,"The JSON 'time_line' object header parse failed in '%s'.",cmStringNullGuard(ifn));
1364
+    goto errLabel;
1365
+  }
1366
+
1367
+  if((jsRC = cmJsonMemberValues(cnp,&errLabelPtr,
1368
+      "wndMs",        kRealTId, &p->onsetCfg.wndMs,
1369
+      "hopFact",      kIntTId,  &p->onsetCfg.hopFact,
1370
+      "audioChIdx",   kIntTId,  &p->onsetCfg.audioChIdx,
1371
+      "wndFrmCnt",    kIntTId,  &p->onsetCfg.wndFrmCnt,
1372
+      "preWndMult",   kRealTId, &p->onsetCfg.preWndMult,
1373
+      "threshold",    kRealTId, &p->onsetCfg.threshold,
1374
+      "maxFrqHz",     kRealTId, &p->onsetCfg.maxFrqHz,
1375
+      "filtCoeff",    kRealTId, &p->onsetCfg.filtCoeff,
1376
+      "medFiltWndMs", kRealTId, &p->onsetCfg.medFiltWndMs,
1377
+      "filterId",     kIntTId,  &p->onsetCfg.filterId,
1378
+      "preDelayMs",   kRealTId, &p->onsetCfg.preDelayMs,
1379
+        NULL)) !=        kOkJsRC )
1380
+  {
1381
+    
1382
+    if(jsRC == kNodeNotFoundJsRC )
1383
+      rc = cmErrMsg(&p->err,kParseFailTlRC,"The JSON 'time_line' onset analysizer cfg. required field:'%s' was not found in '%s'.",errLabelPtr,cmStringNullGuard(ifn));
1384
+    else
1385
+      rc = cmErrMsg(&p->err,kParseFailTlRC,"The JSON 'time_line' onset analyzer cfg.  in '%s'.",cmStringNullGuard(ifn));
1374 1386
     goto errLabel;
1375 1387
   }
1376 1388
 
@@ -1444,6 +1456,144 @@ cmTlRC_t cmTimeLineSeqNotify( cmTlH_t h, unsigned seqId )
1444 1456
   return rc;
1445 1457
 }
1446 1458
 
1459
+cmTlRC_t cmTimeLineGenOnsetMarks( cmTlH_t h, unsigned seqId )
1460
+{
1461
+  cmTlRC_t   rc         = kOkTlRC;
1462
+  _cmTl_t*   p          = _cmTlHandleToPtr(h);
1463
+  cmTlObj_t* op         = NULL;
1464
+  cmOnH_t    onsH       = cmOnsetNullHandle;
1465
+  cmChar_t*  textStr    = "";
1466
+  cmChar_t*  sectionStr = "";
1467
+  unsigned   bar        = cmInvalidIdx;
1468
+  unsigned   i,j;
1469
+  unsigned   smpIdx;
1470
+
1471
+  // initialize the audio onset analyzer
1472
+  if( cmOnsetInitialize(&p->ctx, &onsH ) != kOkOnRC )
1473
+  {
1474
+    rc = cmErrMsg(&p->err,kOnsetFailTlRC,"Audio onset analyzer initialization failed.");
1475
+    goto errLabel;
1476
+  }
1477
+
1478
+  // for each audio file
1479
+  
1480
+  for(i=0; (op = cmTimeLineNextTypeObj(h, op, seqId, kAudioFileTlId )) != NULL; ++i)
1481
+  {
1482
+    cmTlAudioFile_t* aop = NULL;
1483
+
1484
+    // get a pointer to this audio file object
1485
+    if((aop = cmTlAudioFileObjPtr(h, op )) == NULL )
1486
+    {
1487
+      rc = cmErrMsg(&p->err,kTypeCvtFailTlRC,"Unexpected audio file object type conversion failure.");
1488
+      goto errLabel;
1489
+    }
1490
+
1491
+    // analyze the onsets in this audio file
1492
+    if( cmOnsetProc(onsH,&p->onsetCfg,aop->fn) != kOkOnRC)
1493
+    {
1494
+      rc = cmErrMsg(&p->err,kOnsetFailTlRC,"Audio onset analyzer failed during processing.");
1495
+      goto errLabel;
1496
+    }
1497
+    
1498
+    // for each detected onset
1499
+    for(j=0; (smpIdx = cmOnsetSampleIndex(onsH,j))!=cmInvalidIdx; ++j)
1500
+    {
1501
+      cmChar_t* labelStr   = NULL;
1502
+
1503
+      labelStr = cmTsPrintfP(labelStr,"a-%i-%i",i,j);
1504
+
1505
+      // generate a marker record
1506
+      rc = _cmTlAllocMarkerRecd(p, labelStr, aop->obj.name, smpIdx, cmOnsetHopSampleCount(onsH), seqId, textStr, bar, sectionStr, kAudioOnsetMarkTlId,NULL );
1507
+
1508
+      cmMemFree(labelStr);
1509
+
1510
+      if( rc != kOkTlRC )
1511
+        goto errLabel;
1512
+    }    
1513
+  }
1514
+
1515
+  unsigned       intervalSmpCnt = 0;
1516
+  cmTlMidiEvt_t* max_eop        = NULL;
1517
+  cmTlObj_t*     fop            = NULL;
1518
+  unsigned       midiFileObjId  = cmInvalidId;
1519
+ 
1520
+  op = NULL;
1521
+  for(i=0; (op = cmTimeLineNextTypeObj(h, op, seqId, kMidiEvtTlId )) != NULL; ++i)
1522
+  {
1523
+    cmTlMidiEvt_t* eop = NULL;
1524
+
1525
+    // get a pointer to this event object
1526
+    if((eop = cmTlMidiEvtObjPtr(h, op )) == NULL )
1527
+    {
1528
+      rc = cmErrMsg(&p->err,kTypeCvtFailTlRC,"Unexpected MIDI event object type conversion failure.");
1529
+      goto errLabel;
1530
+    }
1531
+
1532
+    // if this is the first event in a new MIDI file
1533
+    if(eop->midiFileObjId != midiFileObjId)
1534
+    {
1535
+      // get the MIDI file object
1536
+      if((fop = cmTimeLineIdToObj(h,seqId,eop->midiFileObjId)) == NULL )
1537
+      {
1538
+        rc = cmErrMsg(&p->err,kAssertFailTlRC,"The MIDi file associated with a MIDI event could not be found.");
1539
+        goto errLabel;
1540
+      }
1541
+
1542
+      midiFileObjId  = eop->midiFileObjId;
1543
+      max_eop        = NULL;
1544
+      intervalSmpCnt = 0;
1545
+      j              = 0;
1546
+    }
1547
+
1548
+    // if we have reviewed one second of MIDI events
1549
+    if( intervalSmpCnt > p->srate )
1550
+    {
1551
+      // rewind the interval accumulator to less than one second
1552
+      while(intervalSmpCnt >= p->srate )
1553
+        intervalSmpCnt -= p->srate;
1554
+
1555
+      // if a max veloctiy event was selected ...
1556
+      if( max_eop != NULL )
1557
+      {
1558
+        cmChar_t* labelStr = NULL;
1559
+        labelStr = cmTsPrintfP(labelStr,"%i-%i",i,j);
1560
+
1561
+        // ... generate a marker record
1562
+        rc = _cmTlAllocMarkerRecd(p, labelStr, NULL, 0, cmOnsetHopSampleCount(onsH), seqId, textStr, bar, sectionStr, kMidiOnsetMarkTlId, &max_eop->obj );
1563
+    
1564
+        cmMemFree(labelStr);
1565
+
1566
+        if( rc != kOkTlRC )
1567
+          goto errLabel;
1568
+
1569
+        max_eop = NULL;
1570
+
1571
+        ++j;
1572
+      }
1573
+
1574
+    }
1575
+
1576
+    // update the max velocity event
1577
+    if( max_eop==NULL || (eop->msg->status == kNoteOnMdId && eop->msg->u.chMsgPtr->d1>0 && max_eop->msg->u.chMsgPtr->d1 < eop->msg->u.chMsgPtr->d1) )
1578
+      max_eop = eop;
1579
+
1580
+    // increment the interval accumulator
1581
+    intervalSmpCnt += eop->obj.begSmpIdx;
1582
+    
1583
+  }
1584
+
1585
+ errLabel:
1586
+  if( cmOnsetFinalize(&onsH) != kOkOnRC )
1587
+    rc = cmErrMsg(&p->err,kOnsetFailTlRC,"Audio onset analyzer finalization failed.");
1588
+
1589
+  return rc;
1590
+}
1591
+
1592
+cmTlRC_t cmTimeLineDeleteOnsetMarks( cmTlH_t h, unsigned seqId )
1593
+{
1594
+}
1595
+
1596
+
1447 1597
 void _cmTimeLinePrintObj(_cmTl_t* p, _cmTlObj_t* op, cmRpt_t* rpt )
1448 1598
 {
1449 1599
 
@@ -1661,48 +1811,8 @@ cmTlRC_t  _cmTimeLineDecodeObj( const void* msg, unsigned msgByteCnt, cmTlUiMsg_
1661 1811
 
1662 1812
   r->msgId       = kInsertMsgTlId;
1663 1813
   r->objId       = tp->uid;
1664
-  //r->parentObjId = *parentIdPtr;
1665 1814
   r->seqId       = tp->seqId;
1666
-  //r->typeId      = tp->typeId;
1667
-  //r->begSmpIdx   = tp->begSmpIdx;
1668
-  //r->durSmpCnt   = tp->durSmpCnt;
1669
-  //r->label       = strlen(text)==0 ? NULL : text;
1670 1815
   r->srate       = 0;
1671
-  //r->midiTrkMsg  = NULL;
1672
-  //r->textStr     = NULL;
1673
-  /*
1674
-  switch( tp->typeId )
1675
-  {
1676
-    case kMidiFileTlId:
1677
-      r->textStr = _cmTimeLineMidiFileObjPtr(NULL,tp)->fn;
1678
-      break;
1679
-
1680
-    case kMidiEvtTlId:
1681
-      {
1682
-        cmTlMidiEvt_t* mep; 
1683
-        if((mep = _cmTimeLineMidiEvtObjPtr(NULL,tp)) != NULL )
1684
-        {
1685
-          r->midiFileObjId = mep->midiFileObjId;
1686
-          r->midiTrkMsg    = mep->msg;
1687
-        }
1688
-      }
1689
-      break;
1690
-
1691
-    case kAudioFileTlId:
1692
-      r->textStr = _cmTimeLineAudioFileObjPtr(NULL,tp)->fn;
1693
-      break;
1694
-
1695
-    case kAudioEvtTlId:
1696
-      break;
1697
-
1698
-    case kMarkerTlId:
1699
-      r->textStr = _cmTimeLineMarkerObjPtr(NULL,tp)->text;
1700
-      break;
1701
-
1702
-    default:
1703
-      { assert(0); }
1704
-  }
1705
-  */
1706 1816
   return rc;
1707 1817
 }
1708 1818
 

+ 22
- 3
app/cmTimeLine.h Parādīt failu

@@ -23,7 +23,9 @@ extern "C" {
23 23
     kTypeCvtFailTlRC,
24 24
     kUnknownRecdTypeTlRC,
25 25
     kFinalizeFailTlRC,
26
-    kInvalidSeqIdTlRC
26
+    kInvalidSeqIdTlRC,
27
+    kOnsetFailTlRC,
28
+    kAssertFailTlRC
27 29
   };
28 30
 
29 31
   typedef enum
@@ -41,6 +43,14 @@ extern "C" {
41 43
     kNoWriteTlFl  = 0x02  // do not write this object in cmTimeLineWrite()
42 44
   };
43 45
 
46
+  // marker types
47
+  enum
48
+  {
49
+    kAudioMarkTlId,
50
+    kAudioOnsetMarkTlId,
51
+    kMidiOnsetMarkTlId
52
+  }; 
53
+
44 54
   typedef void (*cmTlCb_t)( void* arg, const void* data, unsigned byteCnt );
45 55
 
46 56
   typedef struct cmTlObj_str
@@ -67,11 +77,15 @@ extern "C" {
67 77
     cmChar_t*     fn;
68 78
   } cmTlMidiFile_t;
69 79
 
80
+  // MIDI events generated from MIDI files reference the previous
81
+  // MIDI event and the first event in the file references the 
82
+  // file object. The 'begSmpIdx' is therefore a delta value
83
+  // from the previous event.
70 84
   typedef struct
71 85
   {
72
-    cmTlObj_t               obj;
86
+    cmTlObj_t               obj; //
73 87
     unsigned                midiFileObjId;
74
-    const cmMidiTrackMsg_t* msg;       // w/ dticks converted to microsecs
88
+    const cmMidiTrackMsg_t* msg;       // w/ dticks converted to samples
75 89
   } cmTlMidiEvt_t;
76 90
 
77 91
 
@@ -95,6 +109,7 @@ extern "C" {
95 109
   typedef struct
96 110
   {
97 111
     cmTlObj_t        obj;
112
+    unsigned         typeId;         // marker type see kXXXMarkTlId above.
98 113
     const cmChar_t*  text;
99 114
     unsigned         bar;            // measure (bar) in which this marker starts
100 115
     const cmChar_t*  sectionStr;     // the section in which this marker starts
@@ -191,6 +206,10 @@ extern "C" {
191 206
   // Make notifications for all records belonging to the sequence.
192 207
   cmTlRC_t cmTimeLineSeqNotify( cmTlH_t h, unsigned seqId );
193 208
 
209
+  // Create and make notification for audio/MIDI onset marks.
210
+  cmTlRC_t cmTimeLineGenOnsetMarks( cmTlH_t h, unsigned seqId );
211
+  cmTlRC_t cmTimeLineDeleteOnsetMarks( cmTlH_t h, unsigned seqId );
212
+
194 213
   cmTlRC_t cmTimeLineWrite( cmTlH_t h, const cmChar_t* fn );
195 214
 
196 215
   cmTlRC_t cmTimeLinePrint( cmTlH_t h, cmRpt_t* rpt );

Notiek ielāde…
Atcelt
Saglabāt