MIDIOutControl.cxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG)
00003  *                         UNIVERSITAT POMPEU FABRA
00004  *
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 
00022 #include "InControl.hxx"
00023 #include "MIDIOutControl.hxx"
00024 #include <string>
00025 
00026 namespace CLAM {
00027 
00028 MIDIOutControl::MIDIOutControl():MIDIOut(false)
00029 { 
00030         mpDevice = 0;
00031         InitMembers();
00032         Configure(MIDIIOConfig());
00033 }
00034 
00035 MIDIOutControl::MIDIOutControl(const MIDIIOConfig &c):MIDIOut(false)
00036 {
00037         mpDevice = 0;
00038         InitMembers();
00039         Configure(c);
00040 }
00041 
00042 void MIDIOutControl::InitMembers(void)
00043 {
00044         mUniqId = 0;
00045 
00046         mMessage = 0;
00047         mReceivedUniqId = 0;
00048         mControlIdToMsgByteId = 0;
00049 
00050         mMessageSize = 0;
00051 
00052         mControlledBytes = 0;
00053         mControlsReceived = 0;
00054 }
00055 
00056 bool MIDIOutControl::ConcreteConfigure(const ProcessingConfig& c)
00057         throw(ErrProcessingObj)
00058 {
00059         bool ret = MIDIOut::ConcreteConfigure(c);
00060         
00061         if (ret==false) return false;
00062 
00063         MIDI::Message m = MIDI::Message(mConfig.GetMessage());
00064 
00065         mMessageSize = MIDI::GetMessageInfo(m).length;
00066 
00067         /* the amount of controlled bytes is the lenght of the midi message,
00068          * but...: */
00069         mControlledBytes = MIDI::GetMessageInfo(m).length;
00070         /* ... one less if we predefine the channel ... */
00071         if (mConfig.GetChannel()!=0) mControlledBytes--;
00072         /* ... and one less if we predefine the first data byte,
00073          * which is particularly useful for control change messages */
00074         if (mConfig.GetFirstData()!=128) mControlledBytes--;
00075 
00076         mControlsReceived = 0;
00077 
00078         /* allocate arrays */
00079         if (mMessage) delete [] mMessage;
00080         mMessage = new unsigned char[mMessageSize];
00081 
00082         if (mReceivedUniqId) delete [] mReceivedUniqId;
00083         mReceivedUniqId = new unsigned char[mControlledBytes];
00084 
00085         if (mControlIdToMsgByteId) delete mControlIdToMsgByteId;
00086         mControlIdToMsgByteId = new unsigned char[mControlledBytes];
00087 
00088         /* init uniq-id-per-received-value array */
00089         for (int i = 0; i < mControlledBytes ; i++ )
00090         {
00091                 mReceivedUniqId[i] = mUniqId;
00092         }
00093         
00094         if (m==MIDI::eNoteOnOff) m = MIDI::eNoteOn;
00095         /* init first message byte, based on message type */
00096         mStatusByte = 0x80|(int(m)<<4);
00097 
00098         int ctrlid = 0;
00099         
00100         /* create the InControls */
00101         for (int i=0;i<MIDI::GetMessageInfo(m).length;i++)
00102         {
00103                 const char* fieldname = 0;
00104                 /* if in this switch we set the fieldname, the control
00105                  * will be added */
00106                 switch (i)
00107                 {
00108                         case 0:
00109                                 if (mConfig.GetChannel()==0)
00110                                         /* channel is not predefined */
00111                                         fieldname = "Channel";
00112                                 else
00113                                         /* channel _is_ predefined, so modify status byte
00114                                          * to contain channel */
00115                                         mStatusByte |= (mConfig.GetChannel()+1);
00116                                 break;
00117                         case 1:
00118                                 if (mConfig.GetFirstData()==128)
00119                                         /* first data byte is not predefined */
00120                                         fieldname = MIDI::GetMessageInfo(m).field[i-1];
00121                                 else
00122                                         /* first data byte _is_ predefined, so modify message */        
00123                                         mMessage[1] = mConfig.GetFirstData();
00124                                 break;
00125                         default:
00126                                 /* all other fields will be controlled */
00127                                 fieldname = MIDI::GetMessageInfo(m).field[i-1];
00128                                 break;
00129                 }
00130                 if (fieldname)
00131                 {
00132                         std::string controlName = std::string(MIDI::GetMessageInfo(m).name) + ":" + fieldname;
00133                         /* add the InControl, and remember which message byte it will
00134                          * control */
00135                         mControlIdToMsgByteId[ctrlid] = i;
00136                         mMyInControls.AddElem(new FloatInControl(ctrlid++,controlName,this,&MIDIOutControl::DoControl));
00137                 }
00138         }
00139 
00140         return true;
00141 }
00142 
00143 void MIDIOutControl::DoControl(unsigned id,TControlData val)
00144 {
00145         /* we keep a uniq id to check if each message has been fully 
00146          * constructed */
00147         if (mReceivedUniqId[id]!=mUniqId)
00148         {
00149                 /* receiving a byte when the prev message was not fully
00150                  * constructed yet... TODO: should we throw or assert? */
00151                 fprintf(stderr,"ERROR!!!! receiving a byte when the prev message was not fully constructed yet... TODO: should we throw or assert?\n");
00152                 return;
00153         }
00154         /* ok, we still needed this byte */
00155         int i = mControlIdToMsgByteId[id];
00156         if (i==0)
00157         {
00158                 /* for the first byte, we need to keep the status, and
00159                  * modify the channel */
00160                 mStatusByte = (mStatusByte&0xF0) | ((unsigned char)(val)-1);
00161         }else{
00162                 mMessage[i] = (unsigned char) val;
00163         }
00164         mReceivedUniqId[id]++;
00165         mControlsReceived++;
00166         if (mControlsReceived==mControlledBytes)
00167         {
00168                 /* we got all controlled bytes, so we increment the mUniqId
00169                  * for the next message, reset mControlsReceived, and 
00170                  * call Handle to send the message to the device */
00171                 mUniqId++;
00172                 mControlsReceived = 0;
00173                                         mMessage[0]=mStatusByte;
00174                 Handle(mMessage,mMessageSize);
00175         }
00176 }
00177 
00178 void MIDIOutControl::Handle(unsigned char* msg,int size)
00179 {
00180         /* write the message to the device */
00181         CLAM_ASSERT(mpDevice,"MIDIOutControl used without a valid device");
00182         if ((msg[0]&0xF0)==0x90 && msg[2]==0) msg[0] &=0x8F;
00183         mpDevice->Write(msg,size);
00184 }
00185 
00186 } // namespace CLAM
00187 
Generated by  doxygen 1.6.3