CLAM-Development  1.4.0
MIDIWriter.cxx
Go to the documentation of this file.
1 #include "MIDITrack.hxx"
2 #include "MIDISong.hxx"
3 #include "MIDIWriter.hxx"
4 
5 namespace MIDI
6 {
7  Writer::Writer(const char* filename)
8  : mFile(0)
9  , mBytesWritten(0)
10  {
11  mFile = fopen(filename,"wb");
12  }
13 
15  {
16  }
17 
19  {
20  if(!mFile) return;
21 
22  static int nbytesPerChnMsg[7] = { 3,3,3,3,2,3,3 };
23 
24  mTracks = s.Tracks();
25  mFormat = (mTracks > 1) ? 1 : 0;
26  mDivision = (int)s.GetTicksPerQ();
27 
28  WriteHeader();
29 
30  unsigned long trkhdr=MTrk;
31  long offset,endt;
32  unsigned t0,t1;
33  for(int i=0; i < mTracks; i++)
34  {
35  // write track header
36  Write32Bit(trkhdr);
37  // remember position
38  offset = ftell(mFile);
39  Write32Bit(0);
40  mBytesWritten=0;
41  t0=t1=0;
42  Track* track = s.GetTrack(i);
43  Track::EventIterator it = track->Begin();
44  for(;it != track->End(); it++)
45  {
46  const Event &ev = **it;
47  t1=(unsigned)ev.GetTicks();
48  int type = ((ev[0]&0xF0)>>4)-8;
49  if(type==7)
50  {
51  if(ev[0]==0xFF && ev[1]==0x51)
52  {
53  // write tempo information
54  WriteVarLen(t1-t0);
55  WriteCh(0xFF);
56  WriteCh(0x51);
57  WriteCh(0x03);
58  MetaEvent* e = (MetaEvent*)*it;
59  for(int k=0; k < 3; k++)
60  {
61  WriteCh(e->mData[k]);
62  }
63  }
64  }
65  else
66  {
67  WriteVarLen(t1-t0); // write delta time
68  int msglen = nbytesPerChnMsg[type];
69  for(int j=0; j < msglen; j++)
70  {
71  WriteCh((char)ev[j]);
72  }
73  }
74  t0=t1;
75 
76  }
77  // write end of track
78  WriteCh(0);
79  WriteCh((unsigned)0xFF);
80  WriteCh((unsigned)0x2f);
81  WriteCh(0);
82  endt = ftell(mFile);
83  fseek(mFile,offset,0);
84  // write track length
85  Write32Bit(mBytesWritten);
86  // retrieve position
87  fseek(mFile,endt,0);
88  }
89  fclose(mFile);
90  }
91 
92  void Writer::WriteHeader()
93  {
94  unsigned long id=MThd;
95 
96  Write32Bit(id); // MThd
97  Write32Bit(6); // header length = 6
98  Write16Bit(mFormat); // format
99  Write16Bit(mTracks); // ntracks
100  Write16Bit(mDivision); // division
101  }
102 
103  void Writer::WriteVarLen(register unsigned long value)
104  {
105  register unsigned long buffer;
106  buffer = value & 0x7F;
107 
108  while( (value >>= 7) )
109  {
110  buffer <<= 8;
111  buffer |= ((value & 0x7F) | 0x80);
112  }
113 
114  while(1)
115  {
116  WriteCh(buffer);
117  if (buffer & 0x80)
118  buffer >>= 8;
119  else
120  break;
121  }
122  }
123 
124  void Writer::Write32Bit(unsigned long data)
125  {
126  WriteCh((unsigned)((data >> 24) & 0xff));
127  WriteCh((unsigned)((data >> 16) & 0xff));
128  WriteCh((unsigned)((data >> 8 ) & 0xff));
129  WriteCh((unsigned)(data & 0xff));
130  }
131 
132  void Writer::Write16Bit(int data)
133  {
134  WriteCh((unsigned)((data & 0xff00) >> 8));
135  WriteCh((unsigned)(data & 0xff));
136  }
137 
138  void Writer::WriteCh(char c)
139  {
140  fputc(c,mFile);
141  mBytesWritten++;
142  }
143 }
144 
145 // END
146