Explorar el Código

cmMidiFile.h/c : Added cmMidiFileWrite() and the 'atick' absolute tick

value field.
master
kpl hace 10 años
padre
commit
e386a9675d
Se han modificado 2 ficheros con 412 adiciones y 51 borrados
  1. 398
    36
      cmMidiFile.c
  2. 14
    15
      cmMidiFile.h

+ 398
- 36
cmMidiFile.c Ver fichero

@@ -31,7 +31,7 @@ typedef struct
31 31
 {
32 32
   cmErr_t            err;                // this objects error object
33 33
   cmLHeapH_t         lhH;                // linked heap used for all dynamically alloc'd data space
34
-  cmFileH_t          fh;                 // cmFile handle (only used in fmMidiFileOpen())
34
+  cmFileH_t          fh;                 // cmFile handle (only used in fmMidiFileOpen() and cmMidiFileWrite())
35 35
   unsigned short     fmtId;              // midi file type id: 0,1,2
36 36
   unsigned short     ticksPerQN;         // ticks per quarter note or 0 if smpteFmtId is valid
37 37
   cmMidiByte_t       smpteFmtId;         // smpte format or 0 if ticksPerQN is valid
@@ -44,14 +44,9 @@ typedef struct
44 44
   
45 45
 } _cmMidiFile_t;
46 46
 
47
-#define _cmMidiFileError( err, rc ) _cmMidiFileOnError(err, rc, __LINE__,__FILE__,__FUNCTION__ )
48 47
 
49 48
 cmMidiFileH_t cmMidiFileNullHandle = cmSTATIC_NULL_HANDLE;
50 49
 
51
-cmMfRC_t _cmMidiFileOnError( cmErr_t* err, cmMfRC_t rc, int line, const char* fn, const char* func )
52
-{
53
-  return cmErrMsg(err,rc,"rc:%i line:%i %s %s\n",rc,line,func,fn);
54
-}
55 50
 
56 51
 _cmMidiFile_t* _cmMidiFileHandleToPtr( cmMidiFileH_t h )
57 52
 {
@@ -67,14 +62,14 @@ void* _cmMidiFileMalloc( _cmMidiFile_t* mfp, unsigned byteN )
67 62
 cmMfRC_t _cmMidiFileRead8( _cmMidiFile_t* mfp, cmMidiByte_t* p )
68 63
 {
69 64
   if( cmFileReadUChar(mfp->fh,p,1) != kOkFileRC )  
70
-    return _cmMidiFileError(&mfp->err,kSysFreadFailMfRC);
65
+    return cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI byte read failed.");
71 66
   return kOkMfRC;
72 67
 }
73 68
 
74 69
 cmMfRC_t _cmMidiFileRead16( _cmMidiFile_t* mfp, unsigned short* p )
75 70
 {
76 71
   if( cmFileReadUShort(mfp->fh,p,1) != kOkFileRC )
77
-    return _cmMidiFileError(&mfp->err,kSysFreadFailMfRC);
72
+    return cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI short read failed.");
78 73
 
79 74
   *p = mfSwap16(*p);
80 75
 
@@ -89,7 +84,7 @@ cmMfRC_t _cmMidiFileRead24( _cmMidiFile_t* mfp, unsigned* p )
89 84
   {
90 85
     unsigned char c;
91 86
     if( cmFileReadUChar(mfp->fh,&c,1) != kOkFileRC )  
92
-      return _cmMidiFileError(&mfp->err,kSysFreadFailMfRC);
87
+      return cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI 24 bit integer read failed.");
93 88
     *p = (*p << 8) + c;
94 89
   }
95 90
 
@@ -101,7 +96,7 @@ cmMfRC_t _cmMidiFileRead24( _cmMidiFile_t* mfp, unsigned* p )
101 96
 cmMfRC_t _cmMidiFileRead32( _cmMidiFile_t* mfp, unsigned* p )
102 97
 {
103 98
   if( cmFileReadUInt(mfp->fh,p,1) != kOkFileRC )  
104
-    return _cmMidiFileError(&mfp->err,kSysFreadFailMfRC);
99
+    return cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI integer read failed.");
105 100
 
106 101
   *p = mfSwap32(*p);
107 102
 
@@ -117,7 +112,7 @@ cmMfRC_t _cmMidiFileReadText( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp, unsigne
117 112
   t[byteN] = 0;
118 113
   
119 114
   if( cmFileReadChar(mfp->fh,t,byteN) != kOkFileRC )  
120
-    return _cmMidiFileError(&mfp->err,kSysFreadFailMfRC);
115
+    return cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI read text failed.");
121 116
 
122 117
   tmp->u.text  = t;
123 118
   tmp->byteCnt = byteN;
@@ -129,7 +124,7 @@ cmMfRC_t _cmMidiFileReadRecd( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp, unsigne
129 124
   char*  t = (char*)_cmMidiFileMalloc(mfp,byteN);
130 125
   
131 126
   if( cmFileReadChar(mfp->fh,t,byteN) != kOkFileRC )  
132
-    return _cmMidiFileError(&mfp->err,kSysFreadFailMfRC);
127
+    return cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI read record failed.");
133 128
 
134 129
   tmp->byteCnt = byteN;
135 130
   tmp->u.voidPtr = t;
@@ -142,7 +137,7 @@ cmMfRC_t _cmMidiFileReadVarLen( _cmMidiFile_t* mfp, unsigned* p )
142 137
   unsigned char c;
143 138
 
144 139
   if( cmFileReadUChar(mfp->fh,&c,1) != kOkFileRC )  
145
-    return _cmMidiFileError(&mfp->err,kSysFreadFailMfRC);
140
+    return cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI read variable length integer failed.");
146 141
   
147 142
   if( !(c & 0x80) )
148 143
     *p = c;
@@ -154,7 +149,7 @@ cmMfRC_t _cmMidiFileReadVarLen( _cmMidiFile_t* mfp, unsigned* p )
154 149
     {
155 150
 
156 151
       if( cmFileReadUChar(mfp->fh,&c,1) != kOkFileRC )  
157
-        return _cmMidiFileError(&mfp->err,kSysFreadFailMfRC);
152
+        return cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI read variable length integer failed.");
158 153
 
159 154
       *p = (*p << 7) + (c & 0x7f);
160 155
     
@@ -199,7 +194,7 @@ cmMfRC_t _cmMidiFileReadSysEx( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp, unsign
199 194
 
200 195
     long offs;
201 196
     if( cmFileTell(mfp->fh,&offs) != kOkFileRC )
202
-      return _cmMidiFileError(&mfp->err,kSysFtellFailMfRC);
197
+      return cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI File 'tell' failed.");
203 198
 
204 199
     byteN = 0;
205 200
 
@@ -214,11 +209,11 @@ cmMfRC_t _cmMidiFileReadSysEx( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp, unsign
214 209
 
215 210
     // verify that the EOX byte was found
216 211
     if( b != kSysComEoxMdId )
217
-      return _cmMidiFileError(&mfp->err,kMissingEoxMfRC);
212
+      return cmErrMsg(&mfp->err,kMissingEoxMfRC,"MIDI file missing 'end-of-sys-ex'.");
218 213
 
219 214
     // rewind to the beginning of the msg
220 215
     if( cmFileSeek(mfp->fh,kBeginFileFl,offs) != kOkFileRC )
221
-      return _cmMidiFileError(&mfp->err,kSysFseekFailMfRC);
216
+      return cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file seek failed on sys-ex read.");
222 217
 
223 218
   }
224 219
 
@@ -227,7 +222,7 @@ cmMfRC_t _cmMidiFileReadSysEx( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp, unsign
227 222
 
228 223
   // read the sys-ex msg from the file into msg memory
229 224
   if( cmFileReadUChar(mfp->fh,mp,byteN) != kOkFileRC )  
230
-    return _cmMidiFileError(&mfp->err,kSysFreadFailMfRC);
225
+    return cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI sys-ex read failed.");
231 226
   
232 227
   tmp->byteCnt     = byteN;
233 228
   tmp->u.sysExPtr = mp;
@@ -239,8 +234,8 @@ cmMfRC_t _cmMidiFileReadChannelMsg( _cmMidiFile_t* mfp, cmMidiByte_t* rsPtr, cmM
239 234
 {
240 235
   cmMfRC_t       rc       = kOkMfRC;
241 236
   cmMidiChMsg_t* p        = (cmMidiChMsg_t*)_cmMidiFileMalloc(mfp,sizeof(cmMidiChMsg_t));
242
-  unsigned     useRsFl  = status <= 0x7f;
243
-  cmMidiByte_t statusCh = useRsFl ? *rsPtr : status;
237
+  unsigned       useRsFl  = status <= 0x7f;
238
+  cmMidiByte_t   statusCh = useRsFl ? *rsPtr : status;
244 239
   
245 240
   if( useRsFl )
246 241
     p->d0  = status;    
@@ -309,8 +304,7 @@ cmMfRC_t _cmMidiFileReadMetaMsg( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp )
309 304
 
310 305
     default:
311 306
       cmFileSeek(mfp->fh,kCurFileFl,byteN);
312
-      cmErrMsg(&mfp->err,kUnknownMetaIdMfRC,"Unknown meta status:0x%x %i.",metaId,metaId);
313
-      rc = _cmMidiFileError(&mfp->err,kUnknownMetaIdMfRC);
307
+      rc = cmErrMsg(&mfp->err,kUnknownMetaIdMfRC,"Unknown meta status:0x%x %i.",metaId,metaId);
314 308
   }
315 309
 
316 310
   tmp->metaId = metaId;
@@ -386,7 +380,7 @@ cmMfRC_t _cmMidiFileReadHdr( _cmMidiFile_t* mfp )
386 380
   
387 381
   // verify the file id
388 382
   if( fileId != 'MThd' )
389
-    return _cmMidiFileError(&mfp->err,kNotAMidiFileMfRC);
383
+    return cmErrMsg(&mfp->err,kNotAMidiFileMfRC,"");
390 384
 
391 385
   // read the file chunk byte count
392 386
   if((rc = _cmMidiFileRead32(mfp,&chunkByteN)) != kOkMfRC )
@@ -423,10 +417,10 @@ int _cmMidiFileSortFunc( const void *p0, const void* p1 )
423 417
 {  
424 418
   //printf("%i %i\n",(*(cmMidiTrackMsg_t**)p0)->dticks,(*(cmMidiTrackMsg_t**)p1)->dticks);
425 419
 
426
-  if( (*(cmMidiTrackMsg_t**)p0)->dtick == (*(cmMidiTrackMsg_t**)p1)->dtick )
420
+  if( (*(cmMidiTrackMsg_t**)p0)->atick == (*(cmMidiTrackMsg_t**)p1)->atick )
427 421
     return 0;
428 422
 
429
-  return (*(cmMidiTrackMsg_t**)p0)->dtick < (*(cmMidiTrackMsg_t**)p1)->dtick ? -1 : 1;  
423
+  return (*(cmMidiTrackMsg_t**)p0)->atick < (*(cmMidiTrackMsg_t**)p1)->atick ? -1 : 1;  
430 424
 }
431 425
 
432 426
 cmMfRC_t _cmMidiFileClose( _cmMidiFile_t* mfp )
@@ -440,7 +434,7 @@ cmMfRC_t _cmMidiFileClose( _cmMidiFile_t* mfp )
440 434
 
441 435
   if( cmFileIsValid( mfp->fh ) )
442 436
     if( cmFileClose( &mfp->fh ) != kOkFileRC )
443
-      rc = _cmMidiFileError(&mfp->err,kSysFcloseFailMfRC);
437
+      rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file close failed.");
444 438
     
445 439
   if( cmLHeapIsValid( mfp->lhH ) )
446 440
     cmLHeapDestroy(&mfp->lhH);
@@ -467,21 +461,21 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
467 461
 
468 462
   // allocate the midi file object 
469 463
   if(( mfp = cmMemAllocZ( _cmMidiFile_t, 1)) == NULL )
470
-    return rc = _cmMidiFileError(&err,kMemAllocFailMfRC);
464
+    return rc = cmErrMsg(&err,kMemAllocFailMfRC,"MIDI file memory allocation failed.");
471 465
 
472 466
   cmErrClone(&mfp->err,&err);
473 467
 
474 468
   // allocate the linked heap
475 469
   if( cmLHeapIsValid( mfp->lhH = cmLHeapCreate( 1024, ctx )) == false )
476 470
   {
477
-    rc = _cmMidiFileError(&err,kMemAllocFailMfRC);
471
+    rc = cmErrMsg(&err,kMemAllocFailMfRC,"MIDI heap allocation failed.");
478 472
     goto errLabel;
479 473
   }
480 474
 
481 475
   // open the file
482 476
   if(cmFileOpen(&mfp->fh,fn,kReadFileFl | kBinaryFileFl,mfp->err.rpt) != kOkFileRC )
483 477
   {
484
-    rc = _cmMidiFileError(&mfp->err,kSysFopenFailMfRC);
478
+    rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file open failed.");
485 479
     goto errLabel;
486 480
   }
487 481
 
@@ -507,7 +501,7 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
507 501
       //if( fseek( mfp->fp, chkN, SEEK_CUR) != 0 )
508 502
       if( cmFileSeek(mfp->fh,kCurFileFl,chkN) != kOkFileRC )
509 503
       {
510
-        rc = _cmMidiFileError(&mfp->err,kSysFseekFailMfRC);
504
+        rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file seek failed.");
511 505
         goto errLabel;
512 506
       }
513 507
     }  
@@ -541,7 +535,7 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
541 535
       assert( i < mfp->msgN);
542 536
 
543 537
       tick          += tmp->dtick; // convert delta-ticks to absolute ticks
544
-      tmp->dtick      = tick;
538
+      tmp->atick     = tick;
545 539
       mfp->msgV[i]   = tmp;
546 540
       tmp            = tmp->link;
547 541
       ++i;
@@ -561,6 +555,7 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
561 555
   //
562 556
   // calculate the total duration of the MIDI file and convert absolute ticks back to delta ticks
563 557
   //
558
+  /*
564 559
   unsigned mi;
565 560
   unsigned prvTick       = 0;
566 561
 
@@ -574,13 +569,14 @@ cmMfRC_t cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx )
574 569
     prvTick   = mp->dtick;
575 570
     mp->dtick = dtick;
576 571
   }
572
+  */
577 573
 
578 574
   hPtr->h = mfp;
579 575
 
580 576
  errLabel:
581 577
 
582 578
   if( cmFileClose(&mfp->fh) != kOkFileRC )
583
-    rc = _cmMidiFileError(&mfp->err,kCloseFailFileRC);
579
+    rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file close failed.");
584 580
 
585 581
   if( rc != kOkMfRC )
586 582
     _cmMidiFileClose(mfp);
@@ -604,6 +600,348 @@ cmMfRC_t        cmMidiFileClose( cmMidiFileH_t* h )
604 600
   return rc;
605 601
 }
606 602
 
603
+cmMfRC_t _cmMidiFileWrite8( _cmMidiFile_t* mfp, unsigned char v )
604
+{
605
+  cmMfRC_t rc = kOkMfRC;
606
+
607
+  if( cmFileWriteUChar(mfp->fh,&v,1) != kOkFileRC )
608
+    rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file byte write failed.");
609
+
610
+  return rc;  
611
+}
612
+
613
+cmMfRC_t _cmMidiFileWrite16( _cmMidiFile_t* mfp, unsigned short v )
614
+{
615
+  cmMfRC_t rc = kOkMfRC;
616
+
617
+  v = mfSwap16(v);
618
+
619
+  if( cmFileWriteUShort(mfp->fh,&v,1) != kOkFileRC )
620
+    rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file short integer write failed.");
621
+
622
+  return rc;
623
+}
624
+
625
+cmMfRC_t _cmMidiFileWrite24( _cmMidiFile_t* mfp, unsigned v )
626
+{
627
+  cmMfRC_t rc   = kOkMfRC;
628
+  unsigned mask = 0xff0000;
629
+  int      i;
630
+
631
+  for(i=2; i>=0; --i)
632
+  {
633
+    unsigned char c = (v & mask) >> (i*8);
634
+    mask >>= 8;
635
+
636
+    if( cmFileWriteUChar(mfp->fh,&c,1) != kOkFileRC )
637
+    {
638
+      rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file 24 bit integer write failed.");
639
+      goto errLabel;
640
+    }
641
+    
642
+  }
643
+
644
+ errLabel:
645
+  return rc;
646
+}
647
+
648
+cmMfRC_t _cmMidiFileWrite32( _cmMidiFile_t* mfp, unsigned v )
649
+{
650
+  cmMfRC_t rc = kOkMfRC;
651
+
652
+  v = mfSwap32(v);
653
+
654
+  if( cmFileWriteUInt(mfp->fh,&v,1) != kOkFileRC )
655
+    rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file integer write failed.");
656
+
657
+  return rc;
658
+}
659
+
660
+cmMfRC_t _cmMidiFileWriteRecd( _cmMidiFile_t* mfp, const void* v, unsigned byteCnt )
661
+{
662
+  cmMfRC_t rc = kOkMfRC;
663
+
664
+  if( cmFileWriteChar(mfp->fh,v,byteCnt) != kOkFileRC )  
665
+    rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file write record failed.");
666
+
667
+  return rc;
668
+}
669
+
670
+cmMfRC_t _cmMidiFileWriteVarLen( _cmMidiFile_t* mfp, unsigned v )
671
+{
672
+  cmMfRC_t rc = kOkMfRC;
673
+  unsigned buf = v & 0x7f;
674
+ 
675
+  while((v >>= 7) > 0 )
676
+  {
677
+    buf <<= 8;          
678
+    buf |= 0x80;
679
+    buf += (v & 0x7f);
680
+  }
681
+
682
+  while(1)
683
+  {
684
+    unsigned char c = (unsigned char)(buf & 0xff);
685
+    if( cmFileWriteUChar(mfp->fh,&c,1) != kOkFileRC )
686
+    {
687
+      rc = cmErrMsg(&mfp->err,kFileFailMfRC,"MIDI file variable length integer write failed.");
688
+      goto errLabel;
689
+    }
690
+
691
+    if( buf & 0x80 )
692
+      buf >>= 8;
693
+    else
694
+      break;
695
+  }
696
+
697
+ errLabel:
698
+  return rc;
699
+}
700
+
701
+cmMfRC_t _cmMidiFileWriteHdr( _cmMidiFile_t* mfp )
702
+{
703
+  cmMfRC_t rc;
704
+  unsigned fileId = 'MThd';
705
+  unsigned chunkByteN = 6;
706
+
707
+  // write the file id ('MThd')
708
+  if((rc = _cmMidiFileWrite32(mfp,fileId)) != kOkMfRC )
709
+    return rc;
710
+  
711
+  // write the file chunk byte count (always 6)
712
+  if((rc = _cmMidiFileWrite32(mfp,chunkByteN)) != kOkMfRC )
713
+    return  rc;
714
+
715
+  // write the MIDI file format id (0,1,2)
716
+  if((rc = _cmMidiFileWrite16(mfp,mfp->fmtId)) != kOkMfRC )
717
+    return rc;
718
+
719
+  // write the track count
720
+  if((rc = _cmMidiFileWrite16(mfp,mfp->trkN)) != kOkMfRC )
721
+    return rc;
722
+
723
+  unsigned short v = 0;
724
+
725
+  // if the ticks per quarter note field is valid ...
726
+  if( mfp->ticksPerQN )
727
+    v = mfp->ticksPerQN;
728
+  else
729
+  {
730
+    // ... otherwise the division field was given in smpte
731
+    v  = mfp->smpteFmtId << 8;
732
+    v += mfp->smpteTicksPerFrame;    
733
+  }
734
+
735
+  if((rc = _cmMidiFileWrite16(mfp,v)) != kOkMfRC )
736
+    return rc;
737
+
738
+  return rc;
739
+
740
+}
741
+
742
+
743
+cmMfRC_t _cmMidiFileWriteSysEx( _cmMidiFile_t* mfp, cmMidiTrackMsg_t* tmp )
744
+{
745
+  cmMfRC_t     rc = kOkMfRC;
746
+
747
+  if((rc = _cmMidiFileWrite8(mfp,kSysExMdId)) != kOkMfRC )
748
+    goto errLabel;
749
+
750
+  if( cmFileWriteUChar(mfp->fh,tmp->u.sysExPtr,tmp->byteCnt) != kOkFileRC )
751
+    rc = cmErrMsg(&mfp->err,kFileFailMfRC,"Sys-ex msg write failed.");
752
+
753
+ errLabel:
754
+  return rc;
755
+}
756
+
757
+cmMfRC_t _cmMidiFileWriteChannelMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tmp, cmMidiByte_t* runStatus )
758
+{
759
+  cmMfRC_t     rc     = kOkMfRC;
760
+  unsigned     byteN  = cmMidiStatusToByteCount(tmp->status);
761
+  cmMidiByte_t status = tmp->status + tmp->u.chMsgPtr->ch;
762
+
763
+  if( status != *runStatus )
764
+  {
765
+    *runStatus = status;
766
+    if((rc = _cmMidiFileWrite8(mfp,status)) != kOkMfRC )
767
+      goto errLabel;
768
+  }
769
+
770
+  if(byteN>=1)
771
+    if((rc = _cmMidiFileWrite8(mfp,tmp->u.chMsgPtr->d0)) != kOkMfRC )
772
+      goto errLabel;
773
+
774
+  if(byteN>=2)
775
+    if((rc = _cmMidiFileWrite8(mfp,tmp->u.chMsgPtr->d1)) != kOkMfRC )
776
+      goto errLabel;
777
+
778
+ errLabel:
779
+  return rc;
780
+}
781
+
782
+cmMfRC_t _cmMidiFileWriteMetaMsg( _cmMidiFile_t* mfp, const cmMidiTrackMsg_t* tmp )
783
+{
784
+  cmMfRC_t     rc;
785
+
786
+  if((rc = _cmMidiFileWrite8(mfp,kMetaStId)) != kOkMfRC )
787
+    return rc;
788
+
789
+  if((rc = _cmMidiFileWrite8(mfp,tmp->metaId)) != kOkMfRC )
790
+    return rc;
791
+
792
+
793
+  switch( tmp->metaId )
794
+  {
795
+    case kSeqNumbMdId:
796
+      if((rc = _cmMidiFileWrite8(mfp,sizeof(tmp->u.sVal))) == kOkMfRC )
797
+        rc = _cmMidiFileWrite16(mfp,tmp->u.sVal);
798
+      break;
799
+
800
+    case kTempoMdId:
801
+      if((rc = _cmMidiFileWrite8(mfp,3)) == kOkMfRC )
802
+        rc = _cmMidiFileWrite24(mfp,tmp->u.iVal); 
803
+      break;
804
+
805
+    case kSmpteMdId:
806
+        if((rc = _cmMidiFileWrite8(mfp,sizeof(cmMidiSmpte_t))) == kOkMfRC )
807
+          rc = _cmMidiFileWriteRecd(mfp,tmp->u.smptePtr,sizeof(cmMidiSmpte_t));
808
+        break;
809
+          
810
+    case kTimeSigMdId:
811
+        if((rc = _cmMidiFileWrite8(mfp,sizeof(cmMidiTimeSig_t))) == kOkMfRC )
812
+          rc = _cmMidiFileWriteRecd(mfp,tmp->u.timeSigPtr,sizeof(cmMidiTimeSig_t));
813
+        break;
814
+
815
+    case kKeySigMdId:
816
+        if((rc = _cmMidiFileWrite8(mfp,sizeof(cmMidiKeySig_t))) == kOkMfRC )
817
+          rc = _cmMidiFileWriteRecd(mfp,tmp->u.keySigPtr,sizeof(cmMidiKeySig_t));
818
+        break;
819
+
820
+    case kSeqSpecMdId:
821
+        if((rc = _cmMidiFileWriteVarLen(mfp,sizeof(tmp->byteCnt))) == kOkMfRC )
822
+          rc = _cmMidiFileWriteRecd(mfp,tmp->u.sysExPtr,tmp->byteCnt);
823
+        break;
824
+
825
+    case kMidiChMdId: 
826
+        if((rc = _cmMidiFileWrite8(mfp,sizeof(tmp->u.bVal))) == kOkMfRC )
827
+          rc = _cmMidiFileWrite8(mfp,tmp->u.bVal);
828
+        break;
829
+
830
+    case kEndOfTrkMdId:  
831
+      rc = _cmMidiFileWrite8(mfp,0);
832
+      break;
833
+
834
+    case kTextMdId:      
835
+    case kCopyMdId:      
836
+    case kTrkNameMdId:   
837
+    case kInstrNameMdId: 
838
+    case kLyricsMdId:    
839
+    case kMarkerMdId:    
840
+    case kCuePointMdId:  
841
+      {
842
+        unsigned n = tmp->u.text==NULL ? 0 : strlen(tmp->u.text);
843
+        if((rc = _cmMidiFileWriteVarLen(mfp,n)) == kOkMfRC && n>0 )
844
+          rc = _cmMidiFileWriteRecd(mfp,tmp->u.text,n);
845
+      }
846
+      break;
847
+
848
+    default:
849
+      {
850
+      // ignore unknown meta messages
851
+      }
852
+
853
+  }
854
+
855
+  return rc;
856
+}
857
+
858
+cmMfRC_t _cmMidiFileWriteTrack( _cmMidiFile_t* mfp, unsigned trkIdx )
859
+{
860
+  cmMfRC_t           rc        = kOkMfRC;
861
+  cmMidiTrackMsg_t*  tmp       = mfp->trkV[trkIdx].base;
862
+  cmMidiByte_t       runStatus = 0;
863
+
864
+  for(; tmp!=NULL; tmp=tmp->link)
865
+  {
866
+    // write the msg tick count
867
+    if((rc = _cmMidiFileWriteVarLen(mfp,tmp->dtick)) != kOkMfRC )
868
+      return rc;
869
+
870
+    // switch on status
871
+    switch( tmp->status )
872
+    {
873
+      // handle sys-ex msg
874
+      case kSysExMdId:
875
+        rc = _cmMidiFileWriteSysEx(mfp,tmp);
876
+        break;
877
+
878
+        // handle meta msg
879
+      case kMetaStId:
880
+        rc = _cmMidiFileWriteMetaMsg(mfp,tmp);
881
+        break;
882
+
883
+      default:
884
+        // handle channel msg
885
+        rc = _cmMidiFileWriteChannelMsg(mfp,tmp,&runStatus);
886
+
887
+    }
888
+
889
+  }
890
+
891
+  return rc;
892
+}
893
+
894
+cmMfRC_t   cmMidiFileWrite( cmMidiFileH_t h, const char* fn )
895
+{
896
+  cmMfRC_t       rc  = kOkMfRC;
897
+  _cmMidiFile_t* mfp = _cmMidiFileHandleToPtr(h);
898
+  unsigned       i;
899
+
900
+  // create the output file
901
+  if( cmFileOpen(&mfp->fh,fn,kWriteFileFl,mfp->err.rpt) != kOkFileRC )
902
+    return cmErrMsg(&mfp->err,kFileFailMfRC,"The MIDI file '%s' could not be created.",cmStringNullGuard(fn));
903
+
904
+  // write the file header
905
+  if((rc = _cmMidiFileWriteHdr(mfp)) != kOkMfRC )
906
+  {
907
+    rc = cmErrMsg(&mfp->err,rc,"The file header write failed on the MIDI file '%s'.",cmStringNullGuard(fn));
908
+    goto errLabel;
909
+  }
910
+
911
+  for(i=0; i < mfp->trkN; ++i )
912
+  {
913
+    unsigned chkId='MTrk';
914
+    long offs0,offs1;
915
+
916
+    // write the track chunk id ('MTrk')
917
+    if((rc = _cmMidiFileWrite32(mfp,chkId)) != kOkMfRC )
918
+      goto errLabel;
919
+
920
+    cmFileTell(mfp->fh,&offs0);
921
+
922
+    // write the track chunk size as zero
923
+    if((rc = _cmMidiFileWrite32(mfp,0)) != kOkMfRC )
924
+      goto errLabel;
925
+
926
+    if((rc = _cmMidiFileWriteTrack(mfp,i)) != kOkMfRC )
927
+      goto errLabel;
928
+
929
+    cmFileTell(mfp->fh,&offs1);
930
+
931
+    cmFileSeek(mfp->fh,kBeginFileFl,offs0);
932
+
933
+    _cmMidiFileWrite32(mfp,offs1-offs0-4);
934
+
935
+    cmFileSeek(mfp->fh,kBeginFileFl,offs1);
936
+    
937
+  }
938
+
939
+ errLabel:
940
+  cmFileClose(&mfp->fh);
941
+  return rc;
942
+}
943
+
944
+
607 945
 bool   cmMidiFileIsValid( cmMidiFileH_t h )
608 946
 { return !cmMidiFileIsNull(h); }
609 947
 
@@ -1070,7 +1408,7 @@ void cmMidiFileTestPrint( void* printDataPtr, const char* fmt, va_list vl )
1070 1408
 void cmMidiFileTest( const char* fn, cmCtx_t* ctx )
1071 1409
 {
1072 1410
   cmMfRC_t      rc;
1073
-  cmMidiFileH_t h;
1411
+  cmMidiFileH_t h = cmMidiFileNullHandle;
1074 1412
 
1075 1413
   if((rc = cmMidiFileOpen(fn,&h,ctx)) != kOkMfRC )
1076 1414
   {
@@ -1078,9 +1416,33 @@ void cmMidiFileTest( const char* fn, cmCtx_t* ctx )
1078 1416
     return;
1079 1417
   }
1080 1418
 
1081
-  cmMidiFilePrint(h,cmMidiFileTrackCount(h)-1,&ctx->rpt);
1082
-  
1083
-  printf("Tracks:%i\n",cmMidiFileTrackCount(h));
1419
+  if(1)
1420
+  {
1421
+    //cmMidiFilePrint(h,cmMidiFileTrackCount(h)-1,&ctx->rpt);
1422
+    cmMidiFilePrint(h,cmInvalidIdx,&ctx->rpt);
1423
+  }
1424
+  if( 0 )
1425
+  {
1426
+    printf("Tracks:%i\n",cmMidiFileTrackCount(h));
1427
+
1428
+    unsigned i = 0;
1429
+    for(i=0; i<cmMidiFileMsgCount(h); ++i)
1430
+    {
1431
+      cmMidiTrackMsg_t* tmp = (cmMidiTrackMsg_t*)cmMidiFileMsgArray(h)[i];
1432
+      
1433
+      if( tmp->status==kMetaStId && tmp->metaId == kTempoMdId )
1434
+      {
1435
+        double bpm = 60000000.0/tmp->u.iVal;
1436
+        printf("Tempo:%i %f\n",tmp->u.iVal,bpm);
1437
+
1438
+        tmp->u.iVal = floor( 60000000.0/69.0 );
1439
+
1440
+        break;
1441
+      }
1442
+    }
1443
+
1444
+    cmMidiFileWrite(h,"/home/kevin/temp/test0.mid");
1445
+  }
1084 1446
 
1085 1447
   cmMidiFileClose(&h);
1086 1448
 }

+ 14
- 15
cmMidiFile.h Ver fichero

@@ -56,13 +56,14 @@ extern "C" {
56 56
     cmMidiByte_t ch;
57 57
     cmMidiByte_t d0;
58 58
     cmMidiByte_t d1;
59
-    unsigned     durTicks; // note duration calc'd by 
59
+    unsigned     durTicks; // note duration calc'd by cmMidiFileCalcNoteDurations();
60 60
   } cmMidiChMsg_t;
61 61
 
62 62
 
63 63
   typedef struct cmMidiTrackMsg_str
64 64
   {
65 65
     unsigned                   dtick;   // delta ticks
66
+    unsigned                   atick;   
66 67
     cmMidiByte_t               status;  // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch)
67 68
     cmMidiByte_t               metaId;  //
68 69
     unsigned short             trkIdx;  //  
@@ -86,20 +87,16 @@ extern "C" {
86 87
 
87 88
   enum
88 89
   {
89
-    kOkMfRC = cmOkRC,  // 0
90
-    kSysFopenFailMfRC,  // 1
91
-    kSysFreadFailMfRC,  // 2
92
-    kSysFseekFailMfRC,  // 3
93
-    kSysFtellFailMfRC,  // 4
94
-    kSysFcloseFailMfRC, // 5
95
-    kNotAMidiFileMfRC,  // 6
96
-    kMemAllocFailMfRC,  // 7
97
-    kFileCorruptMfRC,   // 8
98
-    kMissingEoxMfRC,    // 9 
99
-    kUnknownMetaIdMfRC, // 10
100
-    kInvalidHandleMfRC, // 11
101
-    kMissingNoteOffMfRC, // 12
102
-    kInvalidStatusMfRC  // 13
90
+    kOkMfRC = cmOkRC,    // 0
91
+    kFileFailMfRC,       // 1
92
+    kNotAMidiFileMfRC,   // 7
93
+    kMemAllocFailMfRC,   // 8
94
+    kFileCorruptMfRC,    // 9
95
+    kMissingEoxMfRC,     // 10 
96
+    kUnknownMetaIdMfRC,  // 11
97
+    kInvalidHandleMfRC,  // 12
98
+    kMissingNoteOffMfRC, // 13
99
+    kInvalidStatusMfRC   // 14
103 100
   };
104 101
 
105 102
   extern cmMidiFileH_t cmMidiFileNullHandle;
@@ -107,6 +104,8 @@ extern "C" {
107 104
   cmMfRC_t              cmMidiFileOpen( const char* fn, cmMidiFileH_t* hPtr, cmCtx_t* ctx );
108 105
   cmMfRC_t              cmMidiFileClose( cmMidiFileH_t* hp );
109 106
 
107
+  cmMfRC_t              cmMidiFileWrite( cmMidiFileH_t h, const char* fn );
108
+
110 109
   bool                  cmMidiFileIsValid( cmMidiFileH_t h );
111 110
 
112 111
   // Returns track count or kInvalidCnt if 'h' is invalid.

Loading…
Cancelar
Guardar