MIDIInControl.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 "MIDIInControl.hxx"
00023 #include "OutControl.hxx"
00024 #include <string>
00025 #include "ProcessingFactory.hxx"
00026 #include <cstdio>
00027 
00028 namespace CLAM 
00029 {
00030 
00031 namespace Hidden
00032 {
00033         static const char * metadata[] = {
00034                 "key", "MIDIInControl",
00035         //      "category", "MIDI",
00036         //      "description", "MIDIInControl",
00037                 0
00038         };
00039         static FactoryRegistrator<ProcessingFactory, MIDIInControl> reg = metadata;
00040 }
00041 
00042 MIDIInControl::MIDIInControl():MIDIIn(false)
00043 { 
00044         mpDevice = 0;
00045         mMessageSize = mControllingBytes = 0;
00046         mMsgByteIdToControlId = 0;
00047         Configure(MIDIIOConfig());
00048 }
00049 
00050 MIDIInControl::MIDIInControl(const MIDIIOConfig &c):MIDIIn(false)
00051 {
00052         mpDevice = 0;
00053         mMessageSize = mControllingBytes = 0;
00054         mMsgByteIdToControlId = 0;
00055         Configure(c);
00056 }
00057 
00058 
00059 bool MIDIInControl::ConcreteConfigure(const ProcessingConfig& c)
00060         throw(ErrProcessingObj)
00061 {
00062         bool ret = MIDIIn::ConcreteConfigure(c);
00063         if (ret==false) return false;
00064 
00065         MIDI::Message m = MIDI::Message(mConfig.GetMessage());
00066 
00067         int mMessageSize = MIDI::GetMessageInfo(m).length;
00068 
00069         /* the amount of controlled bytes is the lenght of the midi message,
00070          * but...: */
00071         mControllingBytes = mMessageSize;
00072         /* ... one less if we predefine the channel ... */
00073         if (mConfig.GetChannel()!=0) mControllingBytes--;
00074         /* ... and one less if we predefine the first data byte,
00075          * which is particularly useful for control change messages */
00076         if (mConfig.GetFirstData()!=128) mControllingBytes--;
00077 
00078         if (mMsgByteIdToControlId) delete mMsgByteIdToControlId;
00079         mMsgByteIdToControlId = new unsigned char[mControllingBytes];
00080 
00081         int ctrlid = 0;
00082         
00083         bool singlePitchBendValue = false;
00084         
00085         /* create the InControls */
00086         for (int i=0;i<mMessageSize;i++)
00087         {
00088                 const char* fieldname = 0;
00089                 /* if in this switch we set the fieldname, the control
00090                  * will be added */
00091                 switch (i)
00092                 {
00093                         case 0:
00094                                 if (mConfig.GetMessage()==MIDI::eSystem)
00095                                 {
00096                                         if (mConfig.GetChannel()==0)
00097                                                 fprintf(stderr,"ERROR: sysex in not yet implemented\n");
00098                                         else
00099                                                 /* channel is not predefined */
00100                                                 fieldname = MIDI::GetMessageInfo(m).field[i];
00101                                 }else{
00102                                         if (mConfig.GetChannel()==0)
00103                                                 /* channel is not predefined */
00104                                                 fieldname = MIDI::GetMessageInfo(m).field[i];
00105                                 }
00106                                 break;
00107                         case 1:
00108                                 if (mConfig.GetFirstData()==128)
00109                                 {
00110                                         /* first data byte is not predefined */
00111                                         fieldname = MIDI::GetMessageInfo(m).field[i];
00112                                 }
00113                                 /* we make an exception for pitchbend: instead of putting
00114                                  * out to values (LSB, MSB), we prefer 1 14bit value.
00115                                  *      see also the code in Handle
00116                                  */     
00117                                 /* nb: does a FirstData make sense with pitchbend??
00118                                  * I don't think so, so we'll just ignore it. 
00119                                  * (silently...)
00120                                  */
00121                                 if (mConfig.GetMessage()==MIDI::ePitchbend)
00122                                 {
00123                                         fieldname = "Value";
00124                                         singlePitchBendValue = true;
00125                                 }
00126                                         
00127                                 break;
00128                         default:
00129                                 /* all other fields will be controlled */
00130                                 if (!singlePitchBendValue)
00131                                 {
00132                                         fieldname = MIDI::GetMessageInfo(m).field[i];
00133                                 }
00134                                 break;
00135                 }
00136                 if (fieldname)
00137                 {
00138                         std::string tmp = std::string() + MIDI::GetMessageInfo(m).name + ":" + fieldname;
00139                         /* add the InControl, and remember which message byte it will
00140                          * control */
00141                         mMsgByteIdToControlId[i] = ctrlid++;
00142                         mMyOutControls.AddElem(new OutControl(tmp.c_str(),this));
00143                 }else{
00144                         mMsgByteIdToControlId[i] = 0xFF;
00145                 }
00146         }
00147 
00148         return true;
00149 }
00150 
00151 void MIDIInControl::Handle(unsigned char* msg,int size)
00152 {
00153         /* The device has passed the message to this MIDIInControl.
00154          * We now need dispatch the message to the resp. OutControls
00155          */
00156         for (int i=size-1;i>=0;i--)
00157         {
00158                 if (i==0 && (msg[0]&0xF0) == 0xF0) // system message
00159                 {
00160                         /* TODO: this now only handles correctly system realtime
00161                          * messages, where SetChannel is used to specify the
00162                          * type of message. Maybe this can be done more elegantly? */
00163                         SendFloatToOutControl(*this,0,1);
00164                 }
00165                 else
00166                 {
00167                         if (mMsgByteIdToControlId[i] == 0xFF) continue;
00168 
00169                         if (i==1 && (msg[0]&0xF0)==0xE0)
00170                         {
00171                                 /* we make an exception for pitchbend: instead of putting
00172                                  * out to values (LSB, MSB), we prefer 1 14bit value.
00173                                  * see also the code in ConcreteConfigure
00174                                 */
00175                                 SendFloatToOutControl(*this,mMsgByteIdToControlId[1],msg[1] + (msg[2]<<7));
00176                         }
00177                         else
00178                         if (i==0)
00179                         {
00180                                 SendFloatToOutControl(*this,mMsgByteIdToControlId[0],(msg[0]&0x0F)+1);
00181                         }
00182                         else
00183                         {       
00184                                 SendFloatToOutControl(*this,mMsgByteIdToControlId[i],msg[i]);
00185                         }
00186                 }
00187         }
00188 }
00189 
00190 
00191 } // namespace CLAM
00192 

Generated on Tue Feb 22 09:53:23 2011 for CLAM-Development by  doxygen 1.5.9