Implemented Midi devices changed notification for CoreMidi
This commit is contained in:
parent
e285f6ef87
commit
784bed3d97
7 changed files with 76 additions and 68 deletions
|
@ -31,7 +31,7 @@
|
|||
namespace mu::midi {
|
||||
class IMidiOutPort : MODULE_EXPORT_INTERFACE
|
||||
{
|
||||
INTERFACE_ID(IMidiPort)
|
||||
INTERFACE_ID(IMidiOutPort)
|
||||
|
||||
public:
|
||||
virtual ~IMidiOutPort() = default;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
using namespace mu::midi;
|
||||
|
||||
std::vector<MidiDevice> DummyMidiOutPort::devices() const
|
||||
MidiDeviceList DummyMidiOutPort::devices() const
|
||||
{
|
||||
MidiDevice d;
|
||||
d.id = "dummy";
|
||||
|
@ -34,7 +34,12 @@ std::vector<MidiDevice> DummyMidiOutPort::devices() const
|
|||
return { d };
|
||||
}
|
||||
|
||||
mu::Ret DummyMidiOutPort::connect(const std::string& deviceID)
|
||||
mu::async::Notification DummyMidiOutPort::devicesChanged() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
mu::Ret DummyMidiOutPort::connect(const MidiDeviceID& deviceID)
|
||||
{
|
||||
LOGI() << "deviceID: " << deviceID;
|
||||
m_connectedDeviceID = deviceID;
|
||||
|
@ -52,7 +57,7 @@ bool DummyMidiOutPort::isConnected() const
|
|||
return !m_connectedDeviceID.empty();
|
||||
}
|
||||
|
||||
std::string DummyMidiOutPort::deviceID() const
|
||||
MidiDeviceID DummyMidiOutPort::deviceID() const
|
||||
{
|
||||
return m_connectedDeviceID;
|
||||
}
|
||||
|
|
|
@ -28,19 +28,18 @@ namespace mu::midi {
|
|||
class DummyMidiOutPort : public IMidiOutPort
|
||||
{
|
||||
public:
|
||||
MidiDeviceList devices() const override;
|
||||
async::Notification devicesChanged() const override;
|
||||
|
||||
std::vector<MidiDevice> devices() const override;
|
||||
|
||||
Ret connect(const std::string& deviceID) override;
|
||||
Ret connect(const MidiDeviceID& deviceID) override;
|
||||
void disconnect() override;
|
||||
bool isConnected() const override;
|
||||
std::string deviceID() const override;
|
||||
MidiDeviceID deviceID() const override;
|
||||
|
||||
Ret sendEvent(const Event& e) override;
|
||||
|
||||
private:
|
||||
|
||||
std::string m_connectedDeviceID;
|
||||
MidiDeviceID m_connectedDeviceID;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -42,25 +42,6 @@ CoreMidiInPort::CoreMidiInPort()
|
|||
{
|
||||
m_core = std::unique_ptr<Core>(new Core());
|
||||
initCore();
|
||||
|
||||
m_devicesListener.startWithCallback([this]() {
|
||||
return devices();
|
||||
});
|
||||
|
||||
m_devicesListener.devicesChanged().onNotify(this, [this]() {
|
||||
bool connectedDeviceRemoved = true;
|
||||
for (const MidiDevice& device: devices()) {
|
||||
if (m_deviceID == device.id) {
|
||||
connectedDeviceRemoved = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (connectedDeviceRemoved) {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
m_devicesChanged.notify();
|
||||
});
|
||||
}
|
||||
|
||||
CoreMidiInPort::~CoreMidiInPort()
|
||||
|
@ -84,7 +65,6 @@ CoreMidiInPort::~CoreMidiInPort()
|
|||
|
||||
MidiDeviceList CoreMidiInPort::devices() const
|
||||
{
|
||||
std::lock_guard lock(m_devicesMutex);
|
||||
MidiDeviceList ret;
|
||||
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||
|
@ -130,8 +110,7 @@ static void proccess(const MIDIPacketList* list, void* readProc, void* srcConn)
|
|||
uint32_t message(0);
|
||||
memcpy(&message, packet->data, std::min(sizeof(message), sizeof(char) * packet->length));
|
||||
self->doProcess(message, packet->timeStamp);
|
||||
}
|
||||
if (packet->length > 4) {
|
||||
} else if (packet->length > 4) {
|
||||
LOGW() << "unsupported midi message size " << packet->length << " bytes";
|
||||
}
|
||||
|
||||
|
@ -143,14 +122,42 @@ void CoreMidiInPort::initCore()
|
|||
{
|
||||
OSStatus result;
|
||||
|
||||
static auto onCoreMidiNotificationReceived = [](const MIDINotification* notification, void* refCon) {
|
||||
auto self = static_cast<CoreMidiInPort*>(refCon);
|
||||
IF_ASSERT_FAILED(self) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (notification->messageID) {
|
||||
case kMIDIMsgObjectAdded:
|
||||
case kMIDIMsgObjectRemoved:
|
||||
self->devicesChanged().notify();
|
||||
break;
|
||||
|
||||
// General message that should be ignored because we handle specific ones
|
||||
case kMIDIMsgSetupChanged:
|
||||
|
||||
// Questionable whether we should send a notification for this ones
|
||||
// Possibly we should send a notification when the changed property is the device name
|
||||
case kMIDIMsgPropertyChanged:
|
||||
case kMIDIMsgThruConnectionsChanged:
|
||||
case kMIDIMsgSerialPortOwnerChanged:
|
||||
|
||||
case kMIDIMsgIOError:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
QString name = "MuseScore";
|
||||
result = MIDIClientCreate(name.toCFString(), nullptr, nullptr, &m_core->client);
|
||||
result = MIDIClientCreate(name.toCFString(), onCoreMidiNotificationReceived, this, &m_core->client);
|
||||
IF_ASSERT_FAILED(result == noErr) {
|
||||
LOGE() << "failed create midi input client";
|
||||
return;
|
||||
}
|
||||
|
||||
QString portName = "MuseScore MIDI input port";
|
||||
// TODO: MIDIInputPortCreate is deprecated according to the documentation.
|
||||
// Need to use MIDIInputPortCreateWithProtocol instead.
|
||||
result = MIDIInputPortCreate(m_core->client, portName.toCFString(), proccess, this, &m_core->inputPort);
|
||||
IF_ASSERT_FAILED(result == noErr) {
|
||||
LOGE() << "failed create midi input port";
|
||||
|
|
|
@ -24,12 +24,10 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "async/asyncable.h"
|
||||
#include "imidiinport.h"
|
||||
#include "internal/midideviceslistener.h"
|
||||
|
||||
namespace mu::midi {
|
||||
class CoreMidiInPort : public IMidiInPort, public async::Asyncable
|
||||
class CoreMidiInPort : public IMidiInPort
|
||||
{
|
||||
public:
|
||||
CoreMidiInPort();
|
||||
|
@ -57,13 +55,10 @@ private:
|
|||
struct Core;
|
||||
std::unique_ptr<Core> m_core;
|
||||
MidiDeviceID m_deviceID;
|
||||
async::Notification m_devicesChanged;
|
||||
|
||||
bool m_running = false;
|
||||
async::Channel<tick_t, Event> m_eventReceived;
|
||||
|
||||
async::Notification m_devicesChanged;
|
||||
MidiDevicesListener m_devicesListener;
|
||||
|
||||
mutable std::mutex m_devicesMutex;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -43,25 +43,6 @@ CoreMidiOutPort::CoreMidiOutPort()
|
|||
{
|
||||
m_core = std::unique_ptr<Core>(new Core());
|
||||
initCore();
|
||||
|
||||
m_devicesListener.startWithCallback([this]() {
|
||||
return devices();
|
||||
});
|
||||
|
||||
m_devicesListener.devicesChanged().onNotify(this, [this]() {
|
||||
bool connectedDeviceRemoved = true;
|
||||
for (const MidiDevice& device: devices()) {
|
||||
if (m_deviceID == device.id) {
|
||||
connectedDeviceRemoved = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (connectedDeviceRemoved) {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
m_devicesChanged.notify();
|
||||
});
|
||||
}
|
||||
|
||||
CoreMidiOutPort::~CoreMidiOutPort()
|
||||
|
@ -81,8 +62,35 @@ CoreMidiOutPort::~CoreMidiOutPort()
|
|||
void CoreMidiOutPort::initCore()
|
||||
{
|
||||
OSStatus result;
|
||||
|
||||
static auto onCoreMidiNotificationReceived = [](const MIDINotification* notification, void* refCon) {
|
||||
auto self = static_cast<CoreMidiOutPort*>(refCon);
|
||||
IF_ASSERT_FAILED(self) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (notification->messageID) {
|
||||
case kMIDIMsgObjectAdded:
|
||||
case kMIDIMsgObjectRemoved:
|
||||
self->devicesChanged().notify();
|
||||
break;
|
||||
|
||||
// General message that should be ignored because we handle specific ones
|
||||
case kMIDIMsgSetupChanged:
|
||||
|
||||
// Questionable whether we should send a notification for this ones
|
||||
// Possibly we should send a notification when the changed property is the device name
|
||||
case kMIDIMsgPropertyChanged:
|
||||
case kMIDIMsgThruConnectionsChanged:
|
||||
case kMIDIMsgSerialPortOwnerChanged:
|
||||
|
||||
case kMIDIMsgIOError:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
QString name = "MuseScore";
|
||||
result = MIDIClientCreate(name.toCFString(), nullptr, nullptr, &m_core->client);
|
||||
result = MIDIClientCreate(name.toCFString(), onCoreMidiNotificationReceived, this, &m_core->client);
|
||||
IF_ASSERT_FAILED(result == noErr) {
|
||||
LOGE() << "failed create midi output client";
|
||||
return;
|
||||
|
@ -97,7 +105,6 @@ void CoreMidiOutPort::initCore()
|
|||
|
||||
MidiDeviceList CoreMidiOutPort::devices() const
|
||||
{
|
||||
std::lock_guard lock(m_devicesMutex);
|
||||
MidiDeviceList ret;
|
||||
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||
|
|
|
@ -24,12 +24,10 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "async/asyncable.h"
|
||||
#include "midi/imidioutport.h"
|
||||
#include "internal/midideviceslistener.h"
|
||||
|
||||
namespace mu::midi {
|
||||
class CoreMidiOutPort : public IMidiOutPort, public async::Asyncable
|
||||
class CoreMidiOutPort : public IMidiOutPort
|
||||
{
|
||||
public:
|
||||
CoreMidiOutPort();
|
||||
|
@ -53,9 +51,6 @@ private:
|
|||
MidiDeviceID m_deviceID;
|
||||
|
||||
async::Notification m_devicesChanged;
|
||||
MidiDevicesListener m_devicesListener;
|
||||
|
||||
mutable std::mutex m_devicesMutex;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue