mirror of
https://github.com/AxioDL/boo.git
synced 2025-05-17 04:41:37 +00:00
Optional teVirtualMIDI integration
This commit is contained in:
parent
fd2a92e2c2
commit
261c06d746
@ -82,6 +82,15 @@ elseif(WIN32)
|
|||||||
lib/graphicsdev/VulkanDispatchTable.cpp)
|
lib/graphicsdev/VulkanDispatchTable.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
find_file(TE_VIRTUAL_MIDI_H teVirtualMIDI.h PATHS
|
||||||
|
"$ENV{PROGRAMFILES\(X86\)}/Tobias Erichsen/teVirtualMIDISDK/C-Binding")
|
||||||
|
if (TE_VIRTUAL_MIDI_H)
|
||||||
|
message(STATUS "Enabling teVirtualMIDI")
|
||||||
|
get_filename_component(TE_VIRTUAL_MIDI_DIR ${TE_VIRTUAL_MIDI_H} DIRECTORY)
|
||||||
|
include_directories(${TE_VIRTUAL_MIDI_DIR})
|
||||||
|
add_definitions("-DTE_VIRTUAL_MIDI=1")
|
||||||
|
endif()
|
||||||
|
|
||||||
list(APPEND PLAT_SRCS
|
list(APPEND PLAT_SRCS
|
||||||
lib/win/ApplicationWin32.cpp
|
lib/win/ApplicationWin32.cpp
|
||||||
lib/win/WindowWin32.cpp
|
lib/win/WindowWin32.cpp
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "../win/Win32Common.hpp"
|
#include "../win/Win32Common.hpp"
|
||||||
#include "AudioVoiceEngine.hpp"
|
#include "AudioVoiceEngine.hpp"
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
|
#include "boo/IApplication.hpp"
|
||||||
|
|
||||||
#include <Mmdeviceapi.h>
|
#include <Mmdeviceapi.h>
|
||||||
#include <Audioclient.h>
|
#include <Audioclient.h>
|
||||||
@ -9,6 +10,20 @@
|
|||||||
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
|
#ifdef TE_VIRTUAL_MIDI
|
||||||
|
#include <teVirtualMIDI.h>
|
||||||
|
typedef LPVM_MIDI_PORT (CALLBACK *pfnvirtualMIDICreatePortEx2)
|
||||||
|
( LPCWSTR portName, LPVM_MIDI_DATA_CB callback, DWORD_PTR dwCallbackInstance, DWORD maxSysexLength, DWORD flags );
|
||||||
|
typedef void (CALLBACK *pfnvirtualMIDIClosePort)( LPVM_MIDI_PORT midiPort );
|
||||||
|
typedef BOOL (CALLBACK *pfnvirtualMIDISendData)( LPVM_MIDI_PORT midiPort, LPBYTE midiDataBytes, DWORD length );
|
||||||
|
typedef LPCWSTR (CALLBACK *pfnvirtualMIDIGetDriverVersion)( PWORD major, PWORD minor, PWORD release, PWORD build );
|
||||||
|
static pfnvirtualMIDICreatePortEx2 virtualMIDICreatePortEx2PROC = nullptr;
|
||||||
|
static pfnvirtualMIDIClosePort virtualMIDIClosePortPROC = nullptr;
|
||||||
|
static pfnvirtualMIDISendData virtualMIDISendDataPROC = nullptr;
|
||||||
|
static pfnvirtualMIDIGetDriverVersion virtualMIDIGetDriverVersionPROC = nullptr;
|
||||||
|
static double PerfFrequency = 0.0;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !WINDOWS_STORE
|
#if !WINDOWS_STORE
|
||||||
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
|
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
|
||||||
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
|
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
|
||||||
@ -385,6 +400,20 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if !WINDOWS_STORE
|
#if !WINDOWS_STORE
|
||||||
|
#ifdef TE_VIRTUAL_MIDI
|
||||||
|
HMODULE virtualMidiModule;
|
||||||
|
if (!virtualMIDICreatePortEx2PROC && (virtualMidiModule = LoadLibraryW(L"teVirtualMIDI64.dll")))
|
||||||
|
{
|
||||||
|
virtualMIDICreatePortEx2PROC = (pfnvirtualMIDICreatePortEx2)GetProcAddress(virtualMidiModule, "virtualMIDICreatePortEx2");
|
||||||
|
virtualMIDIClosePortPROC = (pfnvirtualMIDIClosePort)GetProcAddress(virtualMidiModule, "virtualMIDIClosePort");
|
||||||
|
virtualMIDISendDataPROC = (pfnvirtualMIDISendData)GetProcAddress(virtualMidiModule, "virtualMIDISendData");
|
||||||
|
virtualMIDIGetDriverVersionPROC = (pfnvirtualMIDIGetDriverVersion)GetProcAddress(virtualMidiModule, "virtualMIDIGetDriverVersion");
|
||||||
|
LARGE_INTEGER pf;
|
||||||
|
QueryPerformanceFrequency(&pf);
|
||||||
|
PerfFrequency = double(pf.QuadPart);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Enumerate default audio device */
|
/* Enumerate default audio device */
|
||||||
if (FAILED(CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr,
|
if (FAILED(CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr,
|
||||||
CLSCTX_ALL, IID_IMMDeviceEnumerator,
|
CLSCTX_ALL, IID_IMMDeviceEnumerator,
|
||||||
@ -623,9 +652,34 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
|
|||||||
|
|
||||||
bool supportsVirtualMIDIIn() const
|
bool supportsVirtualMIDIIn() const
|
||||||
{
|
{
|
||||||
|
#ifdef TE_VIRTUAL_MIDI
|
||||||
|
WORD major, minor, release, build;
|
||||||
|
return virtualMIDIGetDriverVersionPROC &&
|
||||||
|
virtualMIDIGetDriverVersionPROC(&major, &minor, &release, &build) != nullptr;
|
||||||
|
#else
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TE_VIRTUAL_MIDI
|
||||||
|
static void CALLBACK VirtualMIDIReceiveProc(LPVM_MIDI_PORT midiPort,
|
||||||
|
LPBYTE midiDataBytes,
|
||||||
|
DWORD length,
|
||||||
|
IMIDIReceiver* dwInstance)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> bytes;
|
||||||
|
bytes.resize(length);
|
||||||
|
memcpy(&bytes[0], midiDataBytes, length);
|
||||||
|
|
||||||
|
double timestamp;
|
||||||
|
LARGE_INTEGER perf;
|
||||||
|
QueryPerformanceCounter(&perf);
|
||||||
|
timestamp = perf.QuadPart / PerfFrequency;
|
||||||
|
|
||||||
|
dwInstance->m_receiver(std::move(bytes), timestamp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void CALLBACK MIDIReceiveProc(HMIDIIN hMidiIn,
|
static void CALLBACK MIDIReceiveProc(HMIDIIN hMidiIn,
|
||||||
UINT wMsg,
|
UINT wMsg,
|
||||||
IMIDIReceiver* dwInstance,
|
IMIDIReceiver* dwInstance,
|
||||||
@ -640,12 +694,77 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TE_VIRTUAL_MIDI
|
||||||
|
struct VMIDIIn : public IMIDIIn
|
||||||
|
{
|
||||||
|
LPVM_MIDI_PORT m_midi = 0;
|
||||||
|
|
||||||
|
VMIDIIn(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver)
|
||||||
|
: IMIDIIn(parent, true, std::move(receiver)) {}
|
||||||
|
|
||||||
|
~VMIDIIn()
|
||||||
|
{
|
||||||
|
virtualMIDIClosePortPROC(m_midi);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string description() const
|
||||||
|
{
|
||||||
|
return "Virtual MIDI-In";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VMIDIOut : public IMIDIOut
|
||||||
|
{
|
||||||
|
LPVM_MIDI_PORT m_midi = 0;
|
||||||
|
|
||||||
|
VMIDIOut(WASAPIAudioVoiceEngine* parent) : IMIDIOut(parent, true) {}
|
||||||
|
|
||||||
|
~VMIDIOut()
|
||||||
|
{
|
||||||
|
virtualMIDIClosePortPROC(m_midi);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string description() const
|
||||||
|
{
|
||||||
|
return "Virtual MIDI-Out";
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t send(const void* buf, size_t len) const
|
||||||
|
{
|
||||||
|
return virtualMIDISendDataPROC(m_midi, (LPBYTE)buf, len) ? len : 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VMIDIInOut : public IMIDIInOut
|
||||||
|
{
|
||||||
|
LPVM_MIDI_PORT m_midi = 0;
|
||||||
|
|
||||||
|
VMIDIInOut(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver)
|
||||||
|
: IMIDIInOut(parent, true, std::move(receiver)) {}
|
||||||
|
|
||||||
|
~VMIDIInOut()
|
||||||
|
{
|
||||||
|
virtualMIDIClosePortPROC(m_midi);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string description() const
|
||||||
|
{
|
||||||
|
return "Virtual MIDI-In/Out";
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t send(const void* buf, size_t len) const
|
||||||
|
{
|
||||||
|
return virtualMIDISendDataPROC(m_midi, (LPBYTE)buf, len) ? len : 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
struct MIDIIn : public IMIDIIn
|
struct MIDIIn : public IMIDIIn
|
||||||
{
|
{
|
||||||
HMIDIIN m_midi = 0;
|
HMIDIIN m_midi = 0;
|
||||||
|
|
||||||
MIDIIn(WASAPIAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver)
|
MIDIIn(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver)
|
||||||
: IMIDIIn(parent, virt, std::move(receiver)) {}
|
: IMIDIIn(parent, false, std::move(receiver)) {}
|
||||||
|
|
||||||
~MIDIIn()
|
~MIDIIn()
|
||||||
{
|
{
|
||||||
@ -675,7 +794,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
|
|||||||
uint8_t m_buf[512];
|
uint8_t m_buf[512];
|
||||||
MIDIHDR m_hdr = {};
|
MIDIHDR m_hdr = {};
|
||||||
|
|
||||||
MIDIOut(WASAPIAudioVoiceEngine* parent, bool virt) : IMIDIOut(parent, virt) {}
|
MIDIOut(WASAPIAudioVoiceEngine* parent) : IMIDIOut(parent, false) {}
|
||||||
|
|
||||||
void prepare()
|
void prepare()
|
||||||
{
|
{
|
||||||
@ -728,8 +847,8 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
|
|||||||
uint8_t m_buf[512];
|
uint8_t m_buf[512];
|
||||||
MIDIHDR m_hdr = {};
|
MIDIHDR m_hdr = {};
|
||||||
|
|
||||||
MIDIInOut(WASAPIAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver)
|
MIDIInOut(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver)
|
||||||
: IMIDIInOut(parent, virt, std::move(receiver)) {}
|
: IMIDIInOut(parent, false, std::move(receiver)) {}
|
||||||
|
|
||||||
void prepare()
|
void prepare()
|
||||||
{
|
{
|
||||||
@ -777,17 +896,70 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
|
|||||||
|
|
||||||
std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver)
|
std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver)
|
||||||
{
|
{
|
||||||
|
#ifdef TE_VIRTUAL_MIDI
|
||||||
|
if (!virtualMIDICreatePortEx2PROC)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
std::unique_ptr<IMIDIIn> ret = std::make_unique<VMIDIIn>(this, std::move(receiver));
|
||||||
|
if (!ret)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
SystemString name = SystemString(APP->getFriendlyName()) + _S(" MIDI-In");
|
||||||
|
auto port = virtualMIDICreatePortEx2PROC(name.c_str(), LPVM_MIDI_DATA_CB(VirtualMIDIReceiveProc),
|
||||||
|
DWORD_PTR(static_cast<IMIDIReceiver*>(ret.get())), 512,
|
||||||
|
TE_VM_FLAGS_PARSE_RX | TE_VM_FLAGS_INSTANTIATE_RX_ONLY);
|
||||||
|
if (!port)
|
||||||
|
return {};
|
||||||
|
static_cast<VMIDIIn&>(*ret).m_midi = port;
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IMIDIOut> newVirtualMIDIOut()
|
std::unique_ptr<IMIDIOut> newVirtualMIDIOut()
|
||||||
{
|
{
|
||||||
|
#ifdef TE_VIRTUAL_MIDI
|
||||||
|
if (!virtualMIDICreatePortEx2PROC)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
std::unique_ptr<IMIDIOut> ret = std::make_unique<VMIDIOut>(this);
|
||||||
|
if (!ret)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
SystemString name = SystemString(APP->getFriendlyName()) + _S(" MIDI-Out");
|
||||||
|
auto port = virtualMIDICreatePortEx2PROC(name.c_str(), nullptr, 0, 512,
|
||||||
|
TE_VM_FLAGS_PARSE_TX | TE_VM_FLAGS_INSTANTIATE_TX_ONLY);
|
||||||
|
if (!port)
|
||||||
|
return {};
|
||||||
|
static_cast<VMIDIOut&>(*ret).m_midi = port;
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver)
|
std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver)
|
||||||
{
|
{
|
||||||
|
#ifdef TE_VIRTUAL_MIDI
|
||||||
|
if (!virtualMIDICreatePortEx2PROC)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
std::unique_ptr<IMIDIInOut> ret = std::make_unique<VMIDIInOut>(this, std::move(receiver));
|
||||||
|
if (!ret)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
SystemString name = SystemString(APP->getFriendlyName()) + _S(" MIDI-In/Out");
|
||||||
|
auto port = virtualMIDICreatePortEx2PROC(name.c_str(), LPVM_MIDI_DATA_CB(VirtualMIDIReceiveProc),
|
||||||
|
DWORD_PTR(static_cast<IMIDIReceiver*>(ret.get())), 512,
|
||||||
|
TE_VM_FLAGS_SUPPORTED);
|
||||||
|
if (!port)
|
||||||
|
return {};
|
||||||
|
static_cast<VMIDIInOut&>(*ret).m_midi = port;
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver)
|
std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver)
|
||||||
@ -796,7 +968,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
|
|||||||
return {};
|
return {};
|
||||||
long id = strtol(name + 2, nullptr, 10);
|
long id = strtol(name + 2, nullptr, 10);
|
||||||
|
|
||||||
std::unique_ptr<IMIDIIn> ret = std::make_unique<MIDIIn>(this, false, std::move(receiver));
|
std::unique_ptr<IMIDIIn> ret = std::make_unique<MIDIIn>(this, std::move(receiver));
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
@ -814,7 +986,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
|
|||||||
return {};
|
return {};
|
||||||
long id = strtol(name + 3, nullptr, 10);
|
long id = strtol(name + 3, nullptr, 10);
|
||||||
|
|
||||||
std::unique_ptr<IMIDIOut> ret = std::make_unique<MIDIOut>(this, false);
|
std::unique_ptr<IMIDIOut> ret = std::make_unique<MIDIOut>(this);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
@ -837,7 +1009,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
|
|||||||
long inId = strtol(in + 2, nullptr, 10);
|
long inId = strtol(in + 2, nullptr, 10);
|
||||||
long outId = strtol(out + 3, nullptr, 10);
|
long outId = strtol(out + 3, nullptr, 10);
|
||||||
|
|
||||||
std::unique_ptr<IMIDIInOut> ret = std::make_unique<MIDIInOut>(this, false, std::move(receiver));
|
std::unique_ptr<IMIDIInOut> ret = std::make_unique<MIDIInOut>(this, std::move(receiver));
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user