CLAM-Development
1.1
|
00001 #include "MIDITrack.hxx" 00002 #include "MIDISong.hxx" 00003 #include "MIDIWriter.hxx" 00004 00005 namespace MIDI 00006 { 00007 Writer::Writer(const char* filename) 00008 : mFile(0) 00009 , mBytesWritten(0) 00010 { 00011 mFile = fopen(filename,"wb"); 00012 } 00013 00014 Writer::~Writer() 00015 { 00016 } 00017 00018 void Writer::Write(Song& s) 00019 { 00020 if(!mFile) return; 00021 00022 static int nbytesPerChnMsg[7] = { 3,3,3,3,2,3,3 }; 00023 00024 mTracks = s.Tracks(); 00025 mFormat = (mTracks > 1) ? 1 : 0; 00026 mDivision = (int)s.GetTicksPerQ(); 00027 00028 WriteHeader(); 00029 00030 unsigned long trkhdr=MTrk; 00031 long offset,endt; 00032 unsigned t0,t1; 00033 for(int i=0; i < mTracks; i++) 00034 { 00035 // write track header 00036 Write32Bit(trkhdr); 00037 // remember position 00038 offset = ftell(mFile); 00039 Write32Bit(0); 00040 mBytesWritten=0; 00041 t0=t1=0; 00042 Track* track = s.GetTrack(i); 00043 Track::EventIterator it = track->Begin(); 00044 for(;it != track->End(); it++) 00045 { 00046 const Event &ev = **it; 00047 t1=(unsigned)ev.GetTicks(); 00048 int type = ((ev[0]&0xF0)>>4)-8; 00049 if(type==7) 00050 { 00051 if(ev[0]==0xFF && ev[1]==0x51) 00052 { 00053 // write tempo information 00054 WriteVarLen(t1-t0); 00055 WriteCh(0xFF); 00056 WriteCh(0x51); 00057 WriteCh(0x03); 00058 MetaEvent* e = (MetaEvent*)*it; 00059 for(int k=0; k < 3; k++) 00060 { 00061 WriteCh(e->mData[k]); 00062 } 00063 } 00064 } 00065 else 00066 { 00067 WriteVarLen(t1-t0); // write delta time 00068 int msglen = nbytesPerChnMsg[type]; 00069 for(int j=0; j < msglen; j++) 00070 { 00071 WriteCh((char)ev[j]); 00072 } 00073 } 00074 t0=t1; 00075 00076 } 00077 // write end of track 00078 WriteCh(0); 00079 WriteCh((unsigned)0xFF); 00080 WriteCh((unsigned)0x2f); 00081 WriteCh(0); 00082 endt = ftell(mFile); 00083 fseek(mFile,offset,0); 00084 // write track length 00085 Write32Bit(mBytesWritten); 00086 // retrieve position 00087 fseek(mFile,endt,0); 00088 } 00089 fclose(mFile); 00090 } 00091 00092 void Writer::WriteHeader() 00093 { 00094 unsigned long id=MThd; 00095 00096 Write32Bit(id); // MThd 00097 Write32Bit(6); // header length = 6 00098 Write16Bit(mFormat); // format 00099 Write16Bit(mTracks); // ntracks 00100 Write16Bit(mDivision); // division 00101 } 00102 00103 void Writer::WriteVarLen(register unsigned long value) 00104 { 00105 register unsigned long buffer; 00106 buffer = value & 0x7F; 00107 00108 while( (value >>= 7) ) 00109 { 00110 buffer <<= 8; 00111 buffer |= ((value & 0x7F) | 0x80); 00112 } 00113 00114 while(1) 00115 { 00116 WriteCh(buffer); 00117 if (buffer & 0x80) 00118 buffer >>= 8; 00119 else 00120 break; 00121 } 00122 } 00123 00124 void Writer::Write32Bit(unsigned long data) 00125 { 00126 WriteCh((unsigned)((data >> 24) & 0xff)); 00127 WriteCh((unsigned)((data >> 16) & 0xff)); 00128 WriteCh((unsigned)((data >> 8 ) & 0xff)); 00129 WriteCh((unsigned)(data & 0xff)); 00130 } 00131 00132 void Writer::Write16Bit(int data) 00133 { 00134 WriteCh((unsigned)((data & 0xff00) >> 8)); 00135 WriteCh((unsigned)(data & 0xff)); 00136 } 00137 00138 void Writer::WriteCh(char c) 00139 { 00140 fputc(c,mFile); 00141 mBytesWritten++; 00142 } 00143 } 00144 00145 // END 00146