drumstick
1.0.2
|
00001 /* 00002 Drumstick RT Backend using the ALSA Sequencer 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 <QString> 00021 #include <QStringList> 00022 #include <QMutex> 00023 #include <QMutexLocker> 00024 #include <qmath.h> 00025 #include "alsaclient.h" 00026 #include "alsaport.h" 00027 #include "alsaevent.h" 00028 #include "alsamidioutput.h" 00029 00030 namespace drumstick { 00031 namespace rt { 00032 00033 static QString DEFAULT_PUBLIC_NAME(QLatin1String("MIDI Out")); 00034 00035 class ALSAMIDIOutput::ALSAMIDIOutputPrivate { 00036 public: 00037 ALSAMIDIOutput *m_out; 00038 MidiClient *m_client; 00039 MidiPort *m_port; 00040 int m_portId; 00041 bool m_clientFilter; 00042 int m_runtimeAlsaNum; 00043 QString m_publicName; 00044 QString m_currentOutput; 00045 QStringList m_outputDevices; 00046 QStringList m_excludedNames; 00047 QMutex m_outMutex; 00048 00049 ALSAMIDIOutputPrivate(ALSAMIDIOutput *q): 00050 m_out(q), 00051 m_client(0), 00052 m_port(0), 00053 m_portId(0), 00054 m_clientFilter(true), 00055 m_runtimeAlsaNum(0), 00056 m_publicName(DEFAULT_PUBLIC_NAME) 00057 { 00058 m_runtimeAlsaNum = getRuntimeALSALibraryNumber(); 00059 m_client = new MidiClient(m_out); 00060 m_client->open(); 00061 m_client->setClientName(m_publicName); 00062 m_port = m_client->createPort(); 00063 m_port->setPortName("out"); 00064 m_port->setCapability( SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ ); 00065 m_port->setPortType( SND_SEQ_PORT_TYPE_APPLICATION | SND_SEQ_PORT_TYPE_MIDI_GENERIC ); 00066 m_portId = m_port->getPortId(); 00067 } 00068 00069 ~ALSAMIDIOutputPrivate() 00070 { 00071 if (m_client != NULL) { 00072 clearSubscription(); 00073 if (m_port != NULL) 00074 m_port->detach(); 00075 m_client->close(); 00076 delete m_client; 00077 } 00078 } 00079 00080 bool clientIsAdvanced(int clientId) 00081 { 00082 // asking for runtime version instead of SND_LIB_VERSION 00083 if (m_runtimeAlsaNum < 0x01000B) 00084 // ALSA <= 1.0.10 00085 return (clientId < 64); 00086 else 00087 // ALSA >= 1.0.11 00088 return (clientId < 16); 00089 } 00090 00091 void reloadDeviceList(bool advanced) 00092 { 00093 m_clientFilter = !advanced; 00094 m_outputDevices.clear(); 00095 QListIterator<PortInfo> it(m_client->getAvailableOutputs()); 00096 while(it.hasNext()) { 00097 bool excluded = false; 00098 PortInfo p = it.next(); 00099 QString name = QString("%1:%2").arg(p.getClientName()).arg(p.getPort()); 00100 if (m_clientFilter && clientIsAdvanced(p.getClient())) 00101 continue; 00102 if ( m_clientFilter && name.startsWith(QLatin1String("Virtual Raw MIDI")) ) 00103 continue; 00104 if ( name.startsWith(m_publicName) ) 00105 continue; 00106 foreach(const QString& n, m_excludedNames) { 00107 if ( name.startsWith(n) ) { 00108 excluded = true; 00109 break; 00110 } 00111 } 00112 if (!excluded) 00113 m_outputDevices << name; 00114 } 00115 if (!m_currentOutput.isEmpty() && 00116 !m_outputDevices.contains(m_currentOutput)) { 00117 m_currentOutput.clear(); 00118 } 00119 } 00120 00121 bool setSubscription(const QString &newOutputDevice) 00122 { 00123 //qDebug() << Q_FUNC_INFO << newOutputDevice; 00124 if (m_outputDevices.contains(newOutputDevice)) { 00125 m_currentOutput = newOutputDevice; 00126 m_port->unsubscribeAll(); 00127 m_port->subscribeTo(newOutputDevice); 00128 return true; 00129 } 00130 return false; 00131 } 00132 00133 void clearSubscription() 00134 { 00135 if (!m_currentOutput.isEmpty()) { 00136 m_port->unsubscribeAll(); 00137 m_currentOutput.clear(); 00138 } 00139 } 00140 00141 void sendEvent(SequencerEvent *ev) 00142 { 00143 QMutexLocker locker(&m_outMutex); 00144 ev->setSource(m_portId); 00145 ev->setSubscribers(); 00146 ev->setDirect(); 00147 m_client->outputDirect(ev); 00148 } 00149 00150 void setPublicName(QString newName) 00151 { 00152 if (newName != m_publicName) { 00153 m_client->setClientName(newName); 00154 m_publicName = newName; 00155 } 00156 } 00157 00158 }; 00159 00160 ALSAMIDIOutput::ALSAMIDIOutput(QObject *parent) : MIDIOutput(parent), 00161 d(new ALSAMIDIOutputPrivate(this)) 00162 { } 00163 00164 ALSAMIDIOutput::~ALSAMIDIOutput() 00165 { 00166 delete d; 00167 } 00168 00169 void ALSAMIDIOutput::initialize(QSettings* settings) 00170 { 00171 Q_UNUSED(settings) 00172 } 00173 00174 /* SLOTS */ 00175 00176 void ALSAMIDIOutput::sendNoteOn(int chan, int note, int vel) 00177 { 00178 NoteOnEvent ev(chan, note, vel); 00179 d->sendEvent(&ev); 00180 } 00181 00182 void ALSAMIDIOutput::sendNoteOff(int chan, int note, int vel) 00183 { 00184 NoteOffEvent ev(chan, note, vel); 00185 d->sendEvent(&ev); 00186 } 00187 00188 void ALSAMIDIOutput::sendController(int chan, int control, int value) 00189 { 00190 ControllerEvent ev(chan, control, value); 00191 d->sendEvent(&ev); 00192 } 00193 00194 void ALSAMIDIOutput::sendKeyPressure(int chan, int note, int value) 00195 { 00196 KeyPressEvent ev(chan, note, value); 00197 d->sendEvent(&ev); 00198 } 00199 00200 void ALSAMIDIOutput::sendProgram(int chan, int program) 00201 { 00202 ProgramChangeEvent ev(chan, program); 00203 d->sendEvent(&ev); 00204 } 00205 00206 void ALSAMIDIOutput::sendChannelPressure(int chan, int value) 00207 { 00208 ChanPressEvent ev(chan, value); 00209 d->sendEvent(&ev); 00210 } 00211 00212 void ALSAMIDIOutput::sendPitchBend(int chan, int value) 00213 { 00214 PitchBendEvent ev(chan, value); 00215 d->sendEvent(&ev); 00216 } 00217 00218 void ALSAMIDIOutput::sendSysex(const QByteArray& data) 00219 { 00220 SysExEvent ev(data); 00221 d->sendEvent(&ev); 00222 } 00223 00224 void ALSAMIDIOutput::sendSystemMsg(const int status) 00225 { 00226 SystemEvent ev(status); 00227 d->sendEvent(&ev); 00228 } 00229 00230 QString ALSAMIDIOutput::backendName() 00231 { 00232 return "ALSA"; 00233 } 00234 00235 QString ALSAMIDIOutput::publicName() 00236 { 00237 return d->m_publicName; 00238 } 00239 00240 void ALSAMIDIOutput::setPublicName(QString name) 00241 { 00242 d->setPublicName(name); 00243 } 00244 00245 QStringList ALSAMIDIOutput::connections(bool advanced) 00246 { 00247 d->reloadDeviceList(advanced); 00248 return d->m_outputDevices; 00249 } 00250 00251 void ALSAMIDIOutput::setExcludedConnections(QStringList conns) 00252 { 00253 d->m_excludedNames = conns; 00254 } 00255 00256 QString ALSAMIDIOutput::currentConnection() 00257 { 00258 return d->m_currentOutput; 00259 } 00260 00261 void ALSAMIDIOutput::open(QString name) 00262 { 00263 d->setSubscription(name); 00264 } 00265 00266 void ALSAMIDIOutput::close() 00267 { 00268 d->clearSubscription(); 00269 } 00270 00271 }} 00272