|
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 "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
1.7.6.1