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 "InControl.hxx" 00023 #include "MIDIOutControl.hxx" 00024 #include <string> 00025 #include <cstdio> 00026 00027 namespace CLAM { 00028 00029 MIDIOutControl::MIDIOutControl():MIDIOut(false) 00030 { 00031 mpDevice = 0; 00032 InitMembers(); 00033 Configure(MIDIIOConfig()); 00034 } 00035 00036 MIDIOutControl::MIDIOutControl(const MIDIIOConfig &c):MIDIOut(false) 00037 { 00038 mpDevice = 0; 00039 InitMembers(); 00040 Configure(c); 00041 } 00042 00043 void MIDIOutControl::InitMembers(void) 00044 { 00045 mUniqId = 0; 00046 00047 mMessage = 0; 00048 mReceivedUniqId = 0; 00049 mControlIdToMsgByteId = 0; 00050 00051 mMessageSize = 0; 00052 00053 mControlledBytes = 0; 00054 mControlsReceived = 0; 00055 } 00056 00057 bool MIDIOutControl::ConcreteConfigure(const ProcessingConfig& c) 00058 throw(ErrProcessingObj) 00059 { 00060 bool ret = MIDIOut::ConcreteConfigure(c); 00061 00062 if (ret==false) return false; 00063 00064 MIDI::Message m = MIDI::Message(mConfig.GetMessage()); 00065 00066 mMessageSize = MIDI::GetMessageInfo(m).length; 00067 00068 /* the amount of controlled bytes is the lenght of the midi message, 00069 * but...: */ 00070 mControlledBytes = MIDI::GetMessageInfo(m).length; 00071 /* ... one less if we predefine the channel ... */ 00072 if (mConfig.GetChannel()!=0) mControlledBytes--; 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) mControlledBytes--; 00076 00077 mControlsReceived = 0; 00078 00079 /* allocate arrays */ 00080 if (mMessage) delete [] mMessage; 00081 mMessage = new unsigned char[mMessageSize]; 00082 00083 if (mReceivedUniqId) delete [] mReceivedUniqId; 00084 mReceivedUniqId = new unsigned char[mControlledBytes]; 00085 00086 if (mControlIdToMsgByteId) delete mControlIdToMsgByteId; 00087 mControlIdToMsgByteId = new unsigned char[mControlledBytes]; 00088 00089 /* init uniq-id-per-received-value array */ 00090 for (int i = 0; i < mControlledBytes ; i++ ) 00091 { 00092 mReceivedUniqId[i] = mUniqId; 00093 } 00094 00095 if (m==MIDI::eNoteOnOff) m = MIDI::eNoteOn; 00096 /* init first message byte, based on message type */ 00097 mStatusByte = 0x80|(int(m)<<4); 00098 00099 int ctrlid = 0; 00100 00101 /* create the InControls */ 00102 for (int i=0;i<MIDI::GetMessageInfo(m).length;i++) 00103 { 00104 const char* fieldname = 0; 00105 /* if in this switch we set the fieldname, the control 00106 * will be added */ 00107 switch (i) 00108 { 00109 case 0: 00110 if (mConfig.GetChannel()==0) 00111 /* channel is not predefined */ 00112 fieldname = "Channel"; 00113 else 00114 /* channel _is_ predefined, so modify status byte 00115 * to contain channel */ 00116 mStatusByte |= (mConfig.GetChannel()+1); 00117 break; 00118 case 1: 00119 if (mConfig.GetFirstData()==128) 00120 /* first data byte is not predefined */ 00121 fieldname = MIDI::GetMessageInfo(m).field[i-1]; 00122 else 00123 /* first data byte _is_ predefined, so modify message */ 00124 mMessage[1] = mConfig.GetFirstData(); 00125 break; 00126 default: 00127 /* all other fields will be controlled */ 00128 fieldname = MIDI::GetMessageInfo(m).field[i-1]; 00129 break; 00130 } 00131 if (fieldname) 00132 { 00133 std::string tmp = std::string() + MIDI::GetMessageInfo(m).name + ":" + fieldname; 00134 /* add the InControl, and remember which message byte it will 00135 * control */ 00136 mControlIdToMsgByteId[ctrlid] = i; 00137 mMyInControls.AddElem(new InControlTmpl<MIDIOutControl>(ctrlid++,tmp.c_str(),this,&MIDIOutControl::DoControl)); 00138 } 00139 } 00140 00141 return true; 00142 } 00143 00144 int MIDIOutControl::DoControl(int id,TControlData val) 00145 { 00146 /* we keep a uniq id to check if each message has been fully 00147 * constructed */ 00148 if (mReceivedUniqId[id]==mUniqId) 00149 { 00150 /* ok, we still needed this byte */ 00151 int i = mControlIdToMsgByteId[id]; 00152 00153 if (i==0) 00154 { 00155 /* for the first byte, we need to keep the status, and 00156 * modify the channel */ 00157 mStatusByte = (mStatusByte&0xF0) | ((unsigned char)(val)-1); 00158 }else{ 00159 mMessage[i] = (unsigned char) val; 00160 } 00161 mReceivedUniqId[id]++; 00162 mControlsReceived++; 00163 if (mControlsReceived==mControlledBytes) 00164 { 00165 /* we got all controlled bytes, so we increment the mUniqId 00166 * for the next message, reset mControlsReceived, and 00167 * call Handle to send the message to the device */ 00168 mUniqId++; 00169 mControlsReceived = 0; 00170 mMessage[0]=mStatusByte; 00171 Handle(mMessage,mMessageSize); 00172 } 00173 }else{ 00174 /* receiving a byte when the prev message was not fully 00175 * constructed yet... TODO: should we throw or assert? */ 00176 fprintf(stderr,"ERROR!!!! receiving a byte when the prev message was not fully constructed yet... TODO: should we throw or assert?\n"); 00177 } 00178 return 1; 00179 } 00180 00181 void MIDIOutControl::Handle(unsigned char* msg,int size) 00182 { 00183 /* write the message to the device */ 00184 CLAM_ASSERT(mpDevice,"MIDIOutControl used without a valid device"); 00185 if ((msg[0]&0xF0)==0x90 && msg[2]==0) msg[0] &=0x8F; 00186 mpDevice->Write(msg,size); 00187 } 00188 00189 } // namespace CLAM 00190