CLAM-Development  1.4.0
FileMIDIDevice.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2004 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 #include "MIDIIn.hxx"
23 #include "MIDIDeviceList.hxx"
24 #include "MIDIDevice.hxx"
25 
26 #include "MIDIEvent.hxx"
27 #include "MIDITrack.hxx"
28 #include "MIDISong.hxx"
29 #include "MIDITempo.hxx"
30 #include "MIDIReader.hxx"
31 #include "MIDISongPlayer.hxx"
32 
33 namespace CLAM {
34 
35  class FileMIDIDevice: public MIDIDevice
36  {
37  private:
38  std::string mFilename;
39  ::MIDI::Song mSong;
40  ::MIDI::SongPlayer mSongPlayer;
41  ::MIDI::Tempo mTempo;
42  bool mHavePendingEvent;
43  ::MIDI::Event mPendingEvent;
44  int mPendingTrackId;
45  ::MIDI::Milliseconds mPendingTime;
46  ::MIDI::Milliseconds mCurTime;
47  bool mReadDone;
48  public:
49  FileMIDIDevice(const std::string& name,const std::string& device);
50  ~FileMIDIDevice();
51 
52  void ConcreteStart(void) throw(Err);
53  void ConcreteStop(void) throw(Err);
54 
55  void Read(void) throw(Err);
56  void Write(unsigned char* msg,int size) throw(Err);
57  void SetClock(TControlData val);
58  };
59 
60  FileMIDIDevice::FileMIDIDevice(const std::string& name,const std::string& fname):
61  MIDIDevice(name)
62  {
63  mFilename = fname;
64  mHavePendingEvent = false;
65  mReadDone = false;
66  mCurTime = 0;
67  }
68 
69  void FileMIDIDevice::ConcreteStart(void) throw(Err)
70  {
71  if (!mReadDone)
72  {
73 
74  mReadDone = true;
75  ::MIDI::Reader reader(mFilename.c_str());
76 
77  if (!reader.Ok())
78  {
79  std::string str("Could not open FileMIDIDevice with file ");
80  str += mFilename;
81  throw Err(str.c_str());
82  }
83  try{
84  reader.Read(mSong);
85  }
86  catch(::MIDI::Reader::Error err)
87  {
88  throw Err(err.mStr);
89  }
90  mSongPlayer.Init(&mSong);
91  mTempo.Init(&mSong);
92 
93  }
94  }
95 
96  void FileMIDIDevice::ConcreteStop(void) throw(Err)
97  {
98  }
99 
100  void FileMIDIDevice::SetClock(TControlData val)
101  {
102  mCurTime = (::MIDI::Milliseconds) val;
103  }
104 
105  void FileMIDIDevice::Write(unsigned char* msg,int size) throw(Err)
106  {
107  throw Err("FileMIDIDevice::Write not implemented yet");
108  }
109 
110  void FileMIDIDevice::Read(void) throw(Err)
111  {
112  bool flag;
113  static int nbytesPerChnMsg[7] =
114  { 3,3,3,3,2,3,3 };
115  do
116  {
117  flag = false;
118  if (!mHavePendingEvent)
119  {
120  mHavePendingEvent =
121  mSongPlayer.GetEvent(mPendingEvent,mPendingTrackId);
122  if (mHavePendingEvent)
123  {
124  mPendingTime = mTempo.TicksToTime(mPendingEvent.GetTicks());
125  }else{
126  HandleRawByte(0xF0|int(MIDI::eStop)); // system stop
127  }
128  }
129  if (mHavePendingEvent) {
130  if (mCurTime >= mPendingTime)
131  {
132  if (
133  mPendingEvent[0] != 0xF0 &&
134  mPendingEvent[0] != 0xF7 &&
135  mPendingEvent[0] != 0xFF)
136  // skip meta events
137  {
138  int nbytes = nbytesPerChnMsg[((mPendingEvent[0]&0xF0)>>4)-8];
139  if ((mPendingEvent[0]&0xF0)==0x80)
140  {
141  HandleRawByte((mPendingEvent[0]&0x0F)|0x90);
142  HandleRawByte(mPendingEvent[1]);
143  HandleRawByte(0);
144  }else
145  for (int i = 0; i < nbytes; i++)
146  {
147  HandleRawByte(mPendingEvent[i]);
148  }
149  }
150  mHavePendingEvent = false;
151  flag = true;
152  }
153  }
154  } while (flag);
155  }
156 
157  FileMIDIDevice::~FileMIDIDevice()
158  {
159  }
160 
161  class FileMIDIDeviceList: public MIDIDeviceList
162  {
163  static FileMIDIDeviceList sDevices;
164 
165  FileMIDIDeviceList()
166  :MIDIDeviceList(std::string("file"))
167  {
168  AddMe();
169  mAvailableDevices.push_back("*.mid");
170  }
171  public:
172 
173  std::string DefaultDevice(void)
174  {
175  return "file:unknown.mid";
176  }
177 
178  MIDIDevice* Create(
179  const std::string& name,const std::string& device)
180  {
181  return new FileMIDIDevice(name,device);
182  }
183  };
184 
185  FileMIDIDeviceList FileMIDIDeviceList::sDevices;
186 }
187 
188 
189 
190 
191 
192 
193