mirror of https://github.com/AxioDL/boo.git
Add IMIDIPort, initial ALSA midiport implementation
This commit is contained in:
parent
ceff1934c1
commit
8ff2b9c404
|
@ -197,6 +197,7 @@ add_library(boo
|
||||||
include/boo/graphicsdev/IGraphicsCommandQueue.hpp
|
include/boo/graphicsdev/IGraphicsCommandQueue.hpp
|
||||||
include/boo/audiodev/IAudioSubmix.hpp
|
include/boo/audiodev/IAudioSubmix.hpp
|
||||||
include/boo/audiodev/IAudioVoice.hpp
|
include/boo/audiodev/IAudioVoice.hpp
|
||||||
|
include/boo/audiodev/IMIDIPort.hpp
|
||||||
include/boo/audiodev/IAudioVoiceEngine.hpp
|
include/boo/audiodev/IAudioVoiceEngine.hpp
|
||||||
include/boo/IWindow.hpp
|
include/boo/IWindow.hpp
|
||||||
include/boo/IApplication.hpp
|
include/boo/IApplication.hpp
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
|
|
||||||
#include "IAudioVoice.hpp"
|
#include "IAudioVoice.hpp"
|
||||||
#include "IAudioSubmix.hpp"
|
#include "IAudioSubmix.hpp"
|
||||||
|
#include "IMIDIPort.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
|
@ -38,6 +40,27 @@ struct IAudioVoiceEngine
|
||||||
|
|
||||||
/** Ensure backing platform buffer is filled as much as possible with mixed samples */
|
/** Ensure backing platform buffer is filled as much as possible with mixed samples */
|
||||||
virtual void pumpAndMixVoices()=0;
|
virtual void pumpAndMixVoices()=0;
|
||||||
|
|
||||||
|
/** Get list of MIDI devices found on system */
|
||||||
|
virtual std::vector<std::string> enumerateMIDIDevices() const=0;
|
||||||
|
|
||||||
|
/** Create ad-hoc MIDI in port and register with system */
|
||||||
|
virtual std::unique_ptr<IMIDIIn> newVirtualMIDIIn()=0;
|
||||||
|
|
||||||
|
/** Create ad-hoc MIDI out port and register with system */
|
||||||
|
virtual std::unique_ptr<IMIDIOut> newVirtualMIDIOut()=0;
|
||||||
|
|
||||||
|
/** Create ad-hoc MIDI in/out port and register with system */
|
||||||
|
virtual std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut()=0;
|
||||||
|
|
||||||
|
/** Open named MIDI in port, name format depends on OS */
|
||||||
|
virtual std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name)=0;
|
||||||
|
|
||||||
|
/** Open named MIDI out port, name format depends on OS */
|
||||||
|
virtual std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name)=0;
|
||||||
|
|
||||||
|
/** Open named MIDI in/out port, name format depends on OS */
|
||||||
|
virtual std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Construct host platform's voice engine */
|
/** Construct host platform's voice engine */
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef BOO_IMIDIPORT_HPP
|
||||||
|
#define BOO_IMIDIPORT_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace boo
|
||||||
|
{
|
||||||
|
|
||||||
|
class IMIDIPort
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IMIDIPort() = default;
|
||||||
|
virtual bool isVirtual() const=0;
|
||||||
|
virtual std::string description() const=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IMIDIIn : public IMIDIPort
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual size_t receive(void* buf, size_t len) const=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IMIDIOut : public IMIDIPort
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual size_t send(const void* buf, size_t len) const=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IMIDIInOut : public IMIDIPort
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual size_t send(const void* buf, size_t len) const=0;
|
||||||
|
virtual size_t receive(void* buf, size_t len) const=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BOO_IMIDIPORT_HPP
|
|
@ -317,6 +317,102 @@ struct ALSAAudioVoiceEngine : BaseAudioVoiceEngine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> enumerateMIDIDevices() const
|
||||||
|
{
|
||||||
|
std::vector<std::string> ret;
|
||||||
|
int status;
|
||||||
|
int card = -1; /* use -1 to prime the pump of iterating through card list */
|
||||||
|
|
||||||
|
if ((status = snd_card_next(&card)) < 0)
|
||||||
|
return {};
|
||||||
|
if (card < 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
while (card >= 0)
|
||||||
|
{
|
||||||
|
snd_ctl_t *ctl;
|
||||||
|
char name[32];
|
||||||
|
int device = -1;
|
||||||
|
int status;
|
||||||
|
sprintf(name, "hw:%d", card);
|
||||||
|
if ((status = snd_ctl_open(&ctl, name, 0)) < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
do {
|
||||||
|
status = snd_ctl_rawmidi_next_device(ctl, &device);
|
||||||
|
if (status < 0)
|
||||||
|
break;
|
||||||
|
if (device >= 0)
|
||||||
|
{
|
||||||
|
snd_rawmidi_info_t *info;
|
||||||
|
snd_rawmidi_info_alloca(&info);
|
||||||
|
snd_rawmidi_info_set_device(info, device);
|
||||||
|
ret.push_back(snd_rawmidi_info_get_name(info));
|
||||||
|
}
|
||||||
|
} while (device >= 0);
|
||||||
|
|
||||||
|
snd_ctl_close(ctl);
|
||||||
|
|
||||||
|
if ((status = snd_card_next(&card)) < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MIDIIn : public IMIDIIn
|
||||||
|
{
|
||||||
|
snd_rawmidi_t* m_midi;
|
||||||
|
bool m_virtual;
|
||||||
|
MIDIIn(snd_rawmidi_t* midi, bool virt)
|
||||||
|
: m_midi(midi), m_virtual(virt) {}
|
||||||
|
|
||||||
|
bool isVirtual() const {return m_virtual;}
|
||||||
|
std::string description() const
|
||||||
|
{
|
||||||
|
snd_rawmidi_info_t* info;
|
||||||
|
snd_rawmidi_info_alloca(&info);
|
||||||
|
snd_rawmidi_info(m_midi, info);
|
||||||
|
std::string ret = snd_rawmidi_info_get_name(info);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
size_t receive(void* buf, size_t len) const
|
||||||
|
{
|
||||||
|
return std::max(0l, snd_rawmidi_read(m_midi, buf, len));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<IMIDIIn> newVirtualMIDIIn()
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
snd_rawmidi_t* midi;
|
||||||
|
status = snd_rawmidi_open(&midi, nullptr, "virtual", 0);
|
||||||
|
if (status)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return std::make_unique<MIDIIn>(midi, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IMIDIOut> newVirtualMIDIOut()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IAudioVoiceEngine> NewAudioVoiceEngine()
|
std::unique_ptr<IAudioVoiceEngine> NewAudioVoiceEngine()
|
||||||
|
|
|
@ -304,6 +304,7 @@ struct GraphicsContextXlibGLX : GraphicsContextXlib
|
||||||
|
|
||||||
GLXFBConfig m_fbconfig = 0;
|
GLXFBConfig m_fbconfig = 0;
|
||||||
int m_visualid = 0;
|
int m_visualid = 0;
|
||||||
|
int m_attribIdx = 0;
|
||||||
GLXWindow m_glxWindow = 0;
|
GLXWindow m_glxWindow = 0;
|
||||||
GLXContext m_glxCtx = 0;
|
GLXContext m_glxCtx = 0;
|
||||||
|
|
||||||
|
@ -451,10 +452,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
s_glxError = false;
|
s_glxError = false;
|
||||||
XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler);
|
XErrorHandler oldHandler = XSetErrorHandler(ctxErrorHandler);
|
||||||
for (int i=0 ; i<std::extent<decltype(ContextAttribList)>::value ; ++i)
|
for (m_attribIdx=0 ; m_attribIdx<std::extent<decltype(ContextAttribList)>::value ; ++m_attribIdx)
|
||||||
{
|
{
|
||||||
m_glxCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_lastCtx, True, ContextAttribList[i]);
|
m_glxCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_lastCtx, True, ContextAttribList[m_attribIdx]);
|
||||||
if (m_glxCtx)
|
if (m_glxCtx)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -497,10 +498,12 @@ public:
|
||||||
|
|
||||||
while (m_vsyncRunning)
|
while (m_vsyncRunning)
|
||||||
{
|
{
|
||||||
unsigned int sync;
|
{
|
||||||
int err = glXWaitVideoSyncSGI(1, 0, &sync);
|
unsigned int sync;
|
||||||
if (err)
|
int err = glXWaitVideoSyncSGI(1, 0, &sync);
|
||||||
Log.report(logvisor::Fatal, "wait err");
|
if (err)
|
||||||
|
Log.report(logvisor::Fatal, "wait err");
|
||||||
|
}
|
||||||
m_vsynccv.notify_one();
|
m_vsynccv.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,13 +551,8 @@ public:
|
||||||
if (!m_mainCtx)
|
if (!m_mainCtx)
|
||||||
{
|
{
|
||||||
s_glxError = false;
|
s_glxError = false;
|
||||||
XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler);
|
XErrorHandler oldHandler = XSetErrorHandler(ctxErrorHandler);
|
||||||
for (int i=0 ; i<std::extent<decltype(ContextAttribList)>::value ; ++i)
|
m_mainCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribList[m_attribIdx]);
|
||||||
{
|
|
||||||
m_mainCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribList[i]);
|
|
||||||
if (m_mainCtx)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
XSetErrorHandler(oldHandler);
|
XSetErrorHandler(oldHandler);
|
||||||
if (!m_mainCtx)
|
if (!m_mainCtx)
|
||||||
Log.report(logvisor::Fatal, "unable to make main GLX context");
|
Log.report(logvisor::Fatal, "unable to make main GLX context");
|
||||||
|
@ -571,13 +569,8 @@ public:
|
||||||
if (!m_loadCtx)
|
if (!m_loadCtx)
|
||||||
{
|
{
|
||||||
s_glxError = false;
|
s_glxError = false;
|
||||||
XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler);
|
XErrorHandler oldHandler = XSetErrorHandler(ctxErrorHandler);
|
||||||
for (int i=0 ; i<std::extent<decltype(ContextAttribList)>::value ; ++i)
|
m_loadCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribList[m_attribIdx]);
|
||||||
{
|
|
||||||
m_loadCtx = glXCreateContextAttribsARB(m_xDisp, m_fbconfig, m_glxCtx, True, ContextAttribList[i]);
|
|
||||||
if (m_loadCtx)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
XSetErrorHandler(oldHandler);
|
XSetErrorHandler(oldHandler);
|
||||||
if (!m_loadCtx)
|
if (!m_loadCtx)
|
||||||
Log.report(logvisor::Fatal, "unable to make load GLX context");
|
Log.report(logvisor::Fatal, "unable to make load GLX context");
|
||||||
|
|
Loading…
Reference in New Issue