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