CLAM-Development
1.1
|
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