CLAM-Development  1.4.0
MIDIOutControl.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 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 "InControl.hxx"
23 #include "MIDIOutControl.hxx"
24 #include <string>
25 
26 namespace CLAM {
27 
29 {
30  mpDevice = 0;
31  InitMembers();
33 }
34 
36 {
37  mpDevice = 0;
38  InitMembers();
39  Configure(c);
40 }
41 
42 void MIDIOutControl::InitMembers(void)
43 {
44  mUniqId = 0;
45 
46  mMessage = 0;
47  mReceivedUniqId = 0;
48  mControlIdToMsgByteId = 0;
49 
50  mMessageSize = 0;
51 
52  mControlledBytes = 0;
53  mControlsReceived = 0;
54 }
55 
57  throw(ErrProcessingObj)
58 {
59  bool ret = MIDIOut::ConcreteConfigure(c);
60 
61  if (ret==false) return false;
62 
63  MIDI::Message m = MIDI::Message(mConfig.GetMessage());
64 
65  mMessageSize = MIDI::GetMessageInfo(m).length;
66 
67  /* the amount of controlled bytes is the lenght of the midi message,
68  * but...: */
69  mControlledBytes = MIDI::GetMessageInfo(m).length;
70  /* ... one less if we predefine the channel ... */
71  if (mConfig.GetChannel()!=0) mControlledBytes--;
72  /* ... and one less if we predefine the first data byte,
73  * which is particularly useful for control change messages */
74  if (mConfig.GetFirstData()!=128) mControlledBytes--;
75 
76  mControlsReceived = 0;
77 
78  /* allocate arrays */
79  if (mMessage) delete [] mMessage;
80  mMessage = new unsigned char[mMessageSize];
81 
82  if (mReceivedUniqId) delete [] mReceivedUniqId;
83  mReceivedUniqId = new unsigned char[mControlledBytes];
84 
85  if (mControlIdToMsgByteId) delete mControlIdToMsgByteId;
86  mControlIdToMsgByteId = new unsigned char[mControlledBytes];
87 
88  /* init uniq-id-per-received-value array */
89  for (int i = 0; i < mControlledBytes ; i++ )
90  {
91  mReceivedUniqId[i] = mUniqId;
92  }
93 
94  if (m==MIDI::eNoteOnOff) m = MIDI::eNoteOn;
95  /* init first message byte, based on message type */
96  mStatusByte = 0x80|(int(m)<<4);
97 
98  int ctrlid = 0;
99 
100  /* create the InControls */
101  for (int i=0;i<MIDI::GetMessageInfo(m).length;i++)
102  {
103  const char* fieldname = 0;
104  /* if in this switch we set the fieldname, the control
105  * will be added */
106  switch (i)
107  {
108  case 0:
109  if (mConfig.GetChannel()==0)
110  /* channel is not predefined */
111  fieldname = "Channel";
112  else
113  /* channel _is_ predefined, so modify status byte
114  * to contain channel */
115  mStatusByte |= (mConfig.GetChannel()+1);
116  break;
117  case 1:
118  if (mConfig.GetFirstData()==128)
119  /* first data byte is not predefined */
120  fieldname = MIDI::GetMessageInfo(m).field[i-1];
121  else
122  /* first data byte _is_ predefined, so modify message */
123  mMessage[1] = mConfig.GetFirstData();
124  break;
125  default:
126  /* all other fields will be controlled */
127  fieldname = MIDI::GetMessageInfo(m).field[i-1];
128  break;
129  }
130  if (fieldname)
131  {
132  std::string controlName = std::string(MIDI::GetMessageInfo(m).name) + ":" + fieldname;
133  /* add the InControl, and remember which message byte it will
134  * control */
135  mControlIdToMsgByteId[ctrlid] = i;
136  mMyInControls.AddElem(new FloatInControl(ctrlid++,controlName,this,&MIDIOutControl::DoControl));
137  }
138  }
139 
140  return true;
141 }
142 
143 void MIDIOutControl::DoControl(unsigned id,TControlData val)
144 {
145  /* we keep a uniq id to check if each message has been fully
146  * constructed */
147  if (mReceivedUniqId[id]!=mUniqId)
148  {
149  /* receiving a byte when the prev message was not fully
150  * constructed yet... TODO: should we throw or assert? */
151  fprintf(stderr,"ERROR!!!! receiving a byte when the prev message was not fully constructed yet... TODO: should we throw or assert?\n");
152  return;
153  }
154  /* ok, we still needed this byte */
155  int i = mControlIdToMsgByteId[id];
156  if (i==0)
157  {
158  /* for the first byte, we need to keep the status, and
159  * modify the channel */
160  mStatusByte = (mStatusByte&0xF0) | ((unsigned char)(val)-1);
161  }else{
162  mMessage[i] = (unsigned char) val;
163  }
164  mReceivedUniqId[id]++;
165  mControlsReceived++;
166  if (mControlsReceived==mControlledBytes)
167  {
168  /* we got all controlled bytes, so we increment the mUniqId
169  * for the next message, reset mControlsReceived, and
170  * call Handle to send the message to the device */
171  mUniqId++;
172  mControlsReceived = 0;
173  mMessage[0]=mStatusByte;
174  Handle(mMessage,mMessageSize);
175  }
176 }
177 
178 void MIDIOutControl::Handle(unsigned char* msg,int size)
179 {
180  /* write the message to the device */
181  CLAM_ASSERT(mpDevice,"MIDIOutControl used without a valid device");
182  if ((msg[0]&0xF0)==0x90 && msg[2]==0) msg[0] &=0x8F;
183  mpDevice->Write(msg,size);
184 }
185 
186 } // namespace CLAM
187