21 #include <QStringList>
23 #include <QVarLengthArray>
27 #include "winmidioutput.h"
33 WinMIDIPacket() : dwPacket(0) {}
35 quint8 data[
sizeof(DWORD)];
38 static QLatin1Literal DEFAULT_PUBLIC_NAME = QLatin1Literal(
"MIDI Out");
40 void CALLBACK midiCallback( HMIDIOUT hmo,
46 class WinMIDIOutput::WinMIDIOutputPrivate {
51 QString m_currentOutput;
52 QMap<int,QString> m_outputDevices;
53 MIDIHDR m_midiSysexHdr;
54 QByteArray m_sysexBuffer;
55 QStringList m_excludedNames;
57 WinMIDIOutputPrivate():
60 m_publicName(DEFAULT_PUBLIC_NAME)
62 reloadDeviceList(
true);
65 void reloadDeviceList(
bool advanced)
68 MIDIOUTCAPS deviceCaps;
70 unsigned int dev, max = midiOutGetNumDevs();
71 m_outputDevices.clear();
72 m_clientFilter = !advanced;
74 for ( dev = 0; dev < max; ++dev) {
75 res = midiOutGetDevCaps( dev, &deviceCaps,
sizeof(MIDIOUTCAPS));
76 if (res != MMSYSERR_NOERROR)
78 if (m_clientFilter && (deviceCaps.wTechnology == MOD_MAPPER))
81 devName = QString::fromWCharArray(deviceCaps.szPname);
83 devName = QString::fromLocal8Bit(deviceCaps.szPname);
85 m_outputDevices[dev] = devName;
87 if (!m_clientFilter) {
89 res = midiOutGetDevCaps( dev, &deviceCaps,
sizeof(MIDIOUTCAPS));
90 if (res == MMSYSERR_NOERROR) {
92 devName = QString::fromWCharArray(deviceCaps.szPname);
94 devName = QString::fromLocal8Bit(deviceCaps.szPname);
96 m_outputDevices[dev] = devName;
101 void setPublicName(QString name)
103 if (m_publicName != name) {
108 int deviceIndex(
const QString& newOutputDevice )
111 QMap<int,QString>::ConstIterator it;
112 for( it = m_outputDevices.constBegin();
113 it != m_outputDevices.constEnd(); ++it ) {
114 if (it.value() == newOutputDevice) {
122 void open(QString name)
129 reloadDeviceList(!m_clientFilter);
130 dev = deviceIndex(name);
132 res = midiOutOpen( &m_handle, dev, (DWORD_PTR) midiCallback, (DWORD_PTR)
this, CALLBACK_FUNCTION);
133 if (res == MMSYSERR_NOERROR)
134 m_currentOutput = name;
136 qDebug() <<
"midiStreamOpen() err:" << mmErrorString(res);
144 res = midiOutReset( m_handle );
145 if (res != MMSYSERR_NOERROR)
146 qDebug() <<
"midiOutReset() err:" << mmErrorString(res);
147 res = midiOutClose( m_handle );
148 if (res == MMSYSERR_NOERROR)
149 m_currentOutput.clear();
151 qDebug() <<
"midiStreamClose() err:" << mmErrorString(res);
156 void doneHeader( LPMIDIHDR lpMidiHdr )
159 res = midiOutUnprepareHeader( m_handle, lpMidiHdr,
sizeof(MIDIHDR) );
160 if (res != MMSYSERR_NOERROR)
161 qDebug() <<
"midiOutUnprepareHeader() err:" << mmErrorString(res);
162 if ((lpMidiHdr->dwFlags & MHDR_ISSTRM) == 0)
166 void sendShortMessage(WinMIDIPacket &packet)
169 res = midiOutShortMsg( m_handle, packet.dwPacket );
170 if ( res != MMSYSERR_NOERROR )
171 qDebug() <<
"midiOutShortMsg() err:" << mmErrorString(res);
174 void sendSysexEvent(
const QByteArray& data)
177 m_sysexBuffer = data;
178 m_midiSysexHdr.lpData = (LPSTR) m_sysexBuffer.data();
179 m_midiSysexHdr.dwBufferLength = m_sysexBuffer.size();
180 m_midiSysexHdr.dwBytesRecorded = m_sysexBuffer.size();
181 m_midiSysexHdr.dwFlags = 0;
182 m_midiSysexHdr.dwUser = 0;
183 res = midiOutPrepareHeader( m_handle, &m_midiSysexHdr,
sizeof(MIDIHDR) );
184 if (res != MMSYSERR_NOERROR)
185 qDebug() <<
"midiOutPrepareHeader() err:" << mmErrorString(res);
187 res = midiOutLongMsg( m_handle, &m_midiSysexHdr,
sizeof(MIDIHDR) );
188 if (res != MMSYSERR_NOERROR)
189 qDebug() <<
"midiOutLongMsg() err:" << mmErrorString(res);
193 QString mmErrorString(MMRESULT err)
198 midiOutGetErrorText(err, &buffer[0],
sizeof(buffer));
199 errstr = QString::fromUtf16((
const ushort*)buffer);
202 midiOutGetErrorText(err, &buffer[0],
sizeof(buffer));
203 errstr = QString::fromLocal8Bit(buffer);
210 void CALLBACK midiCallback( HMIDIOUT hmo,
212 DWORD_PTR dwInstance,
219 WinMIDIOutput::WinMIDIOutputPrivate* obj = (WinMIDIOutput::WinMIDIOutputPrivate*) dwInstance;
222 obj->doneHeader( (LPMIDIHDR) dwParam1 );
225 qDebug() <<
"Open output" << hmo;
228 qDebug() <<
"Close output" << hmo;
231 qDebug() <<
"unknown output message:" << hex << wMsg;
236 WinMIDIOutput::WinMIDIOutput(
QObject *parent) :
237 MIDIOutput(parent), d(new WinMIDIOutputPrivate)
240 WinMIDIOutput::~WinMIDIOutput()
245 void WinMIDIOutput::initialize(QSettings *settings)
250 QString WinMIDIOutput::backendName()
255 QString WinMIDIOutput::publicName()
257 return d->m_publicName;
260 void WinMIDIOutput::setPublicName(QString name)
262 d->setPublicName(name);
265 QStringList WinMIDIOutput::connections(
bool advanced)
267 d->reloadDeviceList(advanced);
268 return d->m_outputDevices.values();
271 void WinMIDIOutput::setExcludedConnections(QStringList conns)
273 d->m_excludedNames = conns;
276 void WinMIDIOutput::open(QString name)
281 void WinMIDIOutput::close()
286 QString WinMIDIOutput::currentConnection()
288 return d->m_currentOutput;
291 void WinMIDIOutput::sendNoteOn(
int chan,
int note,
int vel)
293 WinMIDIPacket packet;
294 packet.data[0] = MIDI_STATUS_NOTEON | (chan & MIDI_CHANNEL_MASK);
295 packet.data[1] = note;
296 packet.data[2] = vel;
297 d->sendShortMessage(packet);
300 void WinMIDIOutput::sendNoteOff(
int chan,
int note,
int vel)
302 WinMIDIPacket packet;
303 packet.data[0] = MIDI_STATUS_NOTEOFF | (chan & MIDI_CHANNEL_MASK);
304 packet.data[1] = note;
305 packet.data[2] = vel;
306 d->sendShortMessage(packet);
309 void WinMIDIOutput::sendController(
int chan,
int control,
int value)
311 WinMIDIPacket packet;
312 packet.data[0] = MIDI_STATUS_CONTROLCHANGE | (chan & MIDI_CHANNEL_MASK);
313 packet.data[1] = control;
314 packet.data[2] = value;
315 d->sendShortMessage(packet);
318 void WinMIDIOutput::sendKeyPressure(
int chan,
int note,
int value)
320 WinMIDIPacket packet;
321 packet.data[0] = MIDI_STATUS_KEYPRESURE | (chan & MIDI_CHANNEL_MASK);
322 packet.data[1] = note;
323 packet.data[2] = value;
324 d->sendShortMessage(packet);
327 void WinMIDIOutput::sendProgram(
int chan,
int program)
329 WinMIDIPacket packet;
330 packet.data[0] = MIDI_STATUS_PROGRAMCHANGE | (chan & MIDI_CHANNEL_MASK);
331 packet.data[1] = program;
332 d->sendShortMessage(packet);
335 void WinMIDIOutput::sendChannelPressure(
int chan,
int value)
337 WinMIDIPacket packet;
338 packet.data[0] = MIDI_STATUS_CHANNELPRESSURE | (chan & MIDI_CHANNEL_MASK);
339 packet.data[1] = value;
340 d->sendShortMessage(packet);
343 void WinMIDIOutput::sendPitchBend(
int chan,
int value)
345 WinMIDIPacket packet;
346 packet.data[0] = MIDI_STATUS_PITCHBEND | (chan & MIDI_CHANNEL_MASK);
347 packet.data[1] = MIDI_LSB(value);
348 packet.data[2] = MIDI_MSB(value);
349 d->sendShortMessage(packet);
352 void WinMIDIOutput::sendSystemMsg(
const int status)
354 WinMIDIPacket packet;
355 packet.data[0] = status;
356 d->sendShortMessage(packet);
359 void WinMIDIOutput::sendSysex(
const QByteArray &data)
361 d->sendSysexEvent(data);
The QObject class is the base class of all Qt objects.