2
* midisnoop - MIDI monitor and prober
3
* Copyright (C) 2012 Devin Anderson
5
* This program is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License as published by the Free
7
* Software Foundation; either version 2 of the License, or (at your option)
10
* This program is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15
* You should have received a copy of the GNU General Public License along with
16
* this program; if not, write to the Free Software Foundation, Inc., 675 Mass
17
* Ave, Cambridge, MA 02139, USA.
22
#include <QtCore/QDateTime>
23
#include <QtCore/QDebug>
31
Engine::handleMidiInput(double timeStamp, std::vector<unsigned char> *message,
34
static_cast<Engine *>(engine)->handleMidiInput(timeStamp, message);
39
Engine::Engine(QObject *parent):
42
// Get available MIDI drivers.
43
std::vector<RtMidi::Api> apis;
44
RtMidi::getCompiledApi(apis);
45
int apiCount = apis.size();
47
for (int i = 0; i < apiCount; i++) {
48
RtMidi::Api api = apis[i];
50
case RtMidi::LINUX_ALSA:
51
driverNames.append(tr("ALSA Sequencer"));
53
case RtMidi::MACOSX_CORE:
54
driverNames.append(tr("CoreMidi"));
56
case RtMidi::UNIX_JACK:
57
driverNames.append(tr("JACK Audio Connection Kit"));
59
case RtMidi::WINDOWS_KS:
60
driverNames.append(tr("Windows Kernel Streaming"));
62
case RtMidi::WINDOWS_MM:
63
driverNames.append(tr("Windows Multimedia MIDI"));
66
qWarning() << tr("Unexpected MIDI API constant: %1").
67
arg(static_cast<int>(api));
68
// Fallthrough on purpose
69
case RtMidi::RTMIDI_DUMMY:
70
case RtMidi::UNSPECIFIED:
73
driverAPIs.append(api);
77
ignoreActiveSensingEvents = true;
78
ignoreSystemExclusiveEvents = true;
79
ignoreTimeEvents = true;
90
Engine::getDriver() const
96
Engine::getDriverCount() const
98
return driverAPIs.count();
102
Engine::getDriverName(int index) const
104
assert((index >= 0) && (index < driverAPIs.count()));
105
return driverNames[index];
109
Engine::getIgnoreActiveSensingEvents() const
111
return ignoreActiveSensingEvents;
115
Engine::getIgnoreSystemExclusiveEvents() const
117
return ignoreSystemExclusiveEvents;
121
Engine::getIgnoreTimeEvents() const
123
return ignoreTimeEvents;
127
Engine::getInputPort() const
133
Engine::getInputPortCount() const
135
return inputPortNames.count();
139
Engine::getInputPortName(int index) const
141
assert((index >= 0) && (index < inputPortNames.count()));
142
return inputPortNames[index];
146
Engine::getOutputPort() const
152
Engine::getOutputPortCount() const
154
return outputPortNames.count();
158
Engine::getOutputPortName(int index) const
160
assert((index >= 0) && (index < outputPortNames.count()));
161
return outputPortNames[index];
165
Engine::handleMidiInput(double /*timeStamp*/,
166
std::vector<unsigned char> *message)
168
quint64 timeStamp = QDateTime::currentDateTime().toMSecsSinceEpoch();
170
int size = static_cast<int>(message->size());
171
for (int i = 0; i < size; i++) {
172
msg.append(message->at(i));
174
emit messageReceived(timeStamp, msg);
178
Engine::removePorts()
182
for (int i = inputPortNames.count() - 1; i >= 0; i--) {
183
inputPortNames.removeAt(i);
184
emit inputPortRemoved(i);
186
for (int i = outputPortNames.count() - 1; i >= 0; i--) {
187
outputPortNames.removeAt(i);
188
emit outputPortRemoved(i);
193
Engine::sendMessage(const QByteArray &message)
195
assert(outputPort != -1);
196
std::vector<unsigned char> msg;
197
for (int i = 0; i < message.count(); i++) {
198
msg.push_back(static_cast<unsigned char>(message[i]));
201
output->sendMessage(&msg);
202
} catch (RtError &e) {
203
throw Error(e.what());
205
return QDateTime::currentDateTime().toMSecsSinceEpoch();
209
Engine::setDriver(int index)
211
assert((index >= -1) && (index < driverAPIs.count()));
212
if (driver != index) {
214
// Close the currently open MIDI driver.
220
emit driverChanged(-1);
223
// Open the new driver.
225
RtMidi::Api api = driverAPIs[index];
227
input = new RtMidiIn(api, "midisnoop");
228
QScopedPointer<RtMidiIn> inputPtr(input);
229
output = new RtMidiOut(api, "midisnoop");
230
QScopedPointer<RtMidiOut> outputPtr(output);
231
input->setCallback(handleMidiInput, this);
235
unsigned int count = input->getPortCount();
237
for (unsigned int i = 0; i < count; i++) {
238
name = QString::fromStdString(input->getPortName(i));
239
inputPortNames.append(name);
240
emit inputPortAdded(i, name);
242
count = output->getPortCount();
243
for (unsigned int i = 0; i < count; i++) {
244
name = QString::fromStdString(output->getPortName(i));
245
outputPortNames.append(name);
246
emit outputPortAdded(i, name);
249
// Add a virtual port to drivers that support virtual ports.
251
case RtMidi::LINUX_ALSA:
252
case RtMidi::MACOSX_CORE:
253
case RtMidi::UNIX_JACK:
254
name = tr("[virtual input]");
255
inputPortNames.append(name);
256
emit inputPortAdded(inputPortNames.count() - 1, name);
257
name = tr("[virtual output]");
258
outputPortNames.append(name);
259
emit outputPortAdded(outputPortNames.count() - 1, name);
260
virtualPortsAdded = true;
263
virtualPortsAdded = false;
271
} catch (RtError &e) {
272
throw Error(e.what());
275
emit driverChanged(index);
281
Engine::setIgnoreActiveSensingEvents(bool ignore)
283
if (ignoreActiveSensingEvents != ignore) {
284
ignoreActiveSensingEvents = ignore;
286
emit ignoreActiveSensingEventsChanged(ignore);
291
Engine::setIgnoreSystemExclusiveEvents(bool ignore)
293
if (ignoreSystemExclusiveEvents != ignore) {
294
ignoreSystemExclusiveEvents = ignore;
296
emit ignoreSystemExclusiveEventsChanged(ignore);
301
Engine::setIgnoreTimeEvents(bool ignore)
303
if (ignoreTimeEvents != ignore) {
304
ignoreTimeEvents = ignore;
306
emit ignoreTimeEventsChanged(ignore);
311
Engine::setInputPort(int index)
313
assert((index >= -1) && (index < inputPortNames.count()));
314
if (inputPort != index) {
316
// Close the currently open input port.
317
if (inputPort != -1) {
320
} catch (RtError &e) {
321
qWarning() << e.what();
324
emit inputPortChanged(-1);
327
// Open the new input port.
330
if (virtualPortsAdded &&
331
(index == (inputPortNames.count() - 1))) {
332
input->openVirtualPort("MIDI Input");
334
input->openPort(index, "MIDI Input");
336
} catch (RtError &e) {
337
throw Error(e.what());
341
emit inputPortChanged(index);
347
Engine::setOutputPort(int index)
349
assert((index >= -1) && (index < outputPortNames.count()));
350
if (outputPort != index) {
352
// Close the currently open output port.
353
if (outputPort != -1) {
356
} catch (RtError &e) {
357
qWarning() << e.what();
360
emit outputPortChanged(-1);
363
// Open the new output port.
366
if (virtualPortsAdded &&
367
(index == (outputPortNames.count() - 1))) {
368
output->openVirtualPort("MIDI Output");
370
output->openPort(index, "MIDI Output");
372
} catch (RtError &e) {
373
throw Error(e.what());
376
emit outputPortChanged(index);
382
Engine::updateEventFilter()
384
if (inputPort != -1) {
385
input->ignoreTypes(ignoreSystemExclusiveEvents, ignoreTimeEvents,
386
ignoreActiveSensingEvents);