|
@@ -19,8 +19,6 @@
|
19
|
19
|
#define mfSwap32(v) cmSwap32(v)
|
20
|
20
|
#endif
|
21
|
21
|
|
22
|
|
-
|
23
|
|
-
|
24
|
22
|
typedef struct
|
25
|
23
|
{
|
26
|
24
|
unsigned cnt; // count of track records
|
|
@@ -160,10 +158,25 @@ cmMfRC_t _cmMidiFileReadVarLen( _cmMidiFile_t* mfp, unsigned* p )
|
160
|
158
|
return kOkMfRC;
|
161
|
159
|
}
|
162
|
160
|
|
163
|
|
-cmMfRC_t _cmMidiFileAppendTrackMsg( _cmMidiFile_t* mfp, unsigned short trkIdx, unsigned dtick, cmMidiByte_t status, cmMidiTrackMsg_t** trkMsgPtrPtr )
|
|
161
|
+cmMidiTrackMsg_t* _cmMidiFileAllocMsg( _cmMidiFile_t* mfp, unsigned short trkIdx, unsigned dtick, cmMidiByte_t status )
|
164
|
162
|
{
|
165
|
163
|
cmMidiTrackMsg_t* tmp = (cmMidiTrackMsg_t*)_cmMidiFileMalloc(mfp, sizeof(cmMidiTrackMsg_t) );
|
166
|
|
-
|
|
164
|
+
|
|
165
|
+ // set the generic track record fields
|
|
166
|
+ tmp->dtick = dtick;
|
|
167
|
+ tmp->status = status;
|
|
168
|
+ tmp->metaId = kInvalidMetaMdId;
|
|
169
|
+ tmp->trkIdx = trkIdx;
|
|
170
|
+ tmp->byteCnt = 0;
|
|
171
|
+ tmp->uid = mfp->nextUid++;
|
|
172
|
+
|
|
173
|
+ return tmp;
|
|
174
|
+}
|
|
175
|
+
|
|
176
|
+cmMfRC_t _cmMidiFileAppendTrackMsg( _cmMidiFile_t* mfp, unsigned short trkIdx, unsigned dtick, cmMidiByte_t status, cmMidiTrackMsg_t** trkMsgPtrPtr )
|
|
177
|
+{
|
|
178
|
+ cmMidiTrackMsg_t* tmp = _cmMidiFileAllocMsg( mfp, trkIdx, dtick, status );
|
|
179
|
+
|
167
|
180
|
// link new record onto track record chain
|
168
|
181
|
if( mfp->trkV[trkIdx].base == NULL )
|
169
|
182
|
mfp->trkV[trkIdx].base = tmp;
|
|
@@ -174,12 +187,6 @@ cmMfRC_t _cmMidiFileAppendTrackMsg( _cmMidiFile_t* mfp, unsigned short trkIdx, u
|
174
|
187
|
mfp->trkV[trkIdx].cnt++;
|
175
|
188
|
|
176
|
189
|
|
177
|
|
- // set the generic track record fields
|
178
|
|
- tmp->dtick = dtick;
|
179
|
|
- tmp->status = status;
|
180
|
|
- tmp->metaId = kInvalidMetaMdId;
|
181
|
|
- tmp->trkIdx = trkIdx;
|
182
|
|
- tmp->byteCnt = 0;
|
183
|
190
|
*trkMsgPtrPtr = tmp;
|
184
|
191
|
|
185
|
192
|
return kOkMfRC;
|
|
@@ -521,6 +528,43 @@ cmMfRC_t _cmMidiFileClose( _cmMidiFile_t* mfp )
|
521
|
528
|
|
522
|
529
|
}
|
523
|
530
|
|
|
531
|
+void _cmMidiFileLinearize( _cmMidiFile_t* mfp )
|
|
532
|
+{
|
|
533
|
+ unsigned trkIdx,i,j;
|
|
534
|
+
|
|
535
|
+ // get the total trk msg count
|
|
536
|
+ mfp->msgN = 0;
|
|
537
|
+ for(trkIdx=0; trkIdx<mfp->trkN; ++trkIdx)
|
|
538
|
+ mfp->msgN += mfp->trkV[ trkIdx ].cnt;
|
|
539
|
+
|
|
540
|
+ // allocate the trk msg index vector: msgV[]
|
|
541
|
+ mfp->msgV = cmMemResizeZ(cmMidiTrackMsg_t*, mfp->msgV, mfp->msgN);
|
|
542
|
+
|
|
543
|
+ // store a pointer to every trk msg in msgV[]
|
|
544
|
+ for(i=0,j=0; i<mfp->trkN; ++i)
|
|
545
|
+ {
|
|
546
|
+ cmMidiTrackMsg_t* m = mfp->trkV[i].base;
|
|
547
|
+
|
|
548
|
+ for(; m!=NULL; m=m->link)
|
|
549
|
+ {
|
|
550
|
+ assert( j < mfp->msgN );
|
|
551
|
+
|
|
552
|
+ mfp->msgV[j++] = m;
|
|
553
|
+ }
|
|
554
|
+ }
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+ // set the atick value in each msg
|
|
558
|
+ _cmMidiFileSetAccumulateTicks(mfp);
|
|
559
|
+
|
|
560
|
+ // sort msgV[] in ascending order on atick
|
|
561
|
+ qsort( mfp->msgV, mfp->msgN, sizeof(cmMidiTrackMsg_t*), _cmMidiFileSortFunc );
|
|
562
|
+
|
|
563
|
+ // set the amicro value in each msg
|
|
564
|
+ _cmMidiFileSetAbsoluteTime(mfp);
|
|
565
|
+
|
|
566
|
+}
|
|
567
|
+
|
524
|
568
|
|
525
|
569
|
cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
526
|
570
|
{
|
|
@@ -528,7 +572,6 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
528
|
572
|
_cmMidiFile_t* mfp = NULL;
|
529
|
573
|
unsigned short trkIdx = 0;
|
530
|
574
|
cmErr_t err;
|
531
|
|
- unsigned i,j;
|
532
|
575
|
|
533
|
576
|
if( cmMidiFileIsValid(*hPtr) )
|
534
|
577
|
if((rc = _cmMidiFileClose(_cmMidiFileHandleToPtr(*hPtr))) != kOkMfRC )
|
|
@@ -538,7 +581,7 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
538
|
581
|
|
539
|
582
|
// allocate the midi file object
|
540
|
583
|
if(( mfp = cmMemAllocZ( _cmMidiFile_t, 1)) == NULL )
|
541
|
|
- return rc = cmErrMsg(&err,kMemAllocFailMfRC,"MIDI file memory allocation failed.");
|
|
584
|
+ return rc = cmErrMsg(&err,kMemAllocFailMfRC,"MIDI file memory allocation failed.");
|
542
|
585
|
|
543
|
586
|
cmErrClone(&mfp->err,&err);
|
544
|
587
|
|
|
@@ -562,7 +605,7 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
562
|
605
|
|
563
|
606
|
while( !cmFileEof(mfp->fh) && trkIdx < mfp->trkN )
|
564
|
607
|
{
|
565
|
|
- unsigned chkId=0,chkN=0;
|
|
608
|
+ unsigned chkId = 0,chkN=0;
|
566
|
609
|
|
567
|
610
|
// read the chunk id
|
568
|
611
|
if((rc = _cmMidiFileRead32(mfp,&chkId)) != kOkMfRC )
|
|
@@ -591,43 +634,12 @@ cmMfRC_t cmMidiFileOpen( cmCtx_t* ctx, cmMidiFileH_t* hPtr, const char* fn )
|
591
|
634
|
}
|
592
|
635
|
}
|
593
|
636
|
|
594
|
|
- // get the total trk msg count
|
595
|
|
- mfp->msgN = 0;
|
596
|
|
- for(trkIdx=0; trkIdx<mfp->trkN; ++trkIdx)
|
597
|
|
- mfp->msgN += mfp->trkV[ trkIdx ].cnt;
|
598
|
|
-
|
599
|
|
- // allocate the trk msg index vector: msgV[]
|
600
|
|
- mfp->msgV = cmMemAllocZ(cmMidiTrackMsg_t*, mfp->msgN);
|
601
|
|
-
|
602
|
|
- mfp->nextUid = 0;
|
603
|
|
-
|
604
|
|
- // store a pointer to every trk msg in msgV[] and set 'uid'
|
605
|
|
- for(i=0,j=0; i<mfp->trkN; ++i)
|
606
|
|
- {
|
607
|
|
- cmMidiTrackMsg_t* m = mfp->trkV[i].base;
|
608
|
|
-
|
609
|
|
- for(; m!=NULL; m=m->link)
|
610
|
|
- {
|
611
|
|
- assert( j < mfp->msgN );
|
612
|
|
-
|
613
|
|
- mfp->msgV[j++] = m;
|
614
|
|
- m->uid = mfp->nextUid++;
|
615
|
|
- }
|
616
|
|
- }
|
617
|
|
-
|
618
|
|
- mfp->fn = _cmMidiFileMalloc(mfp,strlen(fn)+1);
|
|
637
|
+ // store the file name
|
|
638
|
+ mfp->fn = _cmMidiFileMalloc(mfp,strlen(fn)+1);
|
619
|
639
|
assert( mfp->fn != NULL );
|
620
|
640
|
strcpy(mfp->fn,fn);
|
621
|
|
-
|
622
|
|
-
|
623
|
|
- // set the atick value in each msg
|
624
|
|
- _cmMidiFileSetAccumulateTicks(mfp);
|
625
|
|
-
|
626
|
|
- // sort msgV[] in ascending order on atick
|
627
|
|
- qsort( mfp->msgV, mfp->msgN, sizeof(cmMidiTrackMsg_t*), _cmMidiFileSortFunc );
|
628
|
|
-
|
629
|
|
- // set the amicro value in each msg
|
630
|
|
- _cmMidiFileSetAbsoluteTime(mfp);
|
|
641
|
+
|
|
642
|
+ _cmMidiFileLinearize(mfp);
|
631
|
643
|
|
632
|
644
|
hPtr->h = mfp;
|
633
|
645
|
|
|
@@ -682,11 +694,11 @@ cmMfRC_t _cmMidiFileWrite16( _cmMidiFile_t* mfp, unsigned short v )
|
682
|
694
|
|
683
|
695
|
cmMfRC_t _cmMidiFileWrite24( _cmMidiFile_t* mfp, unsigned v )
|
684
|
696
|
{
|
685
|
|
- cmMfRC_t rc = kOkMfRC;
|
|
697
|
+ cmMfRC_t rc = kOkMfRC;
|
686
|
698
|
unsigned mask = 0xff0000;
|
687
|
699
|
int i;
|
688
|
700
|
|
689
|
|
- for(i=2; i>=0; --i)
|
|
701
|
+ for(i = 2; i>=0; --i)
|
690
|
702
|
{
|
691
|
703
|
unsigned char c = (v & mask) >> (i*8);
|
692
|
704
|
mask >>= 8;
|
|
@@ -727,7 +739,7 @@ cmMfRC_t _cmMidiFileWriteRecd( _cmMidiFile_t* mfp, const void* v, unsigned byteC
|
727
|
739
|
|
728
|
740
|
cmMfRC_t _cmMidiFileWriteVarLen( _cmMidiFile_t* mfp, unsigned v )
|
729
|
741
|
{
|
730
|
|
- cmMfRC_t rc = kOkMfRC;
|
|
742
|
+ cmMfRC_t rc = kOkMfRC;
|
731
|
743
|
unsigned buf = v & 0x7f;
|
732
|
744
|
|
733
|
745
|
while((v >>= 7) > 0 )
|
|
@@ -786,7 +798,7 @@ cmMfRC_t _cmMidiFileWriteHdr( _cmMidiFile_t* mfp )
|
786
|
798
|
else
|
787
|
799
|
{
|
788
|
800
|
// ... otherwise the division field was given in smpte
|
789
|
|
- v = mfp->smpteFmtId << 8;
|
|
801
|
+ v = mfp->smpteFmtId << 8;
|
790
|
802
|
v += mfp->smpteTicksPerFrame;
|
791
|
803
|
}
|
792
|
804
|
|
|
@@ -800,7 +812,7 @@ cmMfRC_t _cmMidiFileWriteHdr( _cmMidiFile_t* mfp )
|
800
|
812
|
|
801
|
813
|
cmMfRC_t _cmMidiFileWriteSysEx( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp )
|
802
|
814
|
{
|
803
|
|
- cmMfRC_t rc = kOkMfRC;
|
|
815
|
+ cmMfRC_t rc = kOkMfRC;
|
804
|
816
|
|
805
|
817
|
if((rc = _cmMidiFileWrite8(mfp,kSysExMdId)) != kOkMfRC )
|
806
|
818
|
goto errLabel;
|
|
@@ -814,8 +826,8 @@ cmMfRC_t _cmMidiFileWriteSysEx( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp )
|
814
|
826
|
|
815
|
827
|
cmMfRC_t _cmMidiFileWriteChannelMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tmp, cmMidiByte_t* runStatus )
|
816
|
828
|
{
|
817
|
|
- cmMfRC_t rc = kOkMfRC;
|
818
|
|
- unsigned byteN = cmMidiStatusToByteCount(tmp->status);
|
|
829
|
+ cmMfRC_t rc = kOkMfRC;
|
|
830
|
+ unsigned byteN = cmMidiStatusToByteCount(tmp->status);
|
819
|
831
|
cmMidiByte_t status = tmp->status + tmp->u.chMsgPtr->ch;
|
820
|
832
|
|
821
|
833
|
if( status != *runStatus )
|
|
@@ -839,7 +851,7 @@ cmMfRC_t _cmMidiFileWriteChannelMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t*
|
839
|
851
|
|
840
|
852
|
cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tmp )
|
841
|
853
|
{
|
842
|
|
- cmMfRC_t rc;
|
|
854
|
+ cmMfRC_t rc;
|
843
|
855
|
|
844
|
856
|
if((rc = _cmMidiFileWrite8(mfp,kMetaStId)) != kOkMfRC )
|
845
|
857
|
return rc;
|
|
@@ -852,7 +864,7 @@ cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tm
|
852
|
864
|
{
|
853
|
865
|
case kSeqNumbMdId:
|
854
|
866
|
if((rc = _cmMidiFileWrite8(mfp,sizeof(tmp->u.sVal))) == kOkMfRC )
|
855
|
|
- rc = _cmMidiFileWrite16(mfp,tmp->u.sVal);
|
|
867
|
+ rc = _cmMidiFileWrite16(mfp,tmp->u.sVal);
|
856
|
868
|
break;
|
857
|
869
|
|
858
|
870
|
case kTempoMdId:
|
|
@@ -862,27 +874,27 @@ cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tm
|
862
|
874
|
|
863
|
875
|
case kSmpteMdId:
|
864
|
876
|
if((rc = _cmMidiFileWrite8(mfp,sizeof(cmMidiSmpte_t))) == kOkMfRC )
|
865
|
|
- rc = _cmMidiFileWriteRecd(mfp,tmp->u.smptePtr,sizeof(cmMidiSmpte_t));
|
|
877
|
+ rc = _cmMidiFileWriteRecd(mfp,tmp->u.smptePtr,sizeof(cmMidiSmpte_t));
|
866
|
878
|
break;
|
867
|
879
|
|
868
|
880
|
case kTimeSigMdId:
|
869
|
881
|
if((rc = _cmMidiFileWrite8(mfp,sizeof(cmMidiTimeSig_t))) == kOkMfRC )
|
870
|
|
- rc = _cmMidiFileWriteRecd(mfp,tmp->u.timeSigPtr,sizeof(cmMidiTimeSig_t));
|
|
882
|
+ rc = _cmMidiFileWriteRecd(mfp,tmp->u.timeSigPtr,sizeof(cmMidiTimeSig_t));
|
871
|
883
|
break;
|
872
|
884
|
|
873
|
885
|
case kKeySigMdId:
|
874
|
886
|
if((rc = _cmMidiFileWrite8(mfp,sizeof(cmMidiKeySig_t))) == kOkMfRC )
|
875
|
|
- rc = _cmMidiFileWriteRecd(mfp,tmp->u.keySigPtr,sizeof(cmMidiKeySig_t));
|
|
887
|
+ rc = _cmMidiFileWriteRecd(mfp,tmp->u.keySigPtr,sizeof(cmMidiKeySig_t));
|
876
|
888
|
break;
|
877
|
889
|
|
878
|
890
|
case kSeqSpecMdId:
|
879
|
891
|
if((rc = _cmMidiFileWriteVarLen(mfp,sizeof(tmp->byteCnt))) == kOkMfRC )
|
880
|
|
- rc = _cmMidiFileWriteRecd(mfp,tmp->u.sysExPtr,tmp->byteCnt);
|
|
892
|
+ rc = _cmMidiFileWriteRecd(mfp,tmp->u.sysExPtr,tmp->byteCnt);
|
881
|
893
|
break;
|
882
|
894
|
|
883
|
895
|
case kMidiChMdId:
|
884
|
896
|
if((rc = _cmMidiFileWrite8(mfp,sizeof(tmp->u.bVal))) == kOkMfRC )
|
885
|
|
- rc = _cmMidiFileWrite8(mfp,tmp->u.bVal);
|
|
897
|
+ rc = _cmMidiFileWrite8(mfp,tmp->u.bVal);
|
886
|
898
|
break;
|
887
|
899
|
|
888
|
900
|
case kEndOfTrkMdId:
|
|
@@ -898,8 +910,8 @@ cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tm
|
898
|
910
|
case kCuePointMdId:
|
899
|
911
|
{
|
900
|
912
|
unsigned n = tmp->u.text==NULL ? 0 : strlen(tmp->u.text);
|
901
|
|
- if((rc = _cmMidiFileWriteVarLen(mfp,n)) == kOkMfRC && n>0 )
|
902
|
|
- rc = _cmMidiFileWriteRecd(mfp,tmp->u.text,n);
|
|
913
|
+ if((rc = _cmMidiFileWriteVarLen(mfp,n)) == kOkMfRC && n>0 )
|
|
914
|
+ rc = _cmMidiFileWriteRecd(mfp,tmp->u.text,n);
|
903
|
915
|
}
|
904
|
916
|
break;
|
905
|
917
|
|
|
@@ -915,11 +927,11 @@ cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tm
|
915
|
927
|
|
916
|
928
|
cmMfRC_t _cmMidiFileWriteTrack( _cmMidiFile_t* mfp, unsigned trkIdx )
|
917
|
929
|
{
|
918
|
|
- cmMfRC_t rc = kOkMfRC;
|
919
|
|
- cmMidiTrackMsg_t* tmp = mfp->trkV[trkIdx].base;
|
920
|
|
- cmMidiByte_t runStatus = 0;
|
|
930
|
+ cmMfRC_t rc = kOkMfRC;
|
|
931
|
+ cmMidiTrackMsg_t* tmp = mfp->trkV[trkIdx].base;
|
|
932
|
+ cmMidiByte_t runStatus = 0;
|
921
|
933
|
|
922
|
|
- for(; tmp!=NULL; tmp=tmp->link)
|
|
934
|
+ for(; tmp != NULL; tmp=tmp->link)
|
923
|
935
|
{
|
924
|
936
|
// write the msg tick count
|
925
|
937
|
if((rc = _cmMidiFileWriteVarLen(mfp,tmp->dtick)) != kOkMfRC )
|
|
@@ -968,8 +980,8 @@ cmMfRC_t cmMidiFileWrite( cmMidiFileH_t h, const char* fn )
|
968
|
980
|
|
969
|
981
|
for(i=0; i < mfp->trkN; ++i )
|
970
|
982
|
{
|
971
|
|
- unsigned chkId='MTrk';
|
972
|
|
- long offs0,offs1;
|
|
983
|
+ unsigned chkId = 'MTrk';
|
|
984
|
+ long offs0,offs1;
|
973
|
985
|
|
974
|
986
|
// write the track chunk id ('MTrk')
|
975
|
987
|
if((rc = _cmMidiFileWrite32(mfp,chkId)) != kOkMfRC )
|
|
@@ -1124,14 +1136,14 @@ cmMidiTrackMsg_t* _cmMidiFileUidToMsg( _cmMidiFile_t* mfp, unsigned uid )
|
1124
|
1136
|
cmMfRC_t cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel )
|
1125
|
1137
|
{
|
1126
|
1138
|
cmMidiTrackMsg_t* r;
|
1127
|
|
- _cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
|
|
1139
|
+ _cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
|
1128
|
1140
|
|
1129
|
1141
|
assert( mfp != NULL );
|
1130
|
1142
|
|
1131
|
1143
|
if((r = _cmMidiFileUidToMsg(mfp,uid)) == NULL )
|
1132
|
1144
|
return cmErrMsg(&mfp->err,kUidNotFoundMfRC,"The MIDI file uid %i could not be found.",uid);
|
1133
|
1145
|
|
1134
|
|
- if( cmMidiIsNoteOn(r->status)==false && cmMidiIsNoteOff(r->status,0)==false )
|
|
1146
|
+ if( cmMidiIsNoteOn(r->status) == false && cmMidiIsNoteOff(r->status,0)==false )
|
1135
|
1147
|
return cmErrMsg(&mfp->err,kUidNotANoteMsgMfRC,"Cannot set velocity on a non-Note-On/Off msg.");
|
1136
|
1148
|
|
1137
|
1149
|
cmMidiChMsg_t* chm = (cmMidiChMsg_t*)r->u.chMsgPtr;
|
|
@@ -1141,6 +1153,103 @@ cmMfRC_t cmMidiFileSetVelocity( cmMidiFileH_t h, unsigned uid, cmMidiByte_t vel
|
1141
|
1153
|
return kOkMfRC;
|
1142
|
1154
|
}
|
1143
|
1155
|
|
|
1156
|
+// Returns NULL if uid is not found or if it the first msg on the track.
|
|
1157
|
+cmMidiTrackMsg_t* _cmMidiFileMsgBeforeUid( _cmMidiFile_t* p, unsigned uid )
|
|
1158
|
+{
|
|
1159
|
+ cmMidiTrackMsg_t* m;
|
|
1160
|
+
|
|
1161
|
+ if((m = _cmMidiFileUidToMsg(p,uid)) == NULL )
|
|
1162
|
+ return NULL;
|
|
1163
|
+
|
|
1164
|
+ assert( m->trkIdx < p->trkN );
|
|
1165
|
+
|
|
1166
|
+ cmMidiTrackMsg_t* m0 = NULL;
|
|
1167
|
+ cmMidiTrackMsg_t* m1 = p->trkV[ m->trkIdx ].base;
|
|
1168
|
+ for(; m1!=NULL; m1 = m1->link)
|
|
1169
|
+ {
|
|
1170
|
+ if( m1->uid == uid )
|
|
1171
|
+ break;
|
|
1172
|
+ m0 = m1;
|
|
1173
|
+ }
|
|
1174
|
+
|
|
1175
|
+ return m0;
|
|
1176
|
+}
|
|
1177
|
+
|
|
1178
|
+unsigned _cmMidiFileIsMsgFirstOnTrack( _cmMidiFile_t* p, unsigned uid )
|
|
1179
|
+{
|
|
1180
|
+ unsigned i;
|
|
1181
|
+ for(i=0; i<p->trkN; ++i)
|
|
1182
|
+ if( p->trkV[i].base!=NULL && p->trkV[i].base->uid == uid )
|
|
1183
|
+ return i;
|
|
1184
|
+
|
|
1185
|
+ return cmInvalidIdx;
|
|
1186
|
+}
|
|
1187
|
+
|
|
1188
|
+
|
|
1189
|
+cmMfRC_t cmMidiFileInsertMsg( cmMidiFileH_t h, unsigned uid, int dtick, cmMidiByte_t ch, cmMidiByte_t status, cmMidiByte_t d0, cmMidiByte_t d1 )
|
|
1190
|
+{
|
|
1191
|
+ _cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
|
|
1192
|
+ assert( mfp != NULL );
|
|
1193
|
+ cmMidiTrackMsg_t* ref = NULL;
|
|
1194
|
+ unsigned trkIdx = cmInvalidIdx;
|
|
1195
|
+
|
|
1196
|
+ // if dtick is positive ...
|
|
1197
|
+ if( dtick >= 0 )
|
|
1198
|
+ {
|
|
1199
|
+ ref = _cmMidiFileUidToMsg(mfp,uid); // ... then get the ref. msg.
|
|
1200
|
+ trkIdx = ref->trkIdx;
|
|
1201
|
+ }
|
|
1202
|
+ else // if dtick is negative ...
|
|
1203
|
+ {
|
|
1204
|
+ // ... get get the msg before the ref. msg.
|
|
1205
|
+ if((ref = _cmMidiFileMsgBeforeUid(mfp,uid)) == NULL )
|
|
1206
|
+ {
|
|
1207
|
+ // ... the ref. msg was first in the track so there is no msg before it
|
|
1208
|
+ trkIdx = _cmMidiFileIsMsgFirstOnTrack(mfp,uid);
|
|
1209
|
+ }
|
|
1210
|
+ }
|
|
1211
|
+
|
|
1212
|
+ // verify that the reference msg was found
|
|
1213
|
+ if( trkIdx == cmInvalidIdx )
|
|
1214
|
+ return cmErrMsg(&mfp->err,kUidNotFoundMfRC,"The UID (%i) reference note could not be located.",uid);
|
|
1215
|
+
|
|
1216
|
+ assert( trkIdx < mfp->trkN );
|
|
1217
|
+
|
|
1218
|
+ // complete the msg setup
|
|
1219
|
+ _cmMidiTrack_t* trk = mfp->trkV + trkIdx;
|
|
1220
|
+ cmMidiTrackMsg_t* m = _cmMidiFileAllocMsg(mfp, trkIdx, abs(dtick), status );
|
|
1221
|
+ cmMidiChMsg_t* c = (cmMidiChMsg_t*)m->u.chMsgPtr; // cast away const
|
|
1222
|
+ c->ch = ch;
|
|
1223
|
+ c->d0 = d0;
|
|
1224
|
+ c->d1 = d1;
|
|
1225
|
+
|
|
1226
|
+ // if 'm' is prior to the first msg in the track
|
|
1227
|
+ if( ref == NULL )
|
|
1228
|
+ {
|
|
1229
|
+ // ... then make 'm' the first msg in the first msg
|
|
1230
|
+ m->link = trk->base;
|
|
1231
|
+ trk->base = m;
|
|
1232
|
+ // 'm' is before ref and the track cannot be empty (because ref is in it) 'm'
|
|
1233
|
+ // can never be the last msg in the list
|
|
1234
|
+ }
|
|
1235
|
+ else // ref is the msg before 'm'
|
|
1236
|
+ {
|
|
1237
|
+ m->link = ref->link;
|
|
1238
|
+ ref->link = m;
|
|
1239
|
+
|
|
1240
|
+ // if ref was the last msg in the trk ...
|
|
1241
|
+ if( trk->last == ref )
|
|
1242
|
+ trk->last = m; //... then 'm' is now the last msg in the trk
|
|
1243
|
+ }
|
|
1244
|
+
|
|
1245
|
+ trk->cnt += 1;
|
|
1246
|
+
|
|
1247
|
+ _cmMidiFileLinearize(mfp);
|
|
1248
|
+
|
|
1249
|
+ return kOkMfRC;
|
|
1250
|
+
|
|
1251
|
+}
|
|
1252
|
+
|
1144
|
1253
|
unsigned cmMidiFileSeekUsecs( cmMidiFileH_t h, unsigned long long offsUSecs, unsigned* msgUsecsPtr, unsigned* microsPerTickPtr )
|
1145
|
1254
|
{
|
1146
|
1255
|
_cmMidiFile_t* p;
|