CLAM-Development  1.4.0
MIDIDevice.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 "MIDIDevice.hxx"
23 #include "MIDIIn.hxx"
24 #include "MIDIOut.hxx"
25 #include "MIDIClocker.hxx"
26 #include "MIDIEnums.hxx"
27 #include <algorithm>
28 
29 using std::find;
30 
31 using namespace CLAM;
32 
33 MIDIManager& MIDIDevice::_MIDIManager(void)
34 {
35  if (mMIDIManager==0)
36  throw Err("This MIDIDevice is not associated with any MIDIManager");
37 
38  return *mMIDIManager;
39 }
40 
41 void MIDIDevice::_SetMIDIManager(MIDIManager* am)
42 {
43  if (mMIDIManager==0) mMIDIManager = am;
44  else if (mMIDIManager!=am)
45  {
46  throw Err("An MIDIDevice can only be associated with one MIDIManager");
47  }
48 }
49 
51 {
54  mInputs.push_back(&in);
55  _SetMIDIManager(mm);
56  in.mpDevice = this;
57  return true;
58 }
59 
61 {
62  _SetMIDIManager(mm);
63  in.mpDevice = this;
64  return true;
65 }
66 
68 {
69  mOutputs.push_back(&out);
70  _SetMIDIManager(mm);
71  out.mpDevice = this;
72  return true;
73 }
74 
76 {
77  if (in.mpDevice != this)
78  {
79  throw(Err("MIDIDevice::Unregister(): I am not this MIDIIn object's device."));
80  }
81  std::vector<MIDIIn*>::iterator it = std::find(mInputs.begin(),mInputs.end(),&in);
82  if (it == mInputs.end())
83  {
84  throw(Err("MIDIDevice::Unregister(): MIDIIn object not registered in this device."));
85  }
86 
89  for (int status = 0;status<8;status++)
90  {
91  for (int channel = 0;channel<16;channel++)
92  {
93  for (int i=0;i<128;i++)
94  {
95  if (target[status][channel][i]==&in)
96  target[status][channel][i] = 0;
97  }
98  }
99  }
100 
101  mInputs.erase(it);
102  in.mpDevice = 0;
103 }
104 
106 {
107  in.mpDevice = 0;
108 }
109 
110 
112 {
113  std::vector<MIDIOut*>::iterator it = std::find(mOutputs.begin(),mOutputs.end(),&out);
114  if (it == mOutputs.end())
115  {
116  throw(Err("MIDIDevice::Unregister(): MIDIOut object not registered in this device."));
117  }
118  mOutputs.erase(it);
119  out.mpDevice = 0;
120 }
121 
122 
124 {
125  info.mName = mName;
126 }
127 
128 void MIDIDevice::SetTarget(
129  MIDI::Message msg,
130  unsigned char chn,unsigned char firstData,
131  MIDIIn* inp)
132 {
133  if (msg==MIDI::eNoteOnOff)
134  {
135  SetTarget(MIDI::eNoteOn, chn, firstData, inp);
136  SetTarget(MIDI::eNoteOff,chn, firstData, inp);
137  return;
138  }
139 
140  if (firstData==0x80)
141  {
142  for (firstData=0;firstData<128;firstData++)
143  {
144  SetTarget(msg,chn,firstData,inp);
145  }
146  return;
147  }
148 
149  if (msg==MIDI::eSystem)
150  {
151  if (chn==0)
152  {
153  CLAM_WARNING(true,"CLAM::MIDIDevice: SysEx not yet implemented");
154  return;
155  }
156  }else{
157  if (chn==0)
158  {
159  for (chn = 1;chn<=16;chn++)
160  {
161  SetTarget(msg,chn,firstData,inp);
162  }
163  return;
164  }
165  chn--;
166  }
167  target[msg][chn][firstData] = inp;
168 }
169 
171 {
172  int status ;
173 
176  for (status = 0;status<8;status++)
177  {
178  for (int channel = 0;channel<16;channel++)
179  {
180  for (int byte=0;byte<128;byte++)
181  {
182  target[status][channel][byte] = 0;
183  }
184  }
185  }
186 
187  for (unsigned int i=0; i<mInputs.size(); i++)
188  {
189  const MIDIIOConfig &cfg =
190  dynamic_cast<const MIDIIOConfig&>(mInputs[i]->GetConfig());
191 
192  SetTarget(
193  MIDI::Message(cfg.GetMessage()),
194  cfg.GetChannel(),
195  cfg.GetFirstData(),
196  mInputs[i]);
197  }
198 
199  ConcreteStart();
200 }
201 
203 {
204  ConcreteStop();
205 }
206 
207 int MIDIDevice::GetMessageLength(unsigned char byte)
208 {
210  if (cm == MIDI::eSystem)
211  {
213  return MIDI::sNBytesPerSysMsg[int(sm)];
214  }
215  else
216  {
217  mLastStatus = mData[0];
218  return MIDI::GetMessageInfo(cm).length;
219  }
220 }
221 
222 void MIDIDevice::HandleRawByte(unsigned char byte)
223 {
224  if (byte==0xfe) return;
225  if (mIndex==0)
226  {
227  if (byte&0x80)
228  {
229  mData[0] = byte;
230  mIndex = 1;
231  }
232  else
233  {
234  if (mLastStatus)
235  {
236  mData[0] = mLastStatus;
237  mData[1] = byte;
238  mIndex = 2;
239  }
240  }
242  }else
243  {
244  mData[mIndex++] = byte;
245  }
246  if (mLength && mIndex == mLength)
247  {
249  int status = ((mData[0]&0xF0)>>4)-8;
250  int channel = mData[0]&0x0F;
251  if (status == MIDI::eNoteOn && mData[2]==0)
252  {
253  status = MIDI::eNoteOff;
254  mData[0] = 0x80|channel;
256  }
257  MIDIIn* t = target[status][channel][mData[1]];
259  if (t)
260  {
261  t->Handle(mData,mLength);
262  }
263  mIndex = 0;
264  }
265 }
266