Just Intonation  Version 1.3.0 (18)
Explore scale-independent dynamically adapting tuning in just intonation
midi.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Copyright 2016-2017 Karolin Stange, Christoph Wick, and Haye Hinrichsen
3  *
4  * This file is part of JustIntonation.
5  *
6  * JustIntonation is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * JustIntonation is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with JustIntonation. If not, see http://www.gnu.org/licenses/.
18  *****************************************************************************/
19 
20 //=============================================================================
21 // Midi wrapper class, connecting QtMidi with JustIntonation
22 //=============================================================================
23 
24 #include "midi.h"
25 
26 #include <QMidiSystemNotifier>
27 
28 
29 //-----------------------------------------------------------------------------
30 // Constructor
31 //-----------------------------------------------------------------------------
35 
37  : QObject()
38  , pConnector()
39  , pCurrentInputDevice(nullptr)
40  , pCurrentOutputDevice(nullptr)
41 {
42  setModuleName("Midi");
43 
44  // The notifier informs us about changes in the Midi devices and their connections
45  auto notifier = new QMidiSystemNotifier(this);
46  connect(notifier, &QMidiSystemNotifier::inputDeviceAttached, this, &Midi::inputDeviceAttached);
47  connect(notifier, &QMidiSystemNotifier::outputDeviceAttached, this, &Midi::outputDeviceAttached);
48  connect(notifier, &QMidiSystemNotifier::inputDeviceDetached, this, &Midi::inputDeviceDetached);
49  connect(notifier, &QMidiSystemNotifier::outputDeviceDetached, this, &Midi::outputDeviceDetached);
50 
51  connect(notifier, &QMidiSystemNotifier::inputDeviceCreated, this, &Midi::inputDeviceCreated);
52  connect(notifier, &QMidiSystemNotifier::outputDeviceCreated, this, &Midi::outputDeviceCreated);
53  connect(notifier, &QMidiSystemNotifier::inputDeviceDeleted, this, &Midi::inputDeviceDeleted);
54  connect(notifier, &QMidiSystemNotifier::outputDeviceDeleted, this, &Midi::outputDeviceDeleted);
55 
56  // The AutoConnector is a special instance which controlls automatic connections
57  pConnector = new QMidiAutoConnector(this);
58  pConnector->setForceSingleInputDevice();
59  pConnector->setForceSingleOutputDevice();
60 
61  connect(pConnector, &QMidiAutoConnector::inputDeviceCreated,this,&Midi::acInputDeviceCreated);
62  connect(pConnector, &QMidiAutoConnector::outputDeviceCreated,this,&Midi::acOutputDeviceCreated);
63  connect(pConnector, &QMidiAutoConnector::deviceDeleted,this,&Midi::acDeviceDeleted);
64 }
65 
66 
67 //-----------------------------------------------------------------------------
68 // Initialization, making connections with Qml
69 //-----------------------------------------------------------------------------
75 
76 bool Midi::init(QObject* qml)
77 {
78  // On device changes send an unpdated list of devices to Qml
79  connect(this,SIGNAL(onInputDevicesChanged(QVariant)),
80  qml,SLOT(setQmlMidiInputDeviceNames(QVariant)));
81  connect(this,SIGNAL(onOutputDevicesChanged(QVariant)),
82  qml,SLOT(setQmlMidiOutputDeviceNames(QVariant)));
83 
84  // If the user selects an entry of the Combo box select the corresponding device
85  connect(qml,SIGNAL(onSelectedMidiInputDeviceNameChanged(QString)),
86  this,SLOT(selectInputDevice(QString)));
87  connect(qml,SIGNAL(onSelectedMidiOutputDeviceNameChanged(QString)),
88  this,SLOT(selectOutputDevice(QString)));
89 
90  // If the currently connected device changes update the headline in blue
91  connect(this,SIGNAL(onCurrentInputDeviceChanged(QVariant)),
92  qml,SLOT(setQmlSelectedMidiInputDeviceName(QVariant)));
93  connect(this,SIGNAL(onCurrentOutputDeviceChanged(QVariant)),
94  qml,SLOT(setQmlSelectedMidiOutputDeviceName(QVariant)));
95 
96  // If the user selects/deslects automatic connection these slots will be called:
97  connect(qml,SIGNAL(onAutomaticMidiInputModeChanged(bool)),
98  this,SLOT(setAutomaticInputMode(bool)));
99  connect(qml,SIGNAL(onAutomaticMidiInputModeChanged(bool)),
100  pConnector,SLOT(setAutoConnectToInput(bool)));
101  connect(qml,SIGNAL(onAutomaticMidiOutputModeChanged(bool)),
102  this,SLOT(setAutomaticOutputMode(bool)));
103  connect(qml,SIGNAL(onAutomaticMidiOutputModeChanged(bool)),
104  pConnector,SLOT(setAutoConnectToOutput(bool)));
105 
106  // Initialize available devices
107  updateAvailableDevices(QMidi::MidiInput);
108  updateAvailableDevices(QMidi::MidiOutput);
109  emit onStatusChanged();
110 
111  return true;
112 }
113 
114 
115 //-----------------------------------------------------------------------------
116 // Send a Midi message to the output device
117 //-----------------------------------------------------------------------------
125 
126 void Midi::sendMidiMessage(const QMidiMessage &event)
127 {
128  emit sendMidiEventToOutputDevice(event);
129 
130  if (getVerbosity()>=4)
131  {
132  auto hexadec = [](int i) {
133  QString s=QString("%1").arg(i , 0, 16);
134  if (s.length() == 1) s.prepend('0');
135  return s;
136  };
137  if (getVerbosity()>=4)
138  qDebug() << "Midi send " << hexadec(event.byte0())
139  << hexadec(event.byte1()) << hexadec(event.byte2());
140  }
141 }
142 
143 
144 //-----------------------------------------------------------------------------
145 // Private slot: Input device attached
146 //-----------------------------------------------------------------------------
151 
152 void Midi::inputDeviceAttached(const QMidiDeviceInfo info)
153 {
154  LOGMESSAGE << "New Midi input device attached";
155  LOGSTATUS << info;
156  updateAvailableDevices(QMidi::MidiInput);
157 }
158 
159 
160 //-----------------------------------------------------------------------------
161 // Private slot: Output device attached
162 //-----------------------------------------------------------------------------
167 
168 void Midi::outputDeviceAttached(const QMidiDeviceInfo info)
169 {
170  LOGMESSAGE << "New Midi output device attached";
171  LOGSTATUS << info;
172  updateAvailableDevices(QMidi::MidiOutput);
173 }
174 
175 
176 //-----------------------------------------------------------------------------
177 // Private slot: Input device detached
178 //-----------------------------------------------------------------------------
183 
184 void Midi::inputDeviceDetached(const QMidiDeviceInfo info)
185 {
186  LOGMESSAGE << "Midi input device detached";
187  LOGSTATUS << info;
188  updateAvailableDevices(QMidi::MidiInput);
189 }
190 
191 
192 //-----------------------------------------------------------------------------
193 // Private slot: Output device detached
194 //-----------------------------------------------------------------------------
199 
200 void Midi::outputDeviceDetached(const QMidiDeviceInfo info)
201 {
202  LOGMESSAGE << "Midi output device detached";
203  LOGSTATUS << info;
204  updateAvailableDevices(QMidi::MidiOutput);
205 }
206 
207 
208 //-----------------------------------------------------------------------------
209 // Private slot: Input device created
210 //-----------------------------------------------------------------------------
216 
217 void Midi::inputDeviceCreated(const QMidiInput *device)
218 {
219  QString devname = device->deviceInfo().deviceName();
220  LOGMESSAGE << "New Midi Input device connected" << devname;
221  emit onCurrentInputDeviceChanged(devname);
222  emit onStatusChanged();
223 }
224 
225 
226 //-----------------------------------------------------------------------------
227 // Private slot: Output device created
228 //-----------------------------------------------------------------------------
234 
235 void Midi::outputDeviceCreated(const QMidiOutput *device)
236 {
237  QString devname = device->deviceInfo().deviceName();
238  LOGMESSAGE << "New Midi Output device connected" << devname;
239  emit onCurrentOutputDeviceChanged(devname);
240  emit onStatusChanged();
241 }
242 
243 
244 //-----------------------------------------------------------------------------
245 // Private slot: Input device deleted
246 //-----------------------------------------------------------------------------
252 
253 void Midi::inputDeviceDeleted (QMidiDeviceInfo info)
254 {
255  LOGMESSAGE << "Midi Input device disconnected" << info.deviceName();
256  emit onStatusChanged();
257 }
258 
259 
260 //-----------------------------------------------------------------------------
261 // Private slot: Output device deleted
262 //-----------------------------------------------------------------------------
268 
269 void Midi::outputDeviceDeleted(QMidiDeviceInfo info)
270 {
271  LOGMESSAGE << "Midi Output device disconnected" << info.deviceName();
272  emit onStatusChanged();
273 }
274 
275 
276 //-----------------------------------------------------------------------------
277 // Private slot: Automatically connected input device created
278 //-----------------------------------------------------------------------------
283 
284 void Midi::acInputDeviceCreated(const QMidiDevice *dev)
285 {
286  QString devName = dev->deviceInfo().deviceName();
287  LOGMESSAGE << "Automatically connected to Input" << devName;
288  auto input = qobject_cast<const QMidiInput*>(dev);
289  connect(input, &QMidiInput::notify, this, &Midi::receiveMessage);
290  emit onStatusChanged();
291 }
292 
293 
294 //-----------------------------------------------------------------------------
295 // Private slot: Automatically connected output device created
296 //-----------------------------------------------------------------------------
301 
302 void Midi::acOutputDeviceCreated(const QMidiDevice *dev)
303 {
304  QString devName = dev->deviceInfo().deviceName();
305  LOGMESSAGE << "Automatically connected to Output" << devName;
306  auto output = qobject_cast<const QMidiOutput*>(dev);
307  connect(this,&Midi::sendMidiEventToOutputDevice,output,&QMidiOutput::receiveMidiMessage);
308  emit onStatusChanged();
309 }
310 
311 
312 //-----------------------------------------------------------------------------
313 // Private slot: Automatically connected device deleted (disconnected)
314 //-----------------------------------------------------------------------------
320 
321 void Midi::acDeviceDeleted(const QMidiDeviceInfo info, QMidi::Mode mode)
322 {
323  LOGMESSAGE << "Automatically disconnected from" << info.deviceName() << mode;
324  emit onStatusChanged();
325 }
326 
327 
328 //-----------------------------------------------------------------------------
329 // Private slot: Receiving a Midi message from an external Midi device
330 //-----------------------------------------------------------------------------
337 
338 void Midi::receiveMessage (const QMidiMessage &m)
339 {
340  emit receivedMidiMessage(m);
341  if (getVerbosity()>=4)
342  {
343  QString out(QString::fromLatin1("Midi message received. "));
344  if (m.size() > 0) {
345  out += QString("Cmd: %1").arg(m[0]);
346  }
347  for (int i = 1; i < m.size(); ++i) {
348  out += QString(", Byte%1: %2").arg(QString::number(i), QString::number(m[i]));
349  }
350  LOGSTATUS << out;
351  }
352 }
353 
354 
355 //-----------------------------------------------------------------------------
356 // Disconnect current input device
357 //-----------------------------------------------------------------------------
361 
363 {
365  {
366  disconnect(pCurrentInputDevice, &QMidiInput::notify,
367  this, &Midi::receiveMessage);
368  pCurrentInputDevice->deleteLater();
369  pCurrentInputDevice = nullptr;
370  }
371 }
372 
373 
374 //-----------------------------------------------------------------------------
375 // Disconnect current output device
376 //-----------------------------------------------------------------------------
380 
382 {
384  {
385  disconnect(this,&Midi::sendMidiEventToOutputDevice,
386  pCurrentOutputDevice,&QMidiOutput::receiveMidiMessage);
387  pCurrentOutputDevice->deleteLater();
388  pCurrentOutputDevice = nullptr;
389  }
390 }
391 
392 
393 //-----------------------------------------------------------------------------
394 // select input device
395 //-----------------------------------------------------------------------------
404 
405 void Midi::selectInputDevice (QString deviceName)
406 {
407  LOGMESSAGE << "Selected input device" << deviceName;
408  disconnectInput();
409  auto devices = QMidiDeviceInfo::availableDevices(QMidi::MidiInput);
410  QMidiDeviceInfo info;
411  for (QMidiDeviceInfo &dev : devices)
412  if (dev.deviceName()==deviceName) info=dev;
413  if (info.isNull())
414  {
415  onCurrentInputDeviceChanged(tr("Inactive"));
416  }
417  else
418  {
419  LOGMESSAGE << "CONNECT" << info.deviceName();
420  pCurrentInputDevice = new QMidiInput(info, this);
421  connect(pCurrentInputDevice, &QMidiInput::notify,
422  this, &Midi::receiveMessage);
423  }
424 }
425 
426 
427 //-----------------------------------------------------------------------------
428 // select onput device
429 //-----------------------------------------------------------------------------
438 
439 void Midi::selectOutputDevice (QString deviceName)
440 {
441  LOGMESSAGE << "Selected output device" << deviceName;
443  auto devices = QMidiDeviceInfo::availableDevices(QMidi::MidiOutput);
444  QMidiDeviceInfo info;
445  for (QMidiDeviceInfo &dev : devices)
446  if (dev.deviceName()==deviceName) info=dev;
447  if (info.isNull())
448  {
449  onCurrentOutputDeviceChanged(tr("Inactive"));
450  }
451  else
452  {
453  pCurrentOutputDevice = new QMidiOutput(info, this);
454  pCurrentOutputDevice->setForceTargetChannel(false,0);
455  connect(this,&Midi::sendMidiEventToOutputDevice,
456  pCurrentOutputDevice,&QMidiOutput::receiveMidiMessage);
457  }
458 
459 }
460 
461 
462 //-----------------------------------------------------------------------------
463 // Set automatic input mode
464 //-----------------------------------------------------------------------------
469 
470 void Midi::setAutomaticInputMode (bool autoconnect)
471 {
472  LOGMESSAGE << "Setting automatic Input mode =" << autoconnect;
473  // TODO no action here?
474 }
475 
476 
477 //-----------------------------------------------------------------------------
478 // Set automatic output mode
479 //-----------------------------------------------------------------------------
484 
485 void Midi::setAutomaticOutputMode(bool autoconnect)
486 {
487  LOGMESSAGE << "Setting automatic Output mode =" << autoconnect;
488  // TODO no action here?
489 }
490 
491 
492 //-----------------------------------------------------------------------------
493 // Update the shown available devices
494 //-----------------------------------------------------------------------------
499 
500 void Midi::updateAvailableDevices (QMidi::Mode mode)
501 {
502  auto devices = QMidiDeviceInfo::availableDevices(mode);
503  QStringList availableDevices;
504  for (auto &dev : devices) availableDevices.append(dev.deviceName());
505  availableDevices.prepend(tr("Inactive"));
506  availableDevices.prepend(tr("[Choose Midi device]"));
507  LOGSTATUS << "Update device names:" << availableDevices;
508  if (mode==QMidi::MidiInput) emit onInputDevicesChanged (availableDevices);
509  else if (mode==QMidi::MidiOutput) emit onOutputDevicesChanged (availableDevices);
510  //if (mode==QMidi::MidiInput) mobileError(availableDevices.join('¦'));
511 }
512 
QMidiAutoConnector * pConnector
Definition: midi.h:90
void outputDeviceDeleted(QMidiDeviceInfo info)
Private slot: Output device deleted (disconnected)
Definition: midi.cpp:269
void setModuleName(const QString &name)
Specify the name of the class-specific module.
Definition: log.cpp:82
int getVerbosity()
Get the actual verbosity level.
Definition: log.cpp:118
void disconnectInput()
Disconnect current input device.
Definition: midi.cpp:362
void onCurrentOutputDeviceChanged(QVariant device)
#define LOGMESSAGE
Definition: log.h:43
void onInputDevicesChanged(QVariant devices)
QMidiOutput * pCurrentOutputDevice
Definition: midi.h:97
bool init(QObject *qml)
Initialize the Midi wrapper and connect it with Qml.
Definition: midi.cpp:76
QMidiInput * pCurrentInputDevice
Definition: midi.h:96
void outputDeviceCreated(const QMidiOutput *device)
Private slot: Output device created (connected)
Definition: midi.cpp:235
void outputDeviceAttached(const QMidiDeviceInfo info)
Private slot: Output device attached.
Definition: midi.cpp:168
void acOutputDeviceCreated(const QMidiDevice *dev)
Private slot: Automatically connected output device created.
Definition: midi.cpp:302
void receiveMessage(const QMidiMessage &m)
Private slot: Receiving a Midi message from an external Midi device.
Definition: midi.cpp:338
void inputDeviceAttached(const QMidiDeviceInfo info)
Private slot: Input device attached.
Definition: midi.cpp:152
void inputDeviceDetached(const QMidiDeviceInfo info)
Private slot: Input device detached.
Definition: midi.cpp:184
void outputDeviceDetached(const QMidiDeviceInfo info)
Private slot: Output device detached.
Definition: midi.cpp:200
void selectInputDevice(QString deviceName)
Select the input device from a given device name.
Definition: midi.cpp:405
void setAutomaticInputMode(bool autoconnect)
Midi::setAutomaticInputMode.
Definition: midi.cpp:470
void onStatusChanged()
void sendMidiMessage(const QMidiMessage &event)
Send a Midi message to the output device.
Definition: midi.cpp:126
void acInputDeviceCreated(const QMidiDevice *dev)
Private slot: Automatically connected input device created.
Definition: midi.cpp:284
void sendMidiEventToOutputDevice(const QMidiMessage &event)
#define LOGSTATUS
Definition: log.h:42
void updateAvailableDevices(QMidi::Mode mode)
Update the shown available devices.
Definition: midi.cpp:500
void setAutomaticOutputMode(bool autoconnect)
Set automatic output mode.
Definition: midi.cpp:485
void acDeviceDeleted(const QMidiDeviceInfo info, QMidi::Mode mode)
Private slot: Automatically connected device deleted (disconnected)
Definition: midi.cpp:321
void onOutputDevicesChanged(QVariant devices)
void onCurrentInputDeviceChanged(QVariant device)
Midi()
Constructor without functionality.
Definition: midi.cpp:36
void inputDeviceDeleted(QMidiDeviceInfo info)
Private slot: Input device deleted (disconnected)
Definition: midi.cpp:253
void inputDeviceCreated(const QMidiInput *device)
Private slot: Input device created (connected)
Definition: midi.cpp:217
void disconnectOutput()
Disconnect current output device.
Definition: midi.cpp:381
void receivedMidiMessage(const QMidiMessage &event)
void selectOutputDevice(QString deviceName)
Select the output device from a given device name.
Definition: midi.cpp:439