mirror of https://github.com/AxioDL/boo.git
ALSA MIDI fixes
This commit is contained in:
parent
5e58e989a8
commit
168fb3f516
|
@ -76,6 +76,9 @@ struct IAudioVoiceEngine
|
||||||
/** Get list of MIDI input devices found on system */
|
/** Get list of MIDI input devices found on system */
|
||||||
virtual std::vector<std::pair<std::string, std::string>> enumerateMIDIInputs() const=0;
|
virtual std::vector<std::pair<std::string, std::string>> enumerateMIDIInputs() const=0;
|
||||||
|
|
||||||
|
/** Query if system supports creating a virtual MIDI input */
|
||||||
|
virtual bool supportsVirtualMIDIIn() const=0;
|
||||||
|
|
||||||
/** Create ad-hoc MIDI in port and register with system */
|
/** Create ad-hoc MIDI in port and register with system */
|
||||||
virtual std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver)=0;
|
virtual std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver)=0;
|
||||||
|
|
||||||
|
|
|
@ -8,18 +8,20 @@
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
|
struct IAudioVoiceEngine;
|
||||||
using ReceiveFunctor = std::function<void(std::vector<uint8_t>&&, double time)>;
|
using ReceiveFunctor = std::function<void(std::vector<uint8_t>&&, double time)>;
|
||||||
|
|
||||||
class IMIDIPort
|
class IMIDIPort
|
||||||
{
|
{
|
||||||
bool m_virtual;
|
bool m_virtual;
|
||||||
protected:
|
protected:
|
||||||
IMIDIPort(bool virt) : m_virtual(virt) {}
|
IAudioVoiceEngine* m_parent;
|
||||||
|
IMIDIPort(IAudioVoiceEngine* parent, bool virt) : m_virtual(virt), m_parent(parent) {}
|
||||||
public:
|
public:
|
||||||
virtual ~IMIDIPort();
|
virtual ~IMIDIPort();
|
||||||
bool isVirtual() const {return m_virtual;}
|
bool isVirtual() const {return m_virtual;}
|
||||||
virtual std::string description() const=0;
|
virtual std::string description() const=0;
|
||||||
|
void _disown() { m_parent = nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class IMIDIReceiver
|
class IMIDIReceiver
|
||||||
|
@ -32,8 +34,8 @@ public:
|
||||||
class IMIDIIn : public IMIDIPort, public IMIDIReceiver
|
class IMIDIIn : public IMIDIPort, public IMIDIReceiver
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
IMIDIIn(bool virt, ReceiveFunctor&& receiver)
|
IMIDIIn(IAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver)
|
||||||
: IMIDIPort(virt), IMIDIReceiver(std::move(receiver)) {}
|
: IMIDIPort(parent, virt), IMIDIReceiver(std::move(receiver)) {}
|
||||||
public:
|
public:
|
||||||
virtual ~IMIDIIn();
|
virtual ~IMIDIIn();
|
||||||
};
|
};
|
||||||
|
@ -41,7 +43,7 @@ public:
|
||||||
class IMIDIOut : public IMIDIPort
|
class IMIDIOut : public IMIDIPort
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
IMIDIOut(bool virt) : IMIDIPort(virt) {}
|
IMIDIOut(IAudioVoiceEngine* parent, bool virt) : IMIDIPort(parent, virt) {}
|
||||||
public:
|
public:
|
||||||
virtual ~IMIDIOut();
|
virtual ~IMIDIOut();
|
||||||
virtual size_t send(const void* buf, size_t len) const=0;
|
virtual size_t send(const void* buf, size_t len) const=0;
|
||||||
|
@ -50,8 +52,8 @@ public:
|
||||||
class IMIDIInOut : public IMIDIPort, public IMIDIReceiver
|
class IMIDIInOut : public IMIDIPort, public IMIDIReceiver
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
IMIDIInOut(bool virt, ReceiveFunctor&& receiver)
|
IMIDIInOut(IAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver)
|
||||||
: IMIDIPort(virt), IMIDIReceiver(std::move(receiver)) {}
|
: IMIDIPort(parent, virt), IMIDIReceiver(std::move(receiver)) {}
|
||||||
public:
|
public:
|
||||||
virtual ~IMIDIInOut();
|
virtual ~IMIDIInOut();
|
||||||
virtual size_t send(const void* buf, size_t len) const=0;
|
virtual size_t send(const void* buf, size_t len) const=0;
|
||||||
|
|
|
@ -19,6 +19,30 @@ static inline double TimespecToDouble(struct timespec& ts)
|
||||||
|
|
||||||
struct LinuxMidi : BaseAudioVoiceEngine
|
struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
{
|
{
|
||||||
|
std::unordered_map<std::string, IMIDIPort*> m_openHandles;
|
||||||
|
void _addOpenHandle(const char* name, IMIDIPort* port)
|
||||||
|
{
|
||||||
|
m_openHandles[name] = port;
|
||||||
|
}
|
||||||
|
void _removeOpenHandle(IMIDIPort* port)
|
||||||
|
{
|
||||||
|
for (auto it = m_openHandles.begin(); it != m_openHandles.end();)
|
||||||
|
{
|
||||||
|
if (it->second == port)
|
||||||
|
{
|
||||||
|
it = m_openHandles.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~LinuxMidi()
|
||||||
|
{
|
||||||
|
for (auto& p : m_openHandles)
|
||||||
|
p.second->_disown();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> enumerateMIDIInputs() const
|
std::vector<std::pair<std::string, std::string>> enumerateMIDIInputs() const
|
||||||
{
|
{
|
||||||
std::vector<std::pair<std::string, std::string>> ret;
|
std::vector<std::pair<std::string, std::string>> ret;
|
||||||
|
@ -49,11 +73,21 @@ struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
break;
|
break;
|
||||||
if (device >= 0)
|
if (device >= 0)
|
||||||
{
|
{
|
||||||
snd_rawmidi_info_set_device(info, device);
|
|
||||||
if (snd_rawmidi_info_get_stream(info) != SND_RAWMIDI_STREAM_INPUT)
|
|
||||||
continue;
|
|
||||||
sprintf(name + strlen(name), ",%d", device);
|
sprintf(name + strlen(name), ",%d", device);
|
||||||
ret.push_back(std::make_pair(name, snd_rawmidi_info_get_name(info)));
|
auto search = m_openHandles.find(name);
|
||||||
|
if (search != m_openHandles.cend())
|
||||||
|
{
|
||||||
|
ret.push_back(std::make_pair(name, search->second->description()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
snd_rawmidi_t* midi;
|
||||||
|
if (!snd_rawmidi_open(&midi, nullptr, name, SND_RAWMIDI_NONBLOCK))
|
||||||
|
{
|
||||||
|
snd_rawmidi_info(midi, info);
|
||||||
|
ret.push_back(std::make_pair(name, snd_rawmidi_info_get_name(info)));
|
||||||
|
snd_rawmidi_close(midi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (device >= 0);
|
} while (device >= 0);
|
||||||
|
|
||||||
|
@ -68,6 +102,11 @@ struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool supportsVirtualMIDIIn() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void MIDIFreeProc(void* midiStatus)
|
static void MIDIFreeProc(void* midiStatus)
|
||||||
{
|
{
|
||||||
snd_rawmidi_status_free((snd_rawmidi_status_t*)midiStatus);
|
snd_rawmidi_status_free((snd_rawmidi_status_t*)midiStatus);
|
||||||
|
@ -112,12 +151,14 @@ struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
snd_rawmidi_t* m_midi;
|
snd_rawmidi_t* m_midi;
|
||||||
std::thread m_midiThread;
|
std::thread m_midiThread;
|
||||||
|
|
||||||
MIDIIn(snd_rawmidi_t* midi, bool virt, ReceiveFunctor&& receiver)
|
MIDIIn(LinuxMidi* parent, snd_rawmidi_t* midi, bool virt, ReceiveFunctor&& receiver)
|
||||||
: IMIDIIn(virt, std::move(receiver)), m_midi(midi),
|
: IMIDIIn(parent, virt, std::move(receiver)), m_midi(midi),
|
||||||
m_midiThread(std::bind(MIDIReceiveProc, m_midi, m_receiver)) {}
|
m_midiThread(std::bind(MIDIReceiveProc, m_midi, m_receiver)) {}
|
||||||
|
|
||||||
~MIDIIn()
|
~MIDIIn()
|
||||||
{
|
{
|
||||||
|
if (m_parent)
|
||||||
|
static_cast<LinuxMidi*>(m_parent)->_removeOpenHandle(this);
|
||||||
pthread_cancel(m_midiThread.native_handle());
|
pthread_cancel(m_midiThread.native_handle());
|
||||||
if (m_midiThread.joinable())
|
if (m_midiThread.joinable())
|
||||||
m_midiThread.join();
|
m_midiThread.join();
|
||||||
|
@ -137,10 +178,15 @@ struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
struct MIDIOut : public IMIDIOut
|
struct MIDIOut : public IMIDIOut
|
||||||
{
|
{
|
||||||
snd_rawmidi_t* m_midi;
|
snd_rawmidi_t* m_midi;
|
||||||
MIDIOut(snd_rawmidi_t* midi, bool virt)
|
MIDIOut(LinuxMidi* parent, snd_rawmidi_t* midi, bool virt)
|
||||||
: IMIDIOut(virt), m_midi(midi) {}
|
: IMIDIOut(parent, virt), m_midi(midi) {}
|
||||||
|
|
||||||
~MIDIOut() {snd_rawmidi_close(m_midi);}
|
~MIDIOut()
|
||||||
|
{
|
||||||
|
if (m_parent)
|
||||||
|
static_cast<LinuxMidi*>(m_parent)->_removeOpenHandle(this);
|
||||||
|
snd_rawmidi_close(m_midi);
|
||||||
|
}
|
||||||
|
|
||||||
std::string description() const
|
std::string description() const
|
||||||
{
|
{
|
||||||
|
@ -163,12 +209,14 @@ struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
snd_rawmidi_t* m_midiOut;
|
snd_rawmidi_t* m_midiOut;
|
||||||
std::thread m_midiThread;
|
std::thread m_midiThread;
|
||||||
|
|
||||||
MIDIInOut(snd_rawmidi_t* midiIn, snd_rawmidi_t* midiOut, bool virt, ReceiveFunctor&& receiver)
|
MIDIInOut(LinuxMidi* parent, snd_rawmidi_t* midiIn, snd_rawmidi_t* midiOut, bool virt, ReceiveFunctor&& receiver)
|
||||||
: IMIDIInOut(virt, std::move(receiver)), m_midiIn(midiIn), m_midiOut(midiOut),
|
: IMIDIInOut(parent, virt, std::move(receiver)), m_midiIn(midiIn), m_midiOut(midiOut),
|
||||||
m_midiThread(std::bind(MIDIReceiveProc, m_midiIn, m_receiver)) {}
|
m_midiThread(std::bind(MIDIReceiveProc, m_midiIn, m_receiver)) {}
|
||||||
|
|
||||||
~MIDIInOut()
|
~MIDIInOut()
|
||||||
{
|
{
|
||||||
|
if (m_parent)
|
||||||
|
static_cast<LinuxMidi*>(m_parent)->_removeOpenHandle(this);
|
||||||
pthread_cancel(m_midiThread.native_handle());
|
pthread_cancel(m_midiThread.native_handle());
|
||||||
if (m_midiThread.joinable())
|
if (m_midiThread.joinable())
|
||||||
m_midiThread.join();
|
m_midiThread.join();
|
||||||
|
@ -198,7 +246,7 @@ struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
status = snd_rawmidi_open(&midi, nullptr, "virtual", 0);
|
status = snd_rawmidi_open(&midi, nullptr, "virtual", 0);
|
||||||
if (status)
|
if (status)
|
||||||
return {};
|
return {};
|
||||||
return std::make_unique<MIDIIn>(midi, true, std::move(receiver));
|
return std::make_unique<MIDIIn>(nullptr, midi, true, std::move(receiver));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IMIDIOut> newVirtualMIDIOut()
|
std::unique_ptr<IMIDIOut> newVirtualMIDIOut()
|
||||||
|
@ -208,7 +256,7 @@ struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
status = snd_rawmidi_open(nullptr, &midi, "virtual", 0);
|
status = snd_rawmidi_open(nullptr, &midi, "virtual", 0);
|
||||||
if (status)
|
if (status)
|
||||||
return {};
|
return {};
|
||||||
return std::make_unique<MIDIOut>(midi, true);
|
return std::make_unique<MIDIOut>(nullptr, midi, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver)
|
std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver)
|
||||||
|
@ -219,7 +267,7 @@ struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
status = snd_rawmidi_open(&midiIn, &midiOut, "virtual", 0);
|
status = snd_rawmidi_open(&midiIn, &midiOut, "virtual", 0);
|
||||||
if (status)
|
if (status)
|
||||||
return {};
|
return {};
|
||||||
return std::make_unique<MIDIInOut>(midiIn, midiOut, true, std::move(receiver));
|
return std::make_unique<MIDIInOut>(nullptr, midiIn, midiOut, true, std::move(receiver));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver)
|
std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver)
|
||||||
|
@ -228,7 +276,9 @@ struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
int status = snd_rawmidi_open(&midi, nullptr, name, 0);
|
int status = snd_rawmidi_open(&midi, nullptr, name, 0);
|
||||||
if (status)
|
if (status)
|
||||||
return {};
|
return {};
|
||||||
return std::make_unique<MIDIIn>(midi, true, std::move(receiver));
|
auto ret = std::make_unique<MIDIIn>(this, midi, true, std::move(receiver));
|
||||||
|
_addOpenHandle(name, ret.get());
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name)
|
std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name)
|
||||||
|
@ -237,7 +287,9 @@ struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
int status = snd_rawmidi_open(nullptr, &midi, name, 0);
|
int status = snd_rawmidi_open(nullptr, &midi, name, 0);
|
||||||
if (status)
|
if (status)
|
||||||
return {};
|
return {};
|
||||||
return std::make_unique<MIDIOut>(midi, true);
|
auto ret = std::make_unique<MIDIOut>(this, midi, true);
|
||||||
|
_addOpenHandle(name, ret.get());
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver)
|
std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver)
|
||||||
|
@ -247,7 +299,9 @@ struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
int status = snd_rawmidi_open(&midiIn, &midiOut, name, 0);
|
int status = snd_rawmidi_open(&midiIn, &midiOut, name, 0);
|
||||||
if (status)
|
if (status)
|
||||||
return {};
|
return {};
|
||||||
return std::make_unique<MIDIInOut>(midiIn, midiOut, true, std::move(receiver));
|
auto ret = std::make_unique<MIDIInOut>(this, midiIn, midiOut, true, std::move(receiver));
|
||||||
|
_addOpenHandle(name, ret.get());
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool useMIDILock() const {return true;}
|
bool useMIDILock() const {return true;}
|
||||||
|
|
|
@ -33,12 +33,17 @@ struct WAVOutVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool supportsVirtualMIDIIn() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
boo::ReceiveFunctor* m_midiReceiver = nullptr;
|
boo::ReceiveFunctor* m_midiReceiver = nullptr;
|
||||||
|
|
||||||
struct MIDIIn : public boo::IMIDIIn
|
struct MIDIIn : public boo::IMIDIIn
|
||||||
{
|
{
|
||||||
MIDIIn(bool virt, boo::ReceiveFunctor&& receiver)
|
MIDIIn(WAVOutVoiceEngine* parent, bool virt, boo::ReceiveFunctor&& receiver)
|
||||||
: IMIDIIn(virt, std::move(receiver)) {}
|
: IMIDIIn(parent, virt, std::move(receiver)) {}
|
||||||
|
|
||||||
std::string description() const
|
std::string description() const
|
||||||
{
|
{
|
||||||
|
@ -48,7 +53,7 @@ struct WAVOutVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
|
|
||||||
std::unique_ptr<boo::IMIDIIn> newVirtualMIDIIn(boo::ReceiveFunctor&& receiver)
|
std::unique_ptr<boo::IMIDIIn> newVirtualMIDIIn(boo::ReceiveFunctor&& receiver)
|
||||||
{
|
{
|
||||||
std::unique_ptr<boo::IMIDIIn> ret = std::make_unique<MIDIIn>(true, std::move(receiver));
|
std::unique_ptr<boo::IMIDIIn> ret = std::make_unique<MIDIIn>(nullptr, true, std::move(receiver));
|
||||||
m_midiReceiver = &ret->m_receiver;
|
m_midiReceiver = &ret->m_receiver;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue