drumstick
1.0.2
|
00001 /* 00002 Drumstick RT Backend 00003 Copyright (C) 2009-2015 Pedro Lopez-Cabanillas <plcl@users.sf.net> 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; either version 2 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License along 00016 with this program; if not, write to the Free Software Foundation, Inc., 00017 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "macmidioutput.h" 00021 #include "maccommon.h" 00022 00023 #include <QObject> 00024 #include <QDebug> 00025 #include <QString> 00026 #include <QStringList> 00027 #include <QByteArray> 00028 #include <QVarLengthArray> 00029 00030 #include <CoreFoundation/CoreFoundation.h> 00031 #include <CoreMIDI/MIDIServices.h> 00032 00033 namespace drumstick { 00034 namespace rt { 00035 00036 static CFStringRef DEFAULT_PUBLIC_NAME CFSTR("MIDI Out"); 00037 00038 class MacMIDIOutput::MacMIDIOutputPrivate { 00039 public: 00040 MIDIClientRef m_client; 00041 MIDIPortRef m_port; 00042 MIDIEndpointRef m_endpoint; 00043 MIDIEndpointRef m_destination; 00044 bool m_clientFilter; 00045 00046 QString m_currentOutput; 00047 QString m_publicName; 00048 QStringList m_excludedNames; 00049 QStringList m_outputDevices; 00050 00051 MacMIDIOutputPrivate(): 00052 m_client(0), 00053 m_port(0), 00054 m_endpoint(0), 00055 m_destination(0), 00056 m_clientFilter(true), 00057 m_publicName(QString::fromCFString(DEFAULT_PUBLIC_NAME)) 00058 { 00059 internalCreate(DEFAULT_PUBLIC_NAME); 00060 } 00061 00062 void internalCreate(CFStringRef name) 00063 { 00064 OSStatus result = noErr; 00065 result = MIDIClientCreate( name, NULL, NULL, &m_client ); 00066 if ( result != noErr ) { 00067 qDebug() << "MIDIClientCreate() error:" << result; 00068 return; 00069 } 00070 result = MIDISourceCreate( m_client, name, &m_endpoint ); 00071 if ( result != noErr ) { 00072 qDebug() << "MIDISourceCreate() error:" << result; 00073 return; 00074 } 00075 result = MIDIOutputPortCreate( m_client, name, &m_port ); 00076 if (result != noErr) { 00077 qDebug() << "MIDIOutputPortCreate() error:" << result; 00078 return; 00079 } 00080 reloadDeviceList(true); 00081 } 00082 00083 virtual ~MacMIDIOutputPrivate() 00084 { 00085 internalDispose(); 00086 } 00087 00088 void internalDispose() 00089 { 00090 OSStatus result = noErr; 00091 if (m_port != 0) { 00092 result = MIDIPortDispose( m_port ); 00093 if (result != noErr) { 00094 qDebug() << "MIDIPortDispose() error:" << result; 00095 m_port = 0; 00096 } 00097 } 00098 if (m_endpoint != 0) { 00099 result = MIDIEndpointDispose( m_endpoint ); 00100 if (result != noErr) { 00101 qDebug() << "MIDIEndpointDispose() err:" << result; 00102 m_endpoint = 0; 00103 } 00104 } 00105 if (m_client != 0) { 00106 result = MIDIClientDispose( m_client ); 00107 if (result != noErr) { 00108 qDebug() << "MIDIClientDispose() error:" << result; 00109 m_client = 0; 00110 } 00111 } 00112 } 00113 00114 void setPublicName(QString name) 00115 { 00116 if (m_publicName != name) { 00117 internalDispose(); 00118 internalCreate(name.toCFString()); 00119 m_publicName = name; 00120 } 00121 } 00122 00123 void reloadDeviceList(bool advanced) 00124 { 00125 int num = MIDIGetNumberOfDestinations(); 00126 m_clientFilter = !advanced; 00127 m_outputDevices.clear(); 00128 for (int i = 0; i < num; ++i) { 00129 bool excluded = false; 00130 MIDIEndpointRef dest = MIDIGetDestination( i ); 00131 if (dest != 0) { 00132 QString name = getEndpointName(dest); 00133 if ( m_clientFilter && 00134 name.contains(QLatin1String("IAC"), Qt::CaseSensitive) ) 00135 continue; 00136 if ( name.contains (m_publicName) ) 00137 continue; 00138 foreach ( const QString& n, m_excludedNames ) { 00139 if ( name.contains(n) ) { 00140 excluded = true; 00141 break; 00142 } 00143 } 00144 if (!excluded) 00145 m_outputDevices << name; 00146 } 00147 } 00148 if (!m_currentOutput.isEmpty() && m_destination != 0 && 00149 !m_outputDevices.contains(m_currentOutput)) { 00150 m_currentOutput.clear(); 00151 m_destination = 0; 00152 } 00153 } 00154 00155 void sendEvents( const MIDIPacketList* events ) 00156 { 00157 MIDIReceived(m_endpoint, events); 00158 if (m_destination != 0) 00159 MIDISend(m_port, m_destination, events); 00160 } 00161 00162 bool open(const QString &name) 00163 { 00164 int index; 00165 QStringList allOutputDevices; 00166 int num = MIDIGetNumberOfDestinations(); 00167 for (int i = 0; i < num; ++i) { 00168 MIDIEndpointRef dest = MIDIGetDestination( i ); 00169 if (dest != 0) 00170 allOutputDevices << getEndpointName( dest ); 00171 } 00172 index = allOutputDevices.indexOf(name); 00173 if (index < 0) 00174 return false; 00175 m_destination = MIDIGetDestination( index ); 00176 m_currentOutput = name; 00177 return true; 00178 } 00179 00180 void close() 00181 { 00182 m_destination = 0; 00183 m_currentOutput.clear(); 00184 } 00185 }; 00186 00187 MacMIDIOutput::MacMIDIOutput(QObject *parent) : 00188 MIDIOutput(parent), d(new MacMIDIOutputPrivate) 00189 { 00190 } 00191 00192 MacMIDIOutput::~MacMIDIOutput() 00193 { 00194 delete d; 00195 } 00196 00197 void MacMIDIOutput::initialize(QSettings *settings) 00198 { 00199 Q_UNUSED(settings) 00200 } 00201 00202 QString MacMIDIOutput::backendName() 00203 { 00204 return QLatin1Literal("CoreMIDI"); 00205 } 00206 00207 QString MacMIDIOutput::publicName() 00208 { 00209 return d->m_publicName; 00210 } 00211 00212 void MacMIDIOutput::setPublicName(QString name) 00213 { 00214 d->setPublicName(name); 00215 } 00216 00217 QStringList MacMIDIOutput::connections(bool advanced) 00218 { 00219 d->reloadDeviceList(advanced); 00220 return d->m_outputDevices; 00221 } 00222 00223 void MacMIDIOutput::setExcludedConnections(QStringList conns) 00224 { 00225 d->m_excludedNames = conns; 00226 } 00227 00228 void MacMIDIOutput::open(QString name) 00229 { 00230 d->open(name); 00231 } 00232 00233 void MacMIDIOutput::close() 00234 { 00235 d->close(); 00236 } 00237 00238 QString MacMIDIOutput::currentConnection() 00239 { 00240 return d->m_currentOutput; 00241 } 00242 00243 /* Realtime MIDI slots */ 00244 00245 /*void MacMIDIOutput::allNotesOff() 00246 { 00247 quint8 data[3]; 00248 quint8 buf[2048]; 00249 MIDIPacketList* pktlist = (MIDIPacketList*) &buf; 00250 MIDIPacket* packet = MIDIPacketListInit(pktlist); 00251 for(int chan = 0; chan < MIDI_CHANNELS && packet != NULL; ++chan) { 00252 data[0] = MIDI_STATUS_CONTROLCHANGE | (chan & 0x0f); 00253 data[1] = MIDI_CTL_ALL_NOTES_OFF; 00254 data[2] = 0; 00255 packet = MIDIPacketListAdd(pktlist, sizeof(buf), packet, 0, 00256 sizeof(data), data); 00257 if (packet != NULL) { 00258 data[1] = MIDI_CTL_ALL_SOUNDS_OFF; 00259 packet = MIDIPacketListAdd(pktlist, sizeof(buf), packet, 0, 00260 sizeof(data), data); 00261 } 00262 } 00263 if (packet != NULL) 00264 d->sendEvents(pktlist); 00265 }*/ 00266 00267 /*void MacMIDIOutput::resetControllers() 00268 { 00269 quint8 data[3]; 00270 quint8 buf[2048]; 00271 MIDIPacketList* pktlist = (MIDIPacketList*) &buf; 00272 MIDIPacket* packet = MIDIPacketListInit(pktlist); 00273 for(int chan = 0; chan < MIDI_CHANNELS && packet != NULL; ++chan) { 00274 data[0] = MIDI_STATUS_CONTROLCHANGE | (chan & 0x0f); 00275 data[1] = MIDI_CTL_RESET_CONTROLLERS; 00276 data[2] = 0; 00277 packet = MIDIPacketListAdd(pktlist, sizeof(buf), packet, 0, 00278 sizeof(data), data); 00279 if (packet != NULL) { 00280 data[1] = MIDI_CTL_MSB_MAIN_VOLUME; 00281 data[2] = 100; 00282 packet = MIDIPacketListAdd(pktlist, sizeof(buf), packet, 0, 00283 sizeof(data), data); 00284 } 00285 } 00286 if (packet != NULL) 00287 d->sendEvents(pktlist); 00288 }*/ 00289 00290 void MacMIDIOutput::sendNoteOn(int chan, int note, int vel) 00291 { 00292 quint8 data[3]; 00293 MIDIPacketList pktlist ; 00294 MIDIPacket* packet = MIDIPacketListInit(&pktlist); 00295 data[0] = MIDI_STATUS_NOTEON | (chan & 0x0f); 00296 data[1] = note; 00297 data[2] = vel; 00298 packet = MIDIPacketListAdd(&pktlist, sizeof(pktlist), packet, 0, 00299 sizeof(data), data); 00300 if (packet != NULL) 00301 d->sendEvents(&pktlist); 00302 } 00303 00304 void MacMIDIOutput::sendNoteOff(int chan, int note, int vel) 00305 { 00306 quint8 data[3]; 00307 MIDIPacketList pktlist ; 00308 MIDIPacket* packet = MIDIPacketListInit(&pktlist); 00309 data[0] = MIDI_STATUS_NOTEOFF | (chan & 0x0f); 00310 data[1] = note; 00311 data[2] = vel; 00312 packet = MIDIPacketListAdd(&pktlist, sizeof(pktlist), packet, 0, 00313 sizeof(data), data); 00314 if (packet != NULL) 00315 d->sendEvents(&pktlist); 00316 } 00317 00318 void MacMIDIOutput::sendController(int chan, int control, int value) 00319 { 00320 quint8 data[3]; 00321 MIDIPacketList pktlist ; 00322 MIDIPacket* packet = MIDIPacketListInit(&pktlist); 00323 data[0] = MIDI_STATUS_CONTROLCHANGE | (chan & 0x0f); 00324 data[1] = control; 00325 data[2] = value; 00326 packet = MIDIPacketListAdd(&pktlist, sizeof(pktlist), packet, 0, 00327 sizeof(data), data); 00328 if (packet != NULL) 00329 d->sendEvents(&pktlist); 00330 } 00331 00332 void MacMIDIOutput::sendKeyPressure(int chan, int note, int value) 00333 { 00334 quint8 data[3]; 00335 MIDIPacketList pktlist ; 00336 MIDIPacket* packet = MIDIPacketListInit(&pktlist); 00337 data[0] = MIDI_STATUS_KEYPRESURE | (chan & 0x0f); 00338 data[1] = note; 00339 data[2] = value; 00340 packet = MIDIPacketListAdd(&pktlist, sizeof(pktlist), packet, 0, 00341 sizeof(data), data); 00342 if (packet != NULL) 00343 d->sendEvents(&pktlist); 00344 } 00345 00346 void MacMIDIOutput::sendProgram(int chan, int program) 00347 { 00348 quint8 data[2]; 00349 MIDIPacketList pktlist ; 00350 MIDIPacket* packet = MIDIPacketListInit(&pktlist); 00351 data[0] = MIDI_STATUS_PROGRAMCHANGE | (chan & 0x0f); 00352 data[1] = program; 00353 packet = MIDIPacketListAdd(&pktlist, sizeof(pktlist), packet, 0, 00354 sizeof(data), data); 00355 if (packet != NULL) 00356 d->sendEvents(&pktlist); 00357 } 00358 00359 void MacMIDIOutput::sendChannelPressure(int chan, int value) 00360 { 00361 quint8 data[2]; 00362 MIDIPacketList pktlist ; 00363 MIDIPacket* packet = MIDIPacketListInit(&pktlist); 00364 data[0] = MIDI_STATUS_CHANNELPRESSURE | (chan & 0x0f); 00365 data[1] = value; 00366 packet = MIDIPacketListAdd(&pktlist, sizeof(pktlist), packet, 0, 00367 sizeof(data), data); 00368 if (packet != NULL) 00369 d->sendEvents(&pktlist); 00370 } 00371 00372 void MacMIDIOutput::sendPitchBend(int chan, int value) 00373 { 00374 quint16 val = value + 8192; // value between -8192 and +8191 00375 quint8 data[3]; 00376 MIDIPacketList pktlist ; 00377 MIDIPacket* packet = MIDIPacketListInit(&pktlist); 00378 data[0] = MIDI_STATUS_PITCHBEND | (chan & 0x0f); 00379 data[1] = MIDI_LSB(val); // LSB 00380 data[2] = MIDI_MSB(val); // MSB 00381 packet = MIDIPacketListAdd(&pktlist, sizeof(pktlist), packet, 0, 00382 sizeof(data), data); 00383 if (packet != NULL) 00384 d->sendEvents(&pktlist); 00385 } 00386 00387 void MacMIDIOutput::sendSysex(const QByteArray& data) 00388 { 00389 quint8 buf[4096]; 00390 if (data.size() > 4096) 00391 return; 00392 MIDIPacketList* pktlist = (MIDIPacketList*) &buf; 00393 MIDIPacket* packet = MIDIPacketListInit(pktlist); 00394 packet = MIDIPacketListAdd(pktlist, sizeof(buf), packet, 0, 00395 data.size(), (const Byte*)data.data()); 00396 if (packet != NULL) 00397 d->sendEvents(pktlist); 00398 } 00399 00400 void MacMIDIOutput::sendSystemMsg(const int status) 00401 { 00402 quint8 data; 00403 MIDIPacketList pktlist; 00404 MIDIPacket* packet = MIDIPacketListInit(&pktlist); 00405 data = status; 00406 packet = MIDIPacketListAdd(&pktlist, sizeof(pktlist), packet, 0, 00407 sizeof(data), &data); 00408 if (packet != NULL) 00409 d->sendEvents(&pktlist); 00410 } 00411 00412 }}