New code style refactor

This commit is contained in:
Jack Andersen 2018-12-07 19:17:51 -10:00
parent 2c2c72bfd1
commit 058ea23a00
113 changed files with 23305 additions and 27650 deletions

View File

@ -5,17 +5,13 @@
#include "boo/inputdev/XInputPad.hpp" #include "boo/inputdev/XInputPad.hpp"
#include "boo/inputdev/NintendoPowerA.hpp" #include "boo/inputdev/NintendoPowerA.hpp"
namespace boo namespace boo {
{
const DeviceSignature BOO_DEVICE_SIGS[] = const DeviceSignature BOO_DEVICE_SIGS[] = {DEVICE_SIG(DolphinSmashAdapter, 0x57e, 0x337, DeviceType::USB),
{
DEVICE_SIG(DolphinSmashAdapter, 0x57e, 0x337, DeviceType::USB),
DEVICE_SIG(DualshockPad, 0x54c, 0x268, DeviceType::HID), DEVICE_SIG(DualshockPad, 0x54c, 0x268, DeviceType::HID),
DEVICE_SIG(GenericPad, 0, 0, DeviceType::HID), DEVICE_SIG(GenericPad, 0, 0, DeviceType::HID),
DEVICE_SIG(NintendoPowerA, 0x20D6, 0xA711, DeviceType::USB), DEVICE_SIG(NintendoPowerA, 0x20D6, 0xA711, DeviceType::USB),
DEVICE_SIG(XInputPad, 0, 0, DeviceType::XInput), DEVICE_SIG(XInputPad, 0, 0, DeviceType::XInput),
DEVICE_SIG_SENTINEL() DEVICE_SIG_SENTINEL()};
};
} }

View File

@ -4,21 +4,19 @@
#include <mutex> #include <mutex>
#include "nxstl/mutex" #include "nxstl/mutex"
namespace boo namespace boo {
{
class IObj class IObj {
{
std::atomic_int m_refCount = {0}; std::atomic_int m_refCount = {0};
protected: protected:
virtual ~IObj() = default; virtual ~IObj() = default;
public: public:
virtual std::unique_lock<std::recursive_mutex> destructorLock() = 0; virtual std::unique_lock<std::recursive_mutex> destructorLock() = 0;
void increment() { m_refCount++; } void increment() { m_refCount++; }
void decrement() void decrement() {
{ if (m_refCount.fetch_sub(1) == 1) {
if (m_refCount.fetch_sub(1) == 1)
{
auto lk = destructorLock(); auto lk = destructorLock();
delete this; delete this;
} }
@ -26,28 +24,60 @@ public:
}; };
template <class SubCls> template <class SubCls>
class ObjToken class ObjToken {
{
SubCls* m_obj = nullptr; SubCls* m_obj = nullptr;
public: public:
ObjToken() = default; ObjToken() = default;
ObjToken(SubCls* obj) : m_obj(obj) { if (m_obj) m_obj->increment(); } ObjToken(SubCls* obj) : m_obj(obj) {
ObjToken(const ObjToken& other) : m_obj(other.m_obj) { if (m_obj) m_obj->increment(); } if (m_obj)
m_obj->increment();
}
ObjToken(const ObjToken& other) : m_obj(other.m_obj) {
if (m_obj)
m_obj->increment();
}
ObjToken(ObjToken&& other) : m_obj(other.m_obj) { other.m_obj = nullptr; } ObjToken(ObjToken&& other) : m_obj(other.m_obj) { other.m_obj = nullptr; }
ObjToken& operator=(SubCls* obj) ObjToken& operator=(SubCls* obj) {
{ if (m_obj) m_obj->decrement(); m_obj = obj; if (m_obj) m_obj->increment(); return *this; } if (m_obj)
ObjToken& operator=(const ObjToken& other) m_obj->decrement();
{ if (m_obj) m_obj->decrement(); m_obj = other.m_obj; if (m_obj) m_obj->increment(); return *this; } m_obj = obj;
ObjToken& operator=(ObjToken&& other) if (m_obj)
{ if (m_obj) m_obj->decrement(); m_obj = other.m_obj; other.m_obj = nullptr; return *this; } m_obj->increment();
~ObjToken() { if (m_obj) m_obj->decrement(); } return *this;
}
ObjToken& operator=(const ObjToken& other) {
if (m_obj)
m_obj->decrement();
m_obj = other.m_obj;
if (m_obj)
m_obj->increment();
return *this;
}
ObjToken& operator=(ObjToken&& other) {
if (m_obj)
m_obj->decrement();
m_obj = other.m_obj;
other.m_obj = nullptr;
return *this;
}
~ObjToken() {
if (m_obj)
m_obj->decrement();
}
SubCls* get() const { return m_obj; } SubCls* get() const { return m_obj; }
SubCls* operator->() const { return m_obj; } SubCls* operator->() const { return m_obj; }
SubCls& operator*() const { return *m_obj; } SubCls& operator*() const { return *m_obj; }
template<class T> T* cast() const { return static_cast<T*>(m_obj); } template <class T>
T* cast() const {
return static_cast<T*>(m_obj);
}
operator bool() const { return m_obj != nullptr; } operator bool() const { return m_obj != nullptr; }
void reset() { if (m_obj) m_obj->decrement(); m_obj = nullptr; } void reset() {
if (m_obj)
m_obj->decrement();
m_obj = nullptr;
}
}; };
} } // namespace boo

View File

@ -5,27 +5,21 @@
#include <condition_variable> #include <condition_variable>
#include "nxstl/condition_variable" #include "nxstl/condition_variable"
namespace boo namespace boo {
{
template <class Receiver> template <class Receiver>
struct DeferredWindowEvents : public IWindowCallback struct DeferredWindowEvents : public IWindowCallback {
{
Receiver& m_rec; Receiver& m_rec;
std::mutex m_mt; std::mutex m_mt;
std::condition_variable m_resizeCv; std::condition_variable m_resizeCv;
DeferredWindowEvents(Receiver& rec) : m_rec(rec) {} DeferredWindowEvents(Receiver& rec) : m_rec(rec) {}
bool m_destroyed = false; bool m_destroyed = false;
void destroyed() void destroyed() { m_destroyed = true; }
{
m_destroyed = true;
}
bool m_hasResize = false; bool m_hasResize = false;
SWindowRect m_latestResize; SWindowRect m_latestResize;
void resized(const SWindowRect& rect, bool sync) void resized(const SWindowRect& rect, bool sync) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_latestResize = rect; m_latestResize = rect;
m_hasResize = true; m_hasResize = true;
@ -33,10 +27,8 @@ struct DeferredWindowEvents : public IWindowCallback
m_resizeCv.wait_for(lk, std::chrono::milliseconds(500)); m_resizeCv.wait_for(lk, std::chrono::milliseconds(500));
} }
struct Command struct Command {
{ enum class Type {
enum class Type
{
MouseDown, MouseDown,
MouseUp, MouseUp,
MouseMove, MouseMove,
@ -64,10 +56,8 @@ struct DeferredWindowEvents : public IWindowCallback
ESpecialKey m_special; ESpecialKey m_special;
bool m_isRepeat; bool m_isRepeat;
void dispatch(Receiver& rec) const void dispatch(Receiver& rec) const {
{ switch (m_type) {
switch (m_type)
{
case Type::MouseDown: case Type::MouseDown:
rec.mouseDown(m_coord, m_button, m_mods); rec.mouseDown(m_coord, m_button, m_mods);
break; break;
@ -113,7 +103,8 @@ struct DeferredWindowEvents : public IWindowCallback
case Type::ModKeyUp: case Type::ModKeyUp:
rec.modKeyUp(m_mods); rec.modKeyUp(m_mods);
break; break;
default: break; default:
break;
} }
} }
@ -121,8 +112,7 @@ struct DeferredWindowEvents : public IWindowCallback
}; };
std::vector<Command> m_cmds; std::vector<Command> m_cmds;
void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::MouseDown); m_cmds.emplace_back(Command::Type::MouseDown);
m_cmds.back().m_coord = coord; m_cmds.back().m_coord = coord;
@ -130,8 +120,7 @@ struct DeferredWindowEvents : public IWindowCallback
m_cmds.back().m_mods = mods; m_cmds.back().m_mods = mods;
} }
void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::MouseUp); m_cmds.emplace_back(Command::Type::MouseUp);
m_cmds.back().m_coord = coord; m_cmds.back().m_coord = coord;
@ -139,61 +128,53 @@ struct DeferredWindowEvents : public IWindowCallback
m_cmds.back().m_mods = mods; m_cmds.back().m_mods = mods;
} }
void mouseMove(const SWindowCoord& coord) void mouseMove(const SWindowCoord& coord) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::MouseMove); m_cmds.emplace_back(Command::Type::MouseMove);
m_cmds.back().m_coord = coord; m_cmds.back().m_coord = coord;
} }
void mouseEnter(const SWindowCoord& coord) void mouseEnter(const SWindowCoord& coord) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::MouseEnter); m_cmds.emplace_back(Command::Type::MouseEnter);
m_cmds.back().m_coord = coord; m_cmds.back().m_coord = coord;
} }
void mouseLeave(const SWindowCoord& coord) void mouseLeave(const SWindowCoord& coord) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::MouseLeave); m_cmds.emplace_back(Command::Type::MouseLeave);
m_cmds.back().m_coord = coord; m_cmds.back().m_coord = coord;
} }
void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::Scroll); m_cmds.emplace_back(Command::Type::Scroll);
m_cmds.back().m_coord = coord; m_cmds.back().m_coord = coord;
m_cmds.back().m_scroll = scroll; m_cmds.back().m_scroll = scroll;
} }
void touchDown(const STouchCoord& coord, uintptr_t tid) void touchDown(const STouchCoord& coord, uintptr_t tid) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::TouchDown); m_cmds.emplace_back(Command::Type::TouchDown);
m_cmds.back().m_tCoord = coord; m_cmds.back().m_tCoord = coord;
m_cmds.back().m_tid = tid; m_cmds.back().m_tid = tid;
} }
void touchUp(const STouchCoord& coord, uintptr_t tid) void touchUp(const STouchCoord& coord, uintptr_t tid) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::TouchUp); m_cmds.emplace_back(Command::Type::TouchUp);
m_cmds.back().m_tCoord = coord; m_cmds.back().m_tCoord = coord;
m_cmds.back().m_tid = tid; m_cmds.back().m_tid = tid;
} }
void touchMove(const STouchCoord& coord, uintptr_t tid) void touchMove(const STouchCoord& coord, uintptr_t tid) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::TouchMove); m_cmds.emplace_back(Command::Type::TouchMove);
m_cmds.back().m_tCoord = coord; m_cmds.back().m_tCoord = coord;
m_cmds.back().m_tid = tid; m_cmds.back().m_tid = tid;
} }
void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::CharKeyDown); m_cmds.emplace_back(Command::Type::CharKeyDown);
m_cmds.back().m_charcode = charCode; m_cmds.back().m_charcode = charCode;
@ -201,16 +182,14 @@ struct DeferredWindowEvents : public IWindowCallback
m_cmds.back().m_isRepeat = isRepeat; m_cmds.back().m_isRepeat = isRepeat;
} }
void charKeyUp(unsigned long charCode, EModifierKey mods) void charKeyUp(unsigned long charCode, EModifierKey mods) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::CharKeyUp); m_cmds.emplace_back(Command::Type::CharKeyUp);
m_cmds.back().m_charcode = charCode; m_cmds.back().m_charcode = charCode;
m_cmds.back().m_mods = mods; m_cmds.back().m_mods = mods;
} }
void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::SpecialKeyDown); m_cmds.emplace_back(Command::Type::SpecialKeyDown);
m_cmds.back().m_special = key; m_cmds.back().m_special = key;
@ -218,24 +197,21 @@ struct DeferredWindowEvents : public IWindowCallback
m_cmds.back().m_isRepeat = isRepeat; m_cmds.back().m_isRepeat = isRepeat;
} }
void specialKeyUp(ESpecialKey key, EModifierKey mods) void specialKeyUp(ESpecialKey key, EModifierKey mods) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::SpecialKeyUp); m_cmds.emplace_back(Command::Type::SpecialKeyUp);
m_cmds.back().m_special = key; m_cmds.back().m_special = key;
m_cmds.back().m_mods = mods; m_cmds.back().m_mods = mods;
} }
void modKeyDown(EModifierKey mod, bool isRepeat) void modKeyDown(EModifierKey mod, bool isRepeat) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::ModKeyDown); m_cmds.emplace_back(Command::Type::ModKeyDown);
m_cmds.back().m_mods = mod; m_cmds.back().m_mods = mod;
m_cmds.back().m_isRepeat = isRepeat; m_cmds.back().m_isRepeat = isRepeat;
} }
void modKeyUp(EModifierKey mod) void modKeyUp(EModifierKey mod) {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
m_cmds.emplace_back(Command::Type::ModKeyUp); m_cmds.emplace_back(Command::Type::ModKeyUp);
m_cmds.back().m_mods = mod; m_cmds.back().m_mods = mod;
@ -243,8 +219,7 @@ struct DeferredWindowEvents : public IWindowCallback
ITextInputCallback* getTextInputCallback() { return m_rec.getTextInputCallback(); } ITextInputCallback* getTextInputCallback() { return m_rec.getTextInputCallback(); }
void dispatchEvents() void dispatchEvents() {
{
std::unique_lock<std::mutex> lk(m_mt); std::unique_lock<std::mutex> lk(m_mt);
bool destroyed = m_destroyed; bool destroyed = m_destroyed;
bool hasResize = m_hasResize; bool hasResize = m_hasResize;
@ -255,8 +230,7 @@ struct DeferredWindowEvents : public IWindowCallback
m_cmds.swap(cmds); m_cmds.swap(cmds);
lk.unlock(); lk.unlock();
if (destroyed) if (destroyed) {
{
m_rec.destroyed(); m_rec.destroyed();
return; return;
} }
@ -269,5 +243,4 @@ struct DeferredWindowEvents : public IWindowCallback
} }
}; };
} } // namespace boo

View File

@ -7,29 +7,26 @@
#include "IWindow.hpp" #include "IWindow.hpp"
#include "inputdev/DeviceFinder.hpp" #include "inputdev/DeviceFinder.hpp"
namespace boo namespace boo {
{
class IApplication; class IApplication;
struct IApplicationCallback struct IApplicationCallback {
{
virtual int appMain(IApplication*) = 0; virtual int appMain(IApplication*) = 0;
virtual void appQuitting(IApplication*) = 0; virtual void appQuitting(IApplication*) = 0;
virtual void appFilesOpen(IApplication*, const std::vector<SystemString>&) {} virtual void appFilesOpen(IApplication*, const std::vector<SystemString>&) {}
}; };
class IApplication class IApplication {
{
friend class WindowCocoa; friend class WindowCocoa;
friend class WindowWayland; friend class WindowWayland;
friend class WindowXlib; friend class WindowXlib;
friend class WindowWin32; friend class WindowWin32;
virtual void _deletedWindow(IWindow* window) = 0; virtual void _deletedWindow(IWindow* window) = 0;
public: public:
virtual ~IApplication() = default; virtual ~IApplication() = default;
enum class EPlatformType enum class EPlatformType {
{
Auto = 0, Auto = 0,
Wayland = 1, Wayland = 1,
Xlib = 2, Xlib = 2,
@ -55,40 +52,23 @@ public:
virtual std::shared_ptr<IWindow> newWindow(SystemStringView title) = 0; virtual std::shared_ptr<IWindow> newWindow(SystemStringView title) = 0;
}; };
int int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb, SystemStringView uniqueName,
ApplicationRun(IApplication::EPlatformType platform, SystemStringView friendlyName, SystemStringView pname, const std::vector<SystemString>& args,
IApplicationCallback& cb, std::string_view gfxApi = {}, uint32_t samples = 1, uint32_t anisotropy = 1, bool deepColor = false,
SystemStringView uniqueName,
SystemStringView friendlyName,
SystemStringView pname,
const std::vector<SystemString>& args,
std::string_view gfxApi = {},
uint32_t samples = 1,
uint32_t anisotropy = 1,
bool deepColor = false,
bool singleInstance = true); bool singleInstance = true);
extern IApplication* APP; extern IApplication* APP;
static inline int static inline int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb,
ApplicationRun(IApplication::EPlatformType platform, SystemStringView uniqueName, SystemStringView friendlyName, int argc,
IApplicationCallback& cb, const SystemChar** argv, std::string_view gfxApi = {}, uint32_t samples = 1,
SystemStringView uniqueName, uint32_t anisotropy = 1, bool deepColor = false, bool singleInstance = true) {
SystemStringView friendlyName,
int argc, const SystemChar** argv,
std::string_view gfxApi = {},
uint32_t samples = 1,
uint32_t anisotropy = 1,
bool deepColor = false,
bool singleInstance=true)
{
if (APP) if (APP)
return 1; return 1;
std::vector<SystemString> args; std::vector<SystemString> args;
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
args.push_back(argv[i]); args.push_back(argv[i]);
return ApplicationRun(platform, cb, uniqueName, friendlyName, argv[0], args, return ApplicationRun(platform, cb, uniqueName, friendlyName, argv[0], args, gfxApi, samples, anisotropy, deepColor,
gfxApi, samples, anisotropy, deepColor, singleInstance); singleInstance);
}
} }
} // namespace boo

View File

@ -3,21 +3,17 @@
#include <memory> #include <memory>
#include <cstdint> #include <cstdint>
namespace boo namespace boo {
{
struct IGraphicsCommandQueue; struct IGraphicsCommandQueue;
struct IGraphicsDataFactory; struct IGraphicsDataFactory;
class IGraphicsContext class IGraphicsContext {
{
friend class WindowCocoa; friend class WindowCocoa;
friend class WindowXCB; friend class WindowXCB;
virtual void _setCallback(class IWindowCallback* cb) { (void)cb; } virtual void _setCallback(class IWindowCallback* cb) { (void)cb; }
public: public:
enum class EGraphicsAPI {
enum class EGraphicsAPI
{
None = 0, None = 0,
OpenGL3_3 = 1, OpenGL3_3 = 1,
OpenGL4_2 = 2, OpenGL4_2 = 2,
@ -29,8 +25,7 @@ public:
NX = 9 NX = 9
}; };
enum class EPixelFormat enum class EPixelFormat {
{
None = 0, None = 0,
RGBA8 = 1, /* Default */ RGBA8 = 1, /* Default */
RGBA16 = 2, RGBA16 = 2,
@ -59,5 +54,4 @@ public:
virtual IGraphicsDataFactory* getLoadContextDataFactory() = 0; virtual IGraphicsDataFactory* getLoadContextDataFactory() = 0;
}; };
} } // namespace boo

View File

@ -8,66 +8,46 @@
#undef min #undef min
#undef max #undef max
namespace boo namespace boo {
{
struct IGraphicsCommandQueue; struct IGraphicsCommandQueue;
struct IGraphicsDataFactory; struct IGraphicsDataFactory;
struct IAudioVoiceEngine; struct IAudioVoiceEngine;
enum class EMouseButton enum class EMouseButton { None = 0, Primary = 1, Secondary = 2, Middle = 3, Aux1 = 4, Aux2 = 5 };
{
None = 0,
Primary = 1,
Secondary = 2,
Middle = 3,
Aux1 = 4,
Aux2 = 5
};
struct SWindowCoord struct SWindowCoord {
{
int pixel[2]; int pixel[2];
int virtualPixel[2]; int virtualPixel[2];
float norm[2]; float norm[2];
}; };
struct SWindowRect struct SWindowRect {
{
int location[2]; int location[2];
int size[2]; int size[2];
SWindowRect() { std::memset(this, 0, sizeof(SWindowRect)); } SWindowRect() { std::memset(this, 0, sizeof(SWindowRect)); }
SWindowRect(int x, int y, int w, int h) SWindowRect(int x, int y, int w, int h) {
{
location[0] = x; location[0] = x;
location[1] = y; location[1] = y;
size[0] = w; size[0] = w;
size[1] = h; size[1] = h;
} }
bool operator!=(const SWindowRect& other) const bool operator!=(const SWindowRect& other) const {
{ return location[0] != other.location[0] || location[1] != other.location[1] || size[0] != other.size[0] ||
return location[0] != other.location[0] ||
location[1] != other.location[1] ||
size[0] != other.size[0] ||
size[1] != other.size[1]; size[1] != other.size[1];
} }
bool operator==(const SWindowRect& other) const { return !(*this != other); } bool operator==(const SWindowRect& other) const { return !(*this != other); }
bool coordInRect(const SWindowCoord& coord) const bool coordInRect(const SWindowCoord& coord) const {
{ return coord.pixel[0] >= location[0] && coord.pixel[0] < location[0] + size[0] && coord.pixel[1] >= location[1] &&
return coord.pixel[0] >= location[0] && coord.pixel[0] < location[0] + size[0] && coord.pixel[1] < location[1] + size[1];
coord.pixel[1] >= location[1] && coord.pixel[1] < location[1] + size[1];
} }
SWindowRect intersect(const SWindowRect& other) const SWindowRect intersect(const SWindowRect& other) const {
{ if (location[0] < other.location[0] + other.size[0] && location[0] + size[0] > other.location[0] &&
if (location[0] < other.location[0] + other.size[0] && location[1] < other.location[1] + other.size[1] && location[1] + size[1] > other.location[1]) {
location[0] + size[0] > other.location[0] &&
location[1] < other.location[1] + other.size[1] &&
location[1] + size[1] > other.location[1])
{
SWindowRect ret; SWindowRect ret;
ret.location[0] = std::max(location[0], other.location[0]); ret.location[0] = std::max(location[0], other.location[0]);
ret.location[1] = std::max(location[1], other.location[1]); ret.location[1] = std::max(location[1], other.location[1]);
@ -79,19 +59,16 @@ struct SWindowRect
} }
}; };
struct STouchCoord struct STouchCoord {
{
double coord[2]; double coord[2];
}; };
struct SScrollDelta struct SScrollDelta {
{
double delta[2]; double delta[2];
bool isFine; /* Use system-scale fine-scroll (for scrollable-trackpads) */ bool isFine; /* Use system-scale fine-scroll (for scrollable-trackpads) */
bool isAccelerated = false; /* System performs acceleration computation */ bool isAccelerated = false; /* System performs acceleration computation */
SScrollDelta operator+(const SScrollDelta& other) SScrollDelta operator+(const SScrollDelta& other) {
{
SScrollDelta ret; SScrollDelta ret;
ret.delta[0] = delta[0] + other.delta[0]; ret.delta[0] = delta[0] + other.delta[0];
ret.delta[1] = delta[1] + other.delta[1]; ret.delta[1] = delta[1] + other.delta[1];
@ -99,19 +76,20 @@ struct SScrollDelta
ret.isAccelerated = isAccelerated || other.isAccelerated; ret.isAccelerated = isAccelerated || other.isAccelerated;
return ret; return ret;
} }
SScrollDelta& operator+=(const SScrollDelta& other) SScrollDelta& operator+=(const SScrollDelta& other) {
{
delta[0] += other.delta[0]; delta[0] += other.delta[0];
delta[1] += other.delta[1]; delta[1] += other.delta[1];
isFine |= other.isFine; isFine |= other.isFine;
isAccelerated |= other.isAccelerated; isAccelerated |= other.isAccelerated;
return *this; return *this;
} }
void zeroOut() {delta[0] = 0.0; delta[1] = 0.0;} void zeroOut() {
delta[0] = 0.0;
delta[1] = 0.0;
}
}; };
enum class ESpecialKey enum class ESpecialKey {
{
None = 0, None = 0,
F1 = 1, F1 = 1,
F2 = 2, F2 = 2,
@ -140,8 +118,7 @@ enum class ESpecialKey
Down = 25 Down = 25
}; };
enum class EModifierKey enum class EModifierKey {
{
None = 0, None = 0,
Ctrl = 1 << 0, Ctrl = 1 << 0,
Alt = 1 << 2, Alt = 1 << 2,
@ -151,81 +128,91 @@ enum class EModifierKey
}; };
ENABLE_BITWISE_ENUM(EModifierKey) ENABLE_BITWISE_ENUM(EModifierKey)
struct ITextInputCallback struct ITextInputCallback {
{
virtual bool hasMarkedText() const = 0; virtual bool hasMarkedText() const = 0;
virtual std::pair<int, int> markedRange() const = 0; virtual std::pair<int, int> markedRange() const = 0;
virtual std::pair<int, int> selectedRange() const = 0; virtual std::pair<int, int> selectedRange() const = 0;
virtual void setMarkedText(std::string_view str, virtual void setMarkedText(std::string_view str, const std::pair<int, int>& selectedRange,
const std::pair<int,int>& selectedRange,
const std::pair<int, int>& replacementRange) = 0; const std::pair<int, int>& replacementRange) = 0;
virtual void unmarkText() = 0; virtual void unmarkText() = 0;
virtual std::string substringForRange(const std::pair<int,int>& range, virtual std::string substringForRange(const std::pair<int, int>& range, std::pair<int, int>& actualRange) const = 0;
std::pair<int,int>& actualRange) const=0;
virtual void insertText(std::string_view str, const std::pair<int, int>& range = {-1, 0}) = 0; virtual void insertText(std::string_view str, const std::pair<int, int>& range = {-1, 0}) = 0;
virtual int characterIndexAtPoint(const SWindowCoord& point) const = 0; virtual int characterIndexAtPoint(const SWindowCoord& point) const = 0;
virtual SWindowRect rectForCharacterRange(const std::pair<int, int>& range, virtual SWindowRect rectForCharacterRange(const std::pair<int, int>& range,
std::pair<int, int>& actualRange) const = 0; std::pair<int, int>& actualRange) const = 0;
}; };
class IWindowCallback class IWindowCallback {
{
public: public:
virtual void resized(const SWindowRect& rect, bool sync) virtual void resized(const SWindowRect& rect, bool sync) { (void)rect; }
{(void)rect;} virtual void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) {
virtual void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) (void)coord;
{(void)coord;(void)button;(void)mods;} (void)button;
virtual void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) (void)mods;
{(void)coord;(void)button;(void)mods;} }
virtual void mouseMove(const SWindowCoord& coord) virtual void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) {
{(void)coord;} (void)coord;
virtual void mouseEnter(const SWindowCoord& coord) (void)button;
{(void)coord;} (void)mods;
virtual void mouseLeave(const SWindowCoord& coord) }
{(void)coord;} virtual void mouseMove(const SWindowCoord& coord) { (void)coord; }
virtual void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) virtual void mouseEnter(const SWindowCoord& coord) { (void)coord; }
{(void)coord;(void)scroll;} virtual void mouseLeave(const SWindowCoord& coord) { (void)coord; }
virtual void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) {
(void)coord;
(void)scroll;
}
virtual void touchDown(const STouchCoord& coord, uintptr_t tid) virtual void touchDown(const STouchCoord& coord, uintptr_t tid) {
{(void)coord;(void)tid;} (void)coord;
virtual void touchUp(const STouchCoord& coord, uintptr_t tid) (void)tid;
{(void)coord;(void)tid;} }
virtual void touchMove(const STouchCoord& coord, uintptr_t tid) virtual void touchUp(const STouchCoord& coord, uintptr_t tid) {
{(void)coord;(void)tid;} (void)coord;
(void)tid;
}
virtual void touchMove(const STouchCoord& coord, uintptr_t tid) {
(void)coord;
(void)tid;
}
virtual void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) virtual void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) {
{(void)charCode;(void)mods;(void)isRepeat;} (void)charCode;
virtual void charKeyUp(unsigned long charCode, EModifierKey mods) (void)mods;
{(void)charCode;(void)mods;} (void)isRepeat;
virtual void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) }
{(void)key;(void)mods;(void)isRepeat;} virtual void charKeyUp(unsigned long charCode, EModifierKey mods) {
virtual void specialKeyUp(ESpecialKey key, EModifierKey mods) (void)charCode;
{(void)key;(void)mods;} (void)mods;
virtual void modKeyDown(EModifierKey mod, bool isRepeat) }
{(void)mod;(void)isRepeat;} virtual void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) {
(void)key;
(void)mods;
(void)isRepeat;
}
virtual void specialKeyUp(ESpecialKey key, EModifierKey mods) {
(void)key;
(void)mods;
}
virtual void modKeyDown(EModifierKey mod, bool isRepeat) {
(void)mod;
(void)isRepeat;
}
virtual void modKeyUp(EModifierKey mod) { (void)mod; } virtual void modKeyUp(EModifierKey mod) { (void)mod; }
virtual ITextInputCallback* getTextInputCallback() { return nullptr; } virtual ITextInputCallback* getTextInputCallback() { return nullptr; }
virtual void focusLost() {} virtual void focusLost() {}
virtual void focusGained() {} virtual void focusGained() {}
virtual void windowMoved(const SWindowRect& rect) virtual void windowMoved(const SWindowRect& rect) { (void)rect; }
{ (void)rect; }
virtual void destroyed() virtual void destroyed() {}
{}
}; };
enum class ETouchType enum class ETouchType { None = 0, Display = 1, Trackpad = 2 };
{
None = 0,
Display = 1,
Trackpad = 2
};
enum class EWindowStyle enum class EWindowStyle {
{
None = 0, None = 0,
Titlebar = 1 << 0, Titlebar = 1 << 0,
Resize = 1 << 1, Resize = 1 << 1,
@ -235,28 +222,12 @@ enum class EWindowStyle
}; };
ENABLE_BITWISE_ENUM(EWindowStyle) ENABLE_BITWISE_ENUM(EWindowStyle)
enum class EMouseCursor enum class EMouseCursor { None = 0, Pointer = 1, HorizontalArrow = 2, VerticalArrow = 3, IBeam = 4, Crosshairs = 5 };
{
None = 0,
Pointer = 1,
HorizontalArrow = 2,
VerticalArrow = 3,
IBeam = 4,
Crosshairs = 5
};
enum class EClipboardType enum class EClipboardType { None = 0, String = 1, UTF8String = 2, PNGImage = 3 };
{
None = 0,
String = 1,
UTF8String = 2,
PNGImage = 3
};
class IWindow : public std::enable_shared_from_this<IWindow> class IWindow : public std::enable_shared_from_this<IWindow> {
{
public: public:
virtual ~IWindow() = default; virtual ~IWindow() = default;
virtual void setCallback(IWindowCallback* cb) = 0; virtual void setCallback(IWindowCallback* cb) = 0;
@ -274,16 +245,14 @@ public:
virtual void setWindowFrameDefault() = 0; virtual void setWindowFrameDefault() = 0;
virtual void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const = 0; virtual void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const = 0;
virtual void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const = 0; virtual void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const = 0;
virtual SWindowRect getWindowFrame() const virtual SWindowRect getWindowFrame() const {
{
SWindowRect retval; SWindowRect retval;
getWindowFrame(retval.location[0], retval.location[1], retval.size[0], retval.size[1]); getWindowFrame(retval.location[0], retval.location[1], retval.size[0], retval.size[1]);
return retval; return retval;
} }
virtual void setWindowFrame(float x, float y, float w, float h) = 0; virtual void setWindowFrame(float x, float y, float w, float h) = 0;
virtual void setWindowFrame(int x, int y, int w, int h) = 0; virtual void setWindowFrame(int x, int y, int w, int h) = 0;
virtual void setWindowFrame(const SWindowRect& rect) virtual void setWindowFrame(const SWindowRect& rect) {
{
setWindowFrame(rect.location[0], rect.location[1], rect.size[0], rect.size[1]); setWindowFrame(rect.location[0], rect.location[1], rect.size[0], rect.size[1]);
} }
virtual float getVirtualPixelFactor() const = 0; virtual float getVirtualPixelFactor() const = 0;
@ -298,7 +267,10 @@ public:
virtual void waitForRetrace() = 0; virtual void waitForRetrace() = 0;
virtual uintptr_t getPlatformHandle() const = 0; virtual uintptr_t getPlatformHandle() const = 0;
virtual bool _incomingEvent(void* event) {(void)event; return false;} virtual bool _incomingEvent(void* event) {
(void)event;
return false;
}
virtual void _cleanup() {} virtual void _cleanup() {}
virtual ETouchType getTouchType() const = 0; virtual ETouchType getTouchType() const = 0;
@ -318,5 +290,4 @@ public:
virtual IGraphicsDataFactory* getLoadContextDataFactory() = 0; virtual IGraphicsDataFactory* getLoadContextDataFactory() = 0;
}; };
} } // namespace boo

View File

@ -14,8 +14,9 @@
template <class T> template <class T>
using ComPtr = Microsoft::WRL::ComPtr<T>; using ComPtr = Microsoft::WRL::ComPtr<T>;
template <class T> template <class T>
static inline ComPtr<T>* ReferenceComPtr(ComPtr<T>& ptr) static inline ComPtr<T>* ReferenceComPtr(ComPtr<T>& ptr) {
{ return reinterpret_cast<ComPtr<T>*>(ptr.GetAddressOf()); } return reinterpret_cast<ComPtr<T>*>(ptr.GetAddressOf());
}
#endif #endif
#include <string> #include <string>
@ -23,37 +24,31 @@ static inline ComPtr<T>* ReferenceComPtr(ComPtr<T>& ptr)
#ifndef ENABLE_BITWISE_ENUM #ifndef ENABLE_BITWISE_ENUM
#define ENABLE_BITWISE_ENUM(type) \ #define ENABLE_BITWISE_ENUM(type) \
constexpr type operator|(type a, type b)\ constexpr type operator|(type a, type b) { \
{\
using T = std::underlying_type_t<type>; \ using T = std::underlying_type_t<type>; \
return type(static_cast<T>(a) | static_cast<T>(b)); \ return type(static_cast<T>(a) | static_cast<T>(b)); \
} \ } \
constexpr type operator&(type a, type b)\ constexpr type operator&(type a, type b) { \
{\
using T = std::underlying_type_t<type>; \ using T = std::underlying_type_t<type>; \
return type(static_cast<T>(a) & static_cast<T>(b)); \ return type(static_cast<T>(a) & static_cast<T>(b)); \
} \ } \
inline type& operator|=(type& a, const type& b)\ inline type& operator|=(type& a, const type& b) { \
{\
using T = std::underlying_type_t<type>; \ using T = std::underlying_type_t<type>; \
a = type(static_cast<T>(a) | static_cast<T>(b)); \ a = type(static_cast<T>(a) | static_cast<T>(b)); \
return a; \ return a; \
} \ } \
inline type& operator&=(type& a, const type& b)\ inline type& operator&=(type& a, const type& b) { \
{\
using T = std::underlying_type_t<type>; \ using T = std::underlying_type_t<type>; \
a = type(static_cast<T>(a) & static_cast<T>(b)); \ a = type(static_cast<T>(a) & static_cast<T>(b)); \
return a; \ return a; \
} \ } \
inline type operator~(const type& key)\ inline type operator~(const type& key) { \
{\
using T = std::underlying_type_t<type>; \ using T = std::underlying_type_t<type>; \
return type(~static_cast<T>(key)); \ return type(~static_cast<T>(key)); \
} }
#endif #endif
namespace boo namespace boo {
{
#ifdef _WIN32 #ifdef _WIN32
using SystemString = std::wstring; using SystemString = std::wstring;
@ -75,7 +70,9 @@ namespace boo
#define __BooTraceArgs , const char *file, int line #define __BooTraceArgs , const char *file, int line
#define __BooTraceArgsUse , file, line #define __BooTraceArgsUse , file, line
#define __BooTraceInitializer , m_file(file), m_line(line) #define __BooTraceInitializer , m_file(file), m_line(line)
#define __BooTraceFields const char* m_file; int m_line; #define __BooTraceFields \
const char* m_file; \
int m_line;
#define BooTrace , __FILE__, __LINE__ #define BooTrace , __FILE__, __LINE__
#else #else
#define __BooTraceArgs #define __BooTraceArgs
@ -85,5 +82,4 @@ namespace boo
#define BooTrace #define BooTrace
#endif #endif
} } // namespace boo

View File

@ -9,10 +9,10 @@
/** Multiplatform TLS-pointer wrapper (for compilers without proper thread_local support) */ /** Multiplatform TLS-pointer wrapper (for compilers without proper thread_local support) */
template <class T> template <class T>
class ThreadLocalPtr class ThreadLocalPtr {
{
#if _WIN32 #if _WIN32
DWORD m_key; DWORD m_key;
public: public:
ThreadLocalPtr() { m_key = TlsAlloc(); } ThreadLocalPtr() { m_key = TlsAlloc(); }
~ThreadLocalPtr() { TlsFree(m_key); } ~ThreadLocalPtr() { TlsFree(m_key); }
@ -20,6 +20,7 @@ public:
void reset(T* v = nullptr) { TlsSetValue(m_key, LPVOID(v)); } void reset(T* v = nullptr) { TlsSetValue(m_key, LPVOID(v)); }
#else #else
pthread_key_t m_key; pthread_key_t m_key;
public: public:
ThreadLocalPtr() { pthread_key_create(&m_key, nullptr); } ThreadLocalPtr() { pthread_key_create(&m_key, nullptr); }
~ThreadLocalPtr() { pthread_key_delete(m_key); } ~ThreadLocalPtr() { pthread_key_delete(m_key); }
@ -30,4 +31,3 @@ public:
}; };
#endif #endif

View File

@ -2,24 +2,19 @@
#include "IApplication.hpp" #include "IApplication.hpp"
namespace boo namespace boo {
{
#if WINDOWS_STORE #if WINDOWS_STORE
using namespace Windows::ApplicationModel::Core; using namespace Windows::ApplicationModel::Core;
ref struct ViewProvider sealed : IFrameworkViewSource ref struct ViewProvider sealed : IFrameworkViewSource {
{ internal : ViewProvider(boo::IApplicationCallback& appCb, SystemStringView uniqueName, SystemStringView friendlyName,
internal: SystemStringView pname, Platform::Array<Platform::String ^> ^ params, bool singleInstance)
ViewProvider(boo::IApplicationCallback& appCb, : m_appCb(appCb)
SystemStringView uniqueName, , m_uniqueName(uniqueName)
SystemStringView friendlyName, , m_friendlyName(friendlyName)
SystemStringView pname, , m_pname(pname)
Platform::Array<Platform::String^>^ params, , m_singleInstance(singleInstance) {
bool singleInstance)
: m_appCb(appCb), m_uniqueName(uniqueName), m_friendlyName(friendlyName),
m_pname(pname), m_singleInstance(singleInstance)
{
SystemChar selfPath[1024]; SystemChar selfPath[1024];
GetModuleFileNameW(nullptr, selfPath, 1024); GetModuleFileNameW(nullptr, selfPath, 1024);
m_args.reserve(params->Length + 1); m_args.reserve(params->Length + 1);
@ -27,11 +22,11 @@ internal:
for (Platform::String ^ str : params) for (Platform::String ^ str : params)
m_args.emplace_back(str->Data()); m_args.emplace_back(str->Data());
} }
public: public:
virtual IFrameworkView ^ CreateView(); virtual IFrameworkView ^ CreateView();
internal: internal : boo::IApplicationCallback& m_appCb;
boo::IApplicationCallback& m_appCb;
SystemString m_uniqueName; SystemString m_uniqueName;
SystemString m_friendlyName; SystemString m_friendlyName;
SystemString m_pname; SystemString m_pname;
@ -40,5 +35,4 @@ internal:
}; };
#endif #endif
} } // namespace boo

View File

@ -5,22 +5,15 @@
#include <memory> #include <memory>
#include "boo/BooObject.hpp" #include "boo/BooObject.hpp"
namespace boo namespace boo {
{
struct IAudioVoice; struct IAudioVoice;
struct IAudioVoiceCallback; struct IAudioVoiceCallback;
struct ChannelMap; struct ChannelMap;
struct IAudioSubmixCallback; struct IAudioSubmixCallback;
enum class SubmixFormat enum class SubmixFormat { Int16, Int32, Float };
{
Int16,
Int32,
Float
};
struct IAudioSubmix : IObj struct IAudioSubmix : IObj {
{
/** Reset channel-levels to silence; unbind all submixes */ /** Reset channel-levels to silence; unbind all submixes */
virtual void resetSendLevels() = 0; virtual void resetSendLevels() = 0;
@ -34,22 +27,17 @@ struct IAudioSubmix : IObj
virtual SubmixFormat getSampleFormat() const = 0; virtual SubmixFormat getSampleFormat() const = 0;
}; };
struct IAudioSubmixCallback struct IAudioSubmixCallback {
{
/** Client-provided claim to implement / is ready to call applyEffect() */ /** Client-provided claim to implement / is ready to call applyEffect() */
virtual bool canApplyEffect() const = 0; virtual bool canApplyEffect() const = 0;
/** Client-provided effect solution for interleaved, master sample-rate audio */ /** Client-provided effect solution for interleaved, master sample-rate audio */
virtual void applyEffect(int16_t* audio, size_t frameCount, virtual void applyEffect(int16_t* audio, size_t frameCount, const ChannelMap& chanMap, double sampleRate) const = 0;
const ChannelMap& chanMap, double sampleRate) const=0; virtual void applyEffect(int32_t* audio, size_t frameCount, const ChannelMap& chanMap, double sampleRate) const = 0;
virtual void applyEffect(int32_t* audio, size_t frameCount, virtual void applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap, double sampleRate) const = 0;
const ChannelMap& chanMap, double sampleRate) const=0;
virtual void applyEffect(float* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate) const=0;
/** Notify of output sample rate changes (for instance, changing the default audio device on Windows) */ /** Notify of output sample rate changes (for instance, changing the default audio device on Windows) */
virtual void resetOutputSampleRate(double sampleRate) = 0; virtual void resetOutputSampleRate(double sampleRate) = 0;
}; };
} } // namespace boo

View File

@ -5,21 +5,12 @@
#include <cstring> #include <cstring>
#include "boo/BooObject.hpp" #include "boo/BooObject.hpp"
namespace boo namespace boo {
{
struct IAudioSubmix; struct IAudioSubmix;
enum class AudioChannelSet enum class AudioChannelSet { Stereo, Quad, Surround51, Surround71, Unknown = 0xff };
{
Stereo,
Quad,
Surround51,
Surround71,
Unknown = 0xff
};
enum class AudioChannel enum class AudioChannel {
{
FrontLeft, FrontLeft,
FrontRight, FrontRight,
RearLeft, RearLeft,
@ -31,16 +22,13 @@ enum class AudioChannel
Unknown = 0xff Unknown = 0xff
}; };
struct ChannelMap struct ChannelMap {
{
unsigned m_channelCount = 0; unsigned m_channelCount = 0;
AudioChannel m_channels[8] = {}; AudioChannel m_channels[8] = {};
}; };
static inline unsigned ChannelCount(AudioChannelSet layout) static inline unsigned ChannelCount(AudioChannelSet layout) {
{ switch (layout) {
switch (layout)
{
case AudioChannelSet::Stereo: case AudioChannelSet::Stereo:
return 2; return 2;
case AudioChannelSet::Quad: case AudioChannelSet::Quad:
@ -49,13 +37,13 @@ static inline unsigned ChannelCount(AudioChannelSet layout)
return 6; return 6;
case AudioChannelSet::Surround71: case AudioChannelSet::Surround71:
return 8; return 8;
default: break; default:
break;
} }
return 0; return 0;
} }
struct IAudioVoice : IObj struct IAudioVoice : IObj {
{
/** Set sample rate into voice (may result in audio discontinuities) */ /** Set sample rate into voice (may result in audio discontinuities) */
virtual void resetSampleRate(double sampleRate) = 0; virtual void resetSampleRate(double sampleRate) = 0;
@ -78,8 +66,7 @@ struct IAudioVoice : IObj
virtual void stop() = 0; virtual void stop() = 0;
}; };
struct IAudioVoiceCallback struct IAudioVoiceCallback {
{
/** boo calls this on behalf of the audio platform to proactively invoke potential /** boo calls this on behalf of the audio platform to proactively invoke potential
* pitch or panning changes before processing samples */ * pitch or panning changes before processing samples */
virtual void preSupplyAudio(boo::IAudioVoice& voice, double dt) = 0; virtual void preSupplyAudio(boo::IAudioVoice& voice, double dt) = 0;
@ -90,21 +77,17 @@ struct IAudioVoiceCallback
/** after resampling, boo calls this for each submix that this voice targets; /** after resampling, boo calls this for each submix that this voice targets;
* client performs volume processing and bus-routing this way */ * client performs volume processing and bus-routing this way */
virtual void routeAudio(size_t frames, size_t channels, double dt, int busId, int16_t* in, int16_t* out) virtual void routeAudio(size_t frames, size_t channels, double dt, int busId, int16_t* in, int16_t* out) {
{
memmove(out, in, frames * channels * 2); memmove(out, in, frames * channels * 2);
} }
virtual void routeAudio(size_t frames, size_t channels, double dt, int busId, int32_t* in, int32_t* out) virtual void routeAudio(size_t frames, size_t channels, double dt, int busId, int32_t* in, int32_t* out) {
{
memmove(out, in, frames * channels * 4); memmove(out, in, frames * channels * 4);
} }
virtual void routeAudio(size_t frames, size_t channels, double dt, int busId, float* in, float* out) virtual void routeAudio(size_t frames, size_t channels, double dt, int busId, float* in, float* out) {
{
memmove(out, in, frames * channels * 4); memmove(out, in, frames * channels * 4);
} }
}; };
} } // namespace boo

View File

@ -7,13 +7,11 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
namespace boo namespace boo {
{
struct IAudioVoiceEngine; struct IAudioVoiceEngine;
/** Time-sensitive event callback for synchronizing the client with rendered audio waveform */ /** Time-sensitive event callback for synchronizing the client with rendered audio waveform */
struct IAudioVoiceEngineCallback struct IAudioVoiceEngineCallback {
{
/** All mixing occurs in virtual 5ms intervals; /** All mixing occurs in virtual 5ms intervals;
* this is called at the start of each interval for all mixable entities */ * this is called at the start of each interval for all mixable entities */
virtual void on5MsInterval(IAudioVoiceEngine& engine, double dt) {} virtual void on5MsInterval(IAudioVoiceEngine& engine, double dt) {}
@ -25,8 +23,7 @@ struct IAudioVoiceEngineCallback
/** Mixing and sample-rate-conversion system. Allocates voices and mixes them /** Mixing and sample-rate-conversion system. Allocates voices and mixes them
* before sending the final samples to an OS-supplied audio-queue */ * before sending the final samples to an OS-supplied audio-queue */
struct IAudioVoiceEngine struct IAudioVoiceEngine {
{
virtual ~IAudioVoiceEngine() = default; virtual ~IAudioVoiceEngine() = default;
/** Client calls this to request allocation of new mixer-voice. /** Client calls this to request allocation of new mixer-voice.
@ -36,13 +33,11 @@ struct IAudioVoiceEngine
* Client must be prepared to supply audio frames via the callback when this is called; * Client must be prepared to supply audio frames via the callback when this is called;
* the backing audio-buffers are primed with initial data for low-latency playback start * the backing audio-buffers are primed with initial data for low-latency playback start
*/ */
virtual ObjToken<IAudioVoice> allocateNewMonoVoice(double sampleRate, virtual ObjToken<IAudioVoice> allocateNewMonoVoice(double sampleRate, IAudioVoiceCallback* cb,
IAudioVoiceCallback* cb,
bool dynamicPitch = false) = 0; bool dynamicPitch = false) = 0;
/** Same as allocateNewMonoVoice, but source audio is stereo-interleaved */ /** Same as allocateNewMonoVoice, but source audio is stereo-interleaved */
virtual ObjToken<IAudioVoice> allocateNewStereoVoice(double sampleRate, virtual ObjToken<IAudioVoice> allocateNewStereoVoice(double sampleRate, IAudioVoiceCallback* cb,
IAudioVoiceCallback* cb,
bool dynamicPitch = false) = 0; bool dynamicPitch = false) = 0;
/** Client calls this to allocate a Submix for gathering audio together for effects processing */ /** Client calls this to allocate a Submix for gathering audio together for effects processing */
@ -112,5 +107,4 @@ std::unique_ptr<IAudioVoiceEngine> NewWAVAudioVoiceEngine(const char* path, doub
std::unique_ptr<IAudioVoiceEngine> NewWAVAudioVoiceEngine(const wchar_t* path, double sampleRate, int numChans); std::unique_ptr<IAudioVoiceEngine> NewWAVAudioVoiceEngine(const wchar_t* path, double sampleRate, int numChans);
#endif #endif
} } // namespace boo

View File

@ -5,17 +5,17 @@
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>
namespace boo namespace boo {
{
struct IAudioVoiceEngine; 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:
IAudioVoiceEngine* m_parent; IAudioVoiceEngine* m_parent;
IMIDIPort(IAudioVoiceEngine* parent, bool virt) : m_virtual(virt), m_parent(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; }
@ -23,40 +23,38 @@ public:
void _disown() { m_parent = nullptr; } void _disown() { m_parent = nullptr; }
}; };
class IMIDIReceiver class IMIDIReceiver {
{
public: public:
ReceiveFunctor m_receiver; ReceiveFunctor m_receiver;
IMIDIReceiver(ReceiveFunctor&& receiver) : m_receiver(std::move(receiver)) {} IMIDIReceiver(ReceiveFunctor&& receiver) : m_receiver(std::move(receiver)) {}
}; };
class IMIDIIn : public IMIDIPort, public IMIDIReceiver class IMIDIIn : public IMIDIPort, public IMIDIReceiver {
{
protected: protected:
IMIDIIn(IAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) IMIDIIn(IAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver)
: IMIDIPort(parent, virt), IMIDIReceiver(std::move(receiver)) {} : IMIDIPort(parent, virt), IMIDIReceiver(std::move(receiver)) {}
public: public:
virtual ~IMIDIIn(); virtual ~IMIDIIn();
}; };
class IMIDIOut : public IMIDIPort class IMIDIOut : public IMIDIPort {
{
protected: protected:
IMIDIOut(IAudioVoiceEngine* parent, bool virt) : IMIDIPort(parent, 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;
}; };
class IMIDIInOut : public IMIDIPort, public IMIDIReceiver class IMIDIInOut : public IMIDIPort, public IMIDIReceiver {
{
protected: protected:
IMIDIInOut(IAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) IMIDIInOut(IAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver)
: IMIDIPort(parent, 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;
}; };
} } // namespace boo

View File

@ -3,11 +3,9 @@
#include <cstdlib> #include <cstdlib>
#include <cstdint> #include <cstdint>
namespace boo namespace boo {
{
class IMIDIReader class IMIDIReader {
{
public: public:
virtual void noteOff(uint8_t chan, uint8_t key, uint8_t velocity) = 0; virtual void noteOff(uint8_t chan, uint8_t key, uint8_t velocity) = 0;
virtual void noteOn(uint8_t chan, uint8_t key, uint8_t velocity) = 0; virtual void noteOn(uint8_t chan, uint8_t key, uint8_t velocity) = 0;
@ -37,5 +35,4 @@ public:
virtual void reset() = 0; virtual void reset() = 0;
}; };
} } // namespace boo

View File

@ -5,22 +5,18 @@
#include <functional> #include <functional>
#include <vector> #include <vector>
namespace boo namespace boo {
{
class MIDIDecoder class MIDIDecoder {
{
IMIDIReader& m_out; IMIDIReader& m_out;
uint8_t m_status = 0; uint8_t m_status = 0;
bool _readContinuedValue(std::vector<uint8_t>::const_iterator& it, bool _readContinuedValue(std::vector<uint8_t>::const_iterator& it, std::vector<uint8_t>::const_iterator end,
std::vector<uint8_t>::const_iterator end,
uint32_t& valOut); uint32_t& valOut);
public: public:
MIDIDecoder(IMIDIReader& out) : m_out(out) {} MIDIDecoder(IMIDIReader& out) : m_out(out) {}
std::vector<uint8_t>::const_iterator std::vector<uint8_t>::const_iterator receiveBytes(std::vector<uint8_t>::const_iterator begin,
receiveBytes(std::vector<uint8_t>::const_iterator begin,
std::vector<uint8_t>::const_iterator end); std::vector<uint8_t>::const_iterator end);
}; };
} } // namespace boo

View File

@ -3,16 +3,15 @@
#include "boo/audiodev/IMIDIReader.hpp" #include "boo/audiodev/IMIDIReader.hpp"
#include "boo/audiodev/IMIDIPort.hpp" #include "boo/audiodev/IMIDIPort.hpp"
namespace boo namespace boo {
{
template <class Sender> template <class Sender>
class MIDIEncoder : public IMIDIReader class MIDIEncoder : public IMIDIReader {
{
Sender& m_sender; Sender& m_sender;
uint8_t m_status = 0; uint8_t m_status = 0;
void _sendMessage(const uint8_t* data, size_t len); void _sendMessage(const uint8_t* data, size_t len);
void _sendContinuedValue(uint32_t val); void _sendContinuedValue(uint32_t val);
public: public:
MIDIEncoder(Sender& sender) : m_sender(sender) {} MIDIEncoder(Sender& sender) : m_sender(sender) {}
@ -44,5 +43,4 @@ public:
void reset(); void reset();
}; };
} } // namespace boo

View File

@ -10,4 +10,3 @@
#include "graphicsdev/IGraphicsCommandQueue.hpp" #include "graphicsdev/IGraphicsCommandQueue.hpp"
#include "graphicsdev/IGraphicsDataFactory.hpp" #include "graphicsdev/IGraphicsDataFactory.hpp"
#include "DeferredWindowEvents.hpp" #include "DeferredWindowEvents.hpp"

View File

@ -9,30 +9,26 @@
#include <vector> #include <vector>
#include <unordered_set> #include <unordered_set>
typedef HRESULT (WINAPI *pD3DCreateBlob) typedef HRESULT(WINAPI* pD3DCreateBlob)(SIZE_T Size, ID3DBlob** ppBlob);
(SIZE_T Size,
ID3DBlob** ppBlob);
extern pD3DCreateBlob D3DCreateBlobPROC; extern pD3DCreateBlob D3DCreateBlobPROC;
namespace boo namespace boo {
{
struct BaseGraphicsData; struct BaseGraphicsData;
class D3D11DataFactory : public IGraphicsDataFactory class D3D11DataFactory : public IGraphicsDataFactory {
{
public: public:
virtual ~D3D11DataFactory() = default; virtual ~D3D11DataFactory() = default;
Platform platform() const { return Platform::D3D11; } Platform platform() const { return Platform::D3D11; }
const SystemChar* platformName() const { return _SYS_STR("D3D11"); } const SystemChar* platformName() const { return _SYS_STR("D3D11"); }
class Context final : public IGraphicsDataFactory::Context class Context final : public IGraphicsDataFactory::Context {
{
friend class D3D11DataFactoryImpl; friend class D3D11DataFactoryImpl;
D3D11DataFactory& m_parent; D3D11DataFactory& m_parent;
boo::ObjToken<BaseGraphicsData> m_data; boo::ObjToken<BaseGraphicsData> m_data;
Context(D3D11DataFactory& parent __BooTraceArgs); Context(D3D11DataFactory& parent __BooTraceArgs);
~Context(); ~Context();
public: public:
Platform platform() const { return Platform::D3D11; } Platform platform() const { return Platform::D3D11; }
const SystemChar* platformName() const { return _SYS_STR("D3D11"); } const SystemChar* platformName() const { return _SYS_STR("D3D11"); }
@ -43,36 +39,31 @@ public:
boo::ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, boo::ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz); TextureClampMode clampMode, const void* data, size_t sz);
boo::ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, boo::ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, TextureFormat fmt, TextureClampMode clampMode, const void* data,
const void* data, size_t sz); size_t sz);
boo::ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); boo::ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt,
TextureClampMode clampMode);
boo::ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, boo::ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindCount, size_t depthBindCount); size_t colorBindCount, size_t depthBindCount);
ObjToken<IShaderStage> ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
ObjToken<IShaderPipeline> ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control, ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt, ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo); const AdditionalPipelineInfo& additionalInfo);
boo::ObjToken<IShaderDataBinding> boo::ObjToken<IShaderDataBinding> newShaderDataBinding(
newShaderDataBinding(const boo::ObjToken<IShaderPipeline>& pipeline, const boo::ObjToken<IShaderPipeline>& pipeline, const boo::ObjToken<IGraphicsBuffer>& vbo,
const boo::ObjToken<IGraphicsBuffer>& vbo, const boo::ObjToken<IGraphicsBuffer>& instVbo, const boo::ObjToken<IGraphicsBuffer>& ibo, size_t ubufCount,
const boo::ObjToken<IGraphicsBuffer>& instVbo, const boo::ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs,
const boo::ObjToken<IGraphicsBuffer>& ibo, const size_t* ubufSizes, size_t texCount, const boo::ObjToken<ITexture>* texs, const int* bindIdxs,
size_t ubufCount, const boo::ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const bool* bindDepth, size_t baseVert = 0, size_t baseInst = 0);
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, const boo::ObjToken<ITexture>* texs,
const int* bindIdxs, const bool* bindDepth,
size_t baseVert = 0, size_t baseInst = 0);
}; };
static std::vector<uint8_t> CompileHLSL(const char* source, PipelineStage stage); static std::vector<uint8_t> CompileHLSL(const char* source, PipelineStage stage);
}; };
} } // namespace boo
#endif // _WIN32 #endif // _WIN32

View File

@ -6,27 +6,24 @@
#include "boo/IGraphicsContext.hpp" #include "boo/IGraphicsContext.hpp"
#include "GLSLMacros.hpp" #include "GLSLMacros.hpp"
namespace boo namespace boo {
{
struct BaseGraphicsData; struct BaseGraphicsData;
struct GLContext struct GLContext {
{
uint32_t m_sampleCount = 1; uint32_t m_sampleCount = 1;
uint32_t m_anisotropy = 1; uint32_t m_anisotropy = 1;
bool m_deepColor = false; bool m_deepColor = false;
}; };
class GLDataFactory : public IGraphicsDataFactory class GLDataFactory : public IGraphicsDataFactory {
{
public: public:
class Context final : public IGraphicsDataFactory::Context class Context final : public IGraphicsDataFactory::Context {
{
friend class GLDataFactoryImpl; friend class GLDataFactoryImpl;
GLDataFactory& m_parent; GLDataFactory& m_parent;
ObjToken<BaseGraphicsData> m_data; ObjToken<BaseGraphicsData> m_data;
Context(GLDataFactory& parent __BooTraceArgs); Context(GLDataFactory& parent __BooTraceArgs);
~Context(); ~Context();
public: public:
Platform platform() const { return Platform::OpenGL; } Platform platform() const { return Platform::OpenGL; }
const SystemChar* platformName() const { return _SYS_STR("OpenGL"); } const SystemChar* platformName() const { return _SYS_STR("OpenGL"); }
@ -37,33 +34,28 @@ public:
ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz); TextureClampMode clampMode, const void* data, size_t sz);
ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz); TextureFormat fmt, TextureClampMode clampMode, const void* data,
size_t sz);
ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode);
ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindingCount, size_t depthBindingCount); size_t colorBindingCount, size_t depthBindingCount);
ObjToken<IShaderStage> ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
ObjToken<IShaderPipeline> ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control, ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt, ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo); const AdditionalPipelineInfo& additionalInfo);
ObjToken<IShaderDataBinding> ObjToken<IShaderDataBinding> newShaderDataBinding(
newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline, const ObjToken<IShaderPipeline>& pipeline, const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& vbo, const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>& ibo, size_t ubufCount,
const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs,
const ObjToken<IGraphicsBuffer>& ibo, const size_t* ubufSizes, size_t texCount, const ObjToken<ITexture>* texs, const int* texBindIdx,
size_t ubufCount, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const bool* depthBind, size_t baseVert = 0, size_t baseInst = 0);
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, const ObjToken<ITexture>* texs,
const int* texBindIdx, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0);
}; };
}; };
} } // namespace boo
#endif #endif

View File

@ -47,4 +47,3 @@
"#define TBINDING6\n" \ "#define TBINDING6\n" \
"#define TBINDING7\n" \ "#define TBINDING7\n" \
"#endif\n" "#endif\n"

View File

@ -4,11 +4,9 @@
#include "boo/IWindow.hpp" #include "boo/IWindow.hpp"
#include <functional> #include <functional>
namespace boo namespace boo {
{
struct IGraphicsCommandQueue struct IGraphicsCommandQueue {
{
virtual ~IGraphicsCommandQueue() = default; virtual ~IGraphicsCommandQueue() = default;
using Platform = IGraphicsDataFactory::Platform; using Platform = IGraphicsDataFactory::Platform;
@ -31,8 +29,8 @@ struct IGraphicsCommandQueue
virtual void drawInstances(size_t start, size_t count, size_t instCount, size_t startInst = 0) = 0; virtual void drawInstances(size_t start, size_t count, size_t instCount, size_t startInst = 0) = 0;
virtual void drawInstancesIndexed(size_t start, size_t count, size_t instCount, size_t startInst = 0) = 0; virtual void drawInstancesIndexed(size_t start, size_t count, size_t instCount, size_t startInst = 0) = 0;
virtual void resolveBindTexture(const ObjToken<ITextureR>& texture, const SWindowRect& rect, virtual void resolveBindTexture(const ObjToken<ITextureR>& texture, const SWindowRect& rect, bool tlOrigin,
bool tlOrigin, int bindIdx, bool color, bool depth, bool clearDepth=false)=0; int bindIdx, bool color, bool depth, bool clearDepth = false) = 0;
virtual void resolveDisplay(const ObjToken<ITextureR>& source) = 0; virtual void resolveDisplay(const ObjToken<ITextureR>& source) = 0;
virtual void execute() = 0; virtual void execute() = 0;
@ -40,5 +38,4 @@ struct IGraphicsCommandQueue
virtual void stopRenderer() = 0; virtual void stopRenderer() = 0;
}; };
} } // namespace boo

View File

@ -12,78 +12,48 @@
#include <ctype.h> #include <ctype.h>
#endif #endif
namespace boo namespace boo {
{
struct IGraphicsCommandQueue; struct IGraphicsCommandQueue;
/** Supported buffer uses */ /** Supported buffer uses */
enum class BufferUse enum class BufferUse { Null, Vertex, Index, Uniform };
{
Null,
Vertex,
Index,
Uniform
};
/** Typeless graphics buffer */ /** Typeless graphics buffer */
struct IGraphicsBuffer : IObj struct IGraphicsBuffer : IObj {
{
bool dynamic() const { return m_dynamic; } bool dynamic() const { return m_dynamic; }
protected: protected:
bool m_dynamic; bool m_dynamic;
explicit IGraphicsBuffer(bool dynamic) : m_dynamic(dynamic) {} explicit IGraphicsBuffer(bool dynamic) : m_dynamic(dynamic) {}
}; };
/** Static resource buffer for verts, indices, uniform constants */ /** Static resource buffer for verts, indices, uniform constants */
struct IGraphicsBufferS : IGraphicsBuffer struct IGraphicsBufferS : IGraphicsBuffer {
{
protected: protected:
IGraphicsBufferS() : IGraphicsBuffer(false) {} IGraphicsBufferS() : IGraphicsBuffer(false) {}
}; };
/** Dynamic resource buffer for verts, indices, uniform constants */ /** Dynamic resource buffer for verts, indices, uniform constants */
struct IGraphicsBufferD : IGraphicsBuffer struct IGraphicsBufferD : IGraphicsBuffer {
{
virtual void load(const void* data, size_t sz) = 0; virtual void load(const void* data, size_t sz) = 0;
virtual void* map(size_t sz) = 0; virtual void* map(size_t sz) = 0;
virtual void unmap() = 0; virtual void unmap() = 0;
protected: protected:
IGraphicsBufferD() : IGraphicsBuffer(true) {} IGraphicsBufferD() : IGraphicsBuffer(true) {}
}; };
/** Texture access types */ /** Texture access types */
enum class TextureType enum class TextureType { Static, StaticArray, Dynamic, Render };
{
Static,
StaticArray,
Dynamic,
Render
};
/** Supported texture formats */ /** Supported texture formats */
enum class TextureFormat enum class TextureFormat { RGBA8, I8, I16, DXT1, PVRTC4 };
{
RGBA8,
I8,
I16,
DXT1,
PVRTC4
};
/** Supported texture clamp modes */ /** Supported texture clamp modes */
enum class TextureClampMode enum class TextureClampMode { Invalid = -1, Repeat, ClampToWhite, ClampToBlack, ClampToEdge, ClampToEdgeNearest };
{
Invalid = -1,
Repeat,
ClampToWhite,
ClampToBlack,
ClampToEdge,
ClampToEdgeNearest
};
/** Typeless texture */ /** Typeless texture */
struct ITexture : IObj struct ITexture : IObj {
{
TextureType type() const { return m_type; } TextureType type() const { return m_type; }
/* Only applies on GL and Vulkan. Use shader semantics on other platforms */ /* Only applies on GL and Vulkan. Use shader semantics on other platforms */
@ -95,39 +65,35 @@ protected:
}; };
/** Static resource buffer for textures */ /** Static resource buffer for textures */
struct ITextureS : ITexture struct ITextureS : ITexture {
{
protected: protected:
ITextureS() : ITexture(TextureType::Static) {} ITextureS() : ITexture(TextureType::Static) {}
}; };
/** Static-array resource buffer for array textures */ /** Static-array resource buffer for array textures */
struct ITextureSA : ITexture struct ITextureSA : ITexture {
{
protected: protected:
ITextureSA() : ITexture(TextureType::StaticArray) {} ITextureSA() : ITexture(TextureType::StaticArray) {}
}; };
/** Dynamic resource buffer for textures */ /** Dynamic resource buffer for textures */
struct ITextureD : ITexture struct ITextureD : ITexture {
{
virtual void load(const void* data, size_t sz) = 0; virtual void load(const void* data, size_t sz) = 0;
virtual void* map(size_t sz) = 0; virtual void* map(size_t sz) = 0;
virtual void unmap() = 0; virtual void unmap() = 0;
protected: protected:
ITextureD() : ITexture(TextureType::Dynamic) {} ITextureD() : ITexture(TextureType::Dynamic) {}
}; };
/** Resource buffer for render-target textures */ /** Resource buffer for render-target textures */
struct ITextureR : ITexture struct ITextureR : ITexture {
{
protected: protected:
ITextureR() : ITexture(TextureType::Render) {} ITextureR() : ITexture(TextureType::Render) {}
}; };
/** Types of vertex attributes */ /** Types of vertex attributes */
enum class VertexSemantic enum class VertexSemantic {
{
None = 0, None = 0,
Position3, Position3,
Position4, Position4,
@ -145,29 +111,24 @@ enum class VertexSemantic
ENABLE_BITWISE_ENUM(VertexSemantic) ENABLE_BITWISE_ENUM(VertexSemantic)
/** Used to create IVertexFormat */ /** Used to create IVertexFormat */
struct VertexElementDescriptor struct VertexElementDescriptor {
{
VertexSemantic semantic; VertexSemantic semantic;
int semanticIdx = 0; int semanticIdx = 0;
VertexElementDescriptor() = default; VertexElementDescriptor() = default;
VertexElementDescriptor(VertexSemantic s, int idx=0) VertexElementDescriptor(VertexSemantic s, int idx = 0) : semantic(s), semanticIdx(idx) {}
: semantic(s), semanticIdx(idx) {}
}; };
/** Structure for passing vertex format info for pipeline construction */ /** Structure for passing vertex format info for pipeline construction */
struct VertexFormatInfo struct VertexFormatInfo {
{
size_t elementCount = 0; size_t elementCount = 0;
const VertexElementDescriptor* elements = nullptr; const VertexElementDescriptor* elements = nullptr;
VertexFormatInfo() = default; VertexFormatInfo() = default;
VertexFormatInfo(size_t sz, const VertexElementDescriptor* elem) VertexFormatInfo(size_t sz, const VertexElementDescriptor* elem) : elementCount(sz), elements(elem) {}
: elementCount(sz), elements(elem) {}
template <typename T> template <typename T>
VertexFormatInfo(const T& tp) VertexFormatInfo(const T& tp) : elementCount(std::extent_v<T>), elements(tp) {}
: elementCount(std::extent_v<T>), elements(tp) {}
VertexFormatInfo(const std::initializer_list<VertexElementDescriptor>& l) VertexFormatInfo(const std::initializer_list<VertexElementDescriptor>& l)
: elementCount(l.size()), elements(l.begin()) {} : elementCount(l.size()), elements(l.begin()) {}
@ -186,35 +147,16 @@ struct IShaderPipeline : IObj {};
struct IShaderDataBinding : IObj {}; struct IShaderDataBinding : IObj {};
/** Used wherever distinction of pipeline stages is needed */ /** Used wherever distinction of pipeline stages is needed */
enum class PipelineStage enum class PipelineStage { Null, Vertex, Fragment, Geometry, Control, Evaluation };
{
Null,
Vertex,
Fragment,
Geometry,
Control,
Evaluation
};
/** Used by platform shader pipeline constructors */ /** Used by platform shader pipeline constructors */
enum class Primitive enum class Primitive { Triangles, TriStrips, Patches };
{
Triangles,
TriStrips,
Patches
};
/** Used by platform shader pipeline constructors */ /** Used by platform shader pipeline constructors */
enum class CullMode enum class CullMode { None, Backface, Frontface };
{
None,
Backface,
Frontface
};
/** Used by platform shader pipeline constructors */ /** Used by platform shader pipeline constructors */
enum class ZTest enum class ZTest {
{
None, None,
LEqual, /* Flipped on Vulkan, D3D, Metal */ LEqual, /* Flipped on Vulkan, D3D, Metal */
Greater, Greater,
@ -223,8 +165,7 @@ enum class ZTest
}; };
/** Used by platform shader pipeline constructors */ /** Used by platform shader pipeline constructors */
enum class BlendFactor enum class BlendFactor {
{
Zero, Zero,
One, One,
SrcColor, SrcColor,
@ -243,8 +184,7 @@ enum class BlendFactor
}; };
/** Structure for passing additional pipeline construction information */ /** Structure for passing additional pipeline construction information */
struct AdditionalPipelineInfo struct AdditionalPipelineInfo {
{
BlendFactor srcFac = BlendFactor::One; BlendFactor srcFac = BlendFactor::One;
BlendFactor dstFac = BlendFactor::Zero; BlendFactor dstFac = BlendFactor::Zero;
Primitive prim = Primitive::TriStrips; Primitive prim = Primitive::TriStrips;
@ -259,92 +199,66 @@ struct AdditionalPipelineInfo
}; };
/** Factory object for creating batches of resources as an IGraphicsData token */ /** Factory object for creating batches of resources as an IGraphicsData token */
struct IGraphicsDataFactory struct IGraphicsDataFactory {
{
virtual ~IGraphicsDataFactory() = default; virtual ~IGraphicsDataFactory() = default;
enum class Platform enum class Platform { Null, OpenGL, D3D11, Metal, Vulkan, GX, NX };
{
Null,
OpenGL,
D3D11,
Metal,
Vulkan,
GX,
NX
};
virtual Platform platform() const = 0; virtual Platform platform() const = 0;
virtual const SystemChar* platformName() const = 0; virtual const SystemChar* platformName() const = 0;
struct Context struct Context {
{
virtual Platform platform() const = 0; virtual Platform platform() const = 0;
virtual const SystemChar* platformName() const = 0; virtual const SystemChar* platformName() const = 0;
virtual ObjToken<IGraphicsBufferS> virtual ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride,
newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count)=0; size_t count) = 0;
virtual ObjToken<IGraphicsBufferD> virtual ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count) = 0;
newDynamicBuffer(BufferUse use, size_t stride, size_t count)=0;
virtual ObjToken<ITextureS> virtual ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz) = 0; TextureClampMode clampMode, const void* data, size_t sz) = 0;
virtual ObjToken<ITextureSA> virtual ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, TextureFormat fmt, TextureClampMode clampMode, const void* data,
TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz)=0; size_t sz) = 0;
virtual ObjToken<ITextureD> virtual ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt,
newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode)=0; TextureClampMode clampMode) = 0;
virtual ObjToken<ITextureR> virtual ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindingCount, size_t depthBindingCount) = 0; size_t colorBindingCount, size_t depthBindingCount) = 0;
virtual ObjToken<IShaderStage> virtual ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage) = 0;
newShaderStage(const uint8_t* data, size_t size, PipelineStage stage)=0;
ObjToken<IShaderStage> ObjToken<IShaderStage> newShaderStage(const std::vector<uint8_t>& data, PipelineStage stage) {
newShaderStage(const std::vector<uint8_t>& data, PipelineStage stage)
{
return newShaderStage(data.data(), data.size(), stage); return newShaderStage(data.data(), data.size(), stage);
} }
virtual ObjToken<IShaderPipeline> virtual ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control, ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt, ObjToken<IShaderStage> evaluation,
const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo) = 0; const AdditionalPipelineInfo& additionalInfo) = 0;
ObjToken<IShaderPipeline> ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment, const VertexFormatInfo& vtxFmt,
const VertexFormatInfo& vtxFmt, const AdditionalPipelineInfo& additionalInfo) const AdditionalPipelineInfo& additionalInfo) {
{
return newShaderPipeline(vertex, fragment, {}, {}, {}, vtxFmt, additionalInfo); return newShaderPipeline(vertex, fragment, {}, {}, {}, vtxFmt, additionalInfo);
} }
virtual ObjToken<IShaderDataBinding> virtual ObjToken<IShaderDataBinding> newShaderDataBinding(
newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline, const ObjToken<IShaderPipeline>& pipeline, const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& vbo, const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>& ibo, size_t ubufCount,
const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs,
const ObjToken<IGraphicsBuffer>& ibo, const size_t* ubufSizes, size_t texCount, const ObjToken<ITexture>* texs, const int* texBindIdx,
size_t ubufCount, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const bool* depthBind, size_t baseVert = 0, size_t baseInst = 0) = 0;
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, const ObjToken<ITexture>* texs,
const int* texBindIdx, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0)=0;
ObjToken<IShaderDataBinding> ObjToken<IShaderDataBinding> newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline,
const ObjToken<IGraphicsBuffer>& vbo, const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>& instVbo,
const ObjToken<IGraphicsBuffer>& ibo, const ObjToken<IGraphicsBuffer>& ibo, size_t ubufCount,
size_t ubufCount, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const ObjToken<IGraphicsBuffer>* ubufs,
size_t texCount, const ObjToken<ITexture>* texs, const PipelineStage* ubufStages, size_t texCount,
const int* texBindIdx, const bool* depthBind, const ObjToken<ITexture>* texs, const int* texBindIdx,
size_t baseVert = 0, size_t baseInst = 0) const bool* depthBind, size_t baseVert = 0, size_t baseInst = 0) {
{ return newShaderDataBinding(pipeline, vbo, instVbo, ibo, ubufCount, ubufs, ubufStages, nullptr, nullptr, texCount,
return newShaderDataBinding(pipeline, vbo, instVbo, ibo, texs, texBindIdx, depthBind, baseVert, baseInst);
ubufCount, ubufs, ubufStages, nullptr,
nullptr, texCount, texs, texBindIdx, depthBind,
baseVert, baseInst);
} }
}; };
@ -357,5 +271,4 @@ struct IGraphicsDataFactory
using GraphicsDataFactoryContext = IGraphicsDataFactory::Context; using GraphicsDataFactoryContext = IGraphicsDataFactory::Context;
using FactoryCommitFunc = std::function<bool(GraphicsDataFactoryContext& ctx)>; using FactoryCommitFunc = std::function<bool(GraphicsDataFactoryContext& ctx)>;
} } // namespace boo

View File

@ -6,20 +6,18 @@
#include "IGraphicsCommandQueue.hpp" #include "IGraphicsCommandQueue.hpp"
#include "boo/IGraphicsContext.hpp" #include "boo/IGraphicsContext.hpp"
namespace boo namespace boo {
{
struct BaseGraphicsData; struct BaseGraphicsData;
class MetalDataFactory : public IGraphicsDataFactory class MetalDataFactory : public IGraphicsDataFactory {
{
public: public:
class Context final : public IGraphicsDataFactory::Context class Context final : public IGraphicsDataFactory::Context {
{
friend class MetalDataFactoryImpl; friend class MetalDataFactoryImpl;
MetalDataFactory& m_parent; MetalDataFactory& m_parent;
ObjToken<BaseGraphicsData> m_data; ObjToken<BaseGraphicsData> m_data;
Context(MetalDataFactory& parent __BooTraceArgs); Context(MetalDataFactory& parent __BooTraceArgs);
~Context(); ~Context();
public: public:
Platform platform() const { return Platform::Metal; } Platform platform() const { return Platform::Metal; }
const SystemChar* platformName() const { return _SYS_STR("Metal"); } const SystemChar* platformName() const { return _SYS_STR("Metal"); }
@ -32,10 +30,9 @@ public:
ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, const void* data, TextureFormat fmt, TextureClampMode clampMode, const void* data,
size_t sz); size_t sz);
ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt, ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode);
TextureClampMode clampMode); ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, size_t colorBindCount,
ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, size_t depthBindCount);
size_t colorBindCount, size_t depthBindCount);
ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage); ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
@ -44,22 +41,18 @@ public:
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt, ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo); const AdditionalPipelineInfo& additionalInfo);
ObjToken<IShaderDataBinding> ObjToken<IShaderDataBinding> newShaderDataBinding(
newShaderDataBinding(const ObjToken<IShaderPipeline>& pipeline, const ObjToken<IShaderPipeline>& pipeline, const ObjToken<IGraphicsBuffer>& vbo,
const ObjToken<IGraphicsBuffer>& vbo, const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>& ibo, size_t ubufCount,
const ObjToken<IGraphicsBuffer>& instVbo, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs,
const ObjToken<IGraphicsBuffer>& ibo, const size_t* ubufSizes, size_t texCount, const ObjToken<ITexture>* texs, const int* texBindIdxs,
size_t ubufCount, const ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const bool* depthBind, size_t baseVert = 0, size_t baseInst = 0);
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, const ObjToken<ITexture>* texs,
const int* texBindIdxs, const bool* depthBind,
size_t baseVert = 0, size_t baseInst = 0);
}; };
static std::vector<uint8_t> CompileMetal(const char* source, PipelineStage stage); static std::vector<uint8_t> CompileMetal(const char* source, PipelineStage stage);
}; };
} } // namespace boo
#endif #endif
#endif // __APPLE__ #endif // __APPLE__

View File

@ -12,12 +12,10 @@ struct pipe_context;
struct st_context; struct st_context;
struct pipe_surface; struct pipe_surface;
namespace boo namespace boo {
{
struct BaseGraphicsData; struct BaseGraphicsData;
struct NXContext struct NXContext {
{
struct pipe_surface* m_windowSurfaces[2]; struct pipe_surface* m_windowSurfaces[2];
NvFence m_fences[2]; NvFence m_fences[2];
bool m_fence_swap; bool m_fence_swap;
@ -40,16 +38,15 @@ struct NXContext
std::unordered_map<uint64_t, void*> m_vtxElemStates; std::unordered_map<uint64_t, void*> m_vtxElemStates;
}; };
class NXDataFactory : public IGraphicsDataFactory class NXDataFactory : public IGraphicsDataFactory {
{
public: public:
class Context final : public IGraphicsDataFactory::Context class Context final : public IGraphicsDataFactory::Context {
{
friend class NXDataFactoryImpl; friend class NXDataFactoryImpl;
NXDataFactory& m_parent; NXDataFactory& m_parent;
boo::ObjToken<BaseGraphicsData> m_data; boo::ObjToken<BaseGraphicsData> m_data;
Context(NXDataFactory& parent __BooTraceArgs); Context(NXDataFactory& parent __BooTraceArgs);
~Context(); ~Context();
public: public:
Platform platform() const { return Platform::NX; } Platform platform() const { return Platform::NX; }
const SystemChar* platformName() const { return _SYS_STR("NX"); } const SystemChar* platformName() const { return _SYS_STR("NX"); }
@ -60,34 +57,29 @@ public:
boo::ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, boo::ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz); TextureClampMode clampMode, const void* data, size_t sz);
boo::ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, boo::ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, TextureFormat fmt, TextureClampMode clampMode, const void* data,
const void* data, size_t sz); size_t sz);
boo::ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); boo::ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt,
TextureClampMode clampMode);
boo::ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, boo::ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindCount, size_t depthBindCount); size_t colorBindCount, size_t depthBindCount);
ObjToken<IShaderStage> ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
ObjToken<IShaderPipeline> ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control, ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt, ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo); const AdditionalPipelineInfo& additionalInfo);
boo::ObjToken<IShaderDataBinding> boo::ObjToken<IShaderDataBinding> newShaderDataBinding(
newShaderDataBinding(const boo::ObjToken<IShaderPipeline>& pipeline, const boo::ObjToken<IShaderPipeline>& pipeline, const boo::ObjToken<IGraphicsBuffer>& vbo,
const boo::ObjToken<IGraphicsBuffer>& vbo, const boo::ObjToken<IGraphicsBuffer>& instVbo, const boo::ObjToken<IGraphicsBuffer>& ibo, size_t ubufCount,
const boo::ObjToken<IGraphicsBuffer>& instVbo, const boo::ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs,
const boo::ObjToken<IGraphicsBuffer>& ibo, const size_t* ubufSizes, size_t texCount, const boo::ObjToken<ITexture>* texs, const int* bindIdxs,
size_t ubufCount, const boo::ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const bool* bindDepth, size_t baseVert = 0, size_t baseInst = 0);
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, const boo::ObjToken<ITexture>* texs,
const int* bindIdxs, const bool* bindDepth,
size_t baseVert = 0, size_t baseInst = 0);
}; };
}; };
} } // namespace boo
#endif #endif

View File

@ -15,14 +15,11 @@
/* Forward-declare handle type for Vulkan Memory Allocator */ /* Forward-declare handle type for Vulkan Memory Allocator */
struct VmaAllocator_T; struct VmaAllocator_T;
namespace boo namespace boo {
{
struct BaseGraphicsData; struct BaseGraphicsData;
struct VulkanContext struct VulkanContext {
{ struct LayerProperties {
struct LayerProperties
{
VkLayerProperties properties; VkLayerProperties properties;
std::vector<VkExtensionProperties> extensions; std::vector<VkExtensionProperties> extensions;
}; };
@ -52,14 +49,11 @@ struct VulkanContext
VkFormat m_displayFormat; VkFormat m_displayFormat;
VkFormat m_internalFormat; VkFormat m_internalFormat;
struct Window struct Window {
{ struct SwapChain {
struct SwapChain
{
VkFormat m_format = VK_FORMAT_UNDEFINED; VkFormat m_format = VK_FORMAT_UNDEFINED;
VkSwapchainKHR m_swapChain = VK_NULL_HANDLE; VkSwapchainKHR m_swapChain = VK_NULL_HANDLE;
struct Buffer struct Buffer {
{
VkImage m_image = VK_NULL_HANDLE; VkImage m_image = VK_NULL_HANDLE;
VkImageView m_colorView = VK_NULL_HANDLE; VkImageView m_colorView = VK_NULL_HANDLE;
VkFramebuffer m_framebuffer = VK_NULL_HANDLE; VkFramebuffer m_framebuffer = VK_NULL_HANDLE;
@ -69,13 +63,11 @@ struct VulkanContext
}; };
std::vector<Buffer> m_bufs; std::vector<Buffer> m_bufs;
uint32_t m_backBuf = 0; uint32_t m_backBuf = 0;
void destroy(VkDevice dev) void destroy(VkDevice dev) {
{
for (Buffer& buf : m_bufs) for (Buffer& buf : m_bufs)
buf.destroy(dev); buf.destroy(dev);
m_bufs.clear(); m_bufs.clear();
if (m_swapChain) if (m_swapChain) {
{
vk::DestroySwapchainKHR(dev, m_swapChain, nullptr); vk::DestroySwapchainKHR(dev, m_swapChain, nullptr);
m_swapChain = VK_NULL_HANDLE; m_swapChain = VK_NULL_HANDLE;
} }
@ -108,38 +100,33 @@ struct VulkanContext
void destroyDevice(); void destroyDevice();
void initSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace); void initSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace);
struct SwapChainResize struct SwapChainResize {
{
Window& m_windowCtx; Window& m_windowCtx;
VkSurfaceKHR m_surface; VkSurfaceKHR m_surface;
VkFormat m_format; VkFormat m_format;
VkColorSpaceKHR m_colorspace; VkColorSpaceKHR m_colorspace;
SWindowRect m_rect; SWindowRect m_rect;
SwapChainResize(Window& windowCtx, VkSurfaceKHR surface, SwapChainResize(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace,
VkFormat format, VkColorSpaceKHR colorspace,
const SWindowRect& rect) const SWindowRect& rect)
: m_windowCtx(windowCtx), m_surface(surface), : m_windowCtx(windowCtx), m_surface(surface), m_format(format), m_colorspace(colorspace), m_rect(rect) {}
m_format(format), m_colorspace(colorspace), m_rect(rect) {}
}; };
std::queue<SwapChainResize> m_deferredResizes; std::queue<SwapChainResize> m_deferredResizes;
std::mutex m_resizeLock; std::mutex m_resizeLock;
void resizeSwapChain(Window& windowCtx, VkSurfaceKHR surface, void resizeSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace,
VkFormat format, VkColorSpaceKHR colorspace,
const SWindowRect& rect); const SWindowRect& rect);
bool _resizeSwapChains(); bool _resizeSwapChains();
}; };
extern VulkanContext g_VulkanContext; extern VulkanContext g_VulkanContext;
class VulkanDataFactory : public IGraphicsDataFactory class VulkanDataFactory : public IGraphicsDataFactory {
{
public: public:
class Context final : public IGraphicsDataFactory::Context class Context final : public IGraphicsDataFactory::Context {
{
friend class VulkanDataFactoryImpl; friend class VulkanDataFactoryImpl;
VulkanDataFactory& m_parent; VulkanDataFactory& m_parent;
boo::ObjToken<BaseGraphicsData> m_data; boo::ObjToken<BaseGraphicsData> m_data;
Context(VulkanDataFactory& parent __BooTraceArgs); Context(VulkanDataFactory& parent __BooTraceArgs);
~Context(); ~Context();
public: public:
Platform platform() const { return Platform::Vulkan; } Platform platform() const { return Platform::Vulkan; }
const SystemChar* platformName() const { return _SYS_STR("Vulkan"); } const SystemChar* platformName() const { return _SYS_STR("Vulkan"); }
@ -150,36 +137,31 @@ public:
boo::ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt, boo::ObjToken<ITextureS> newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
TextureClampMode clampMode, const void* data, size_t sz); TextureClampMode clampMode, const void* data, size_t sz);
boo::ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips, boo::ObjToken<ITextureSA> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
TextureFormat fmt, TextureClampMode clampMode, TextureFormat fmt, TextureClampMode clampMode, const void* data,
const void* data, size_t sz); size_t sz);
boo::ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode); boo::ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt,
TextureClampMode clampMode);
boo::ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode, boo::ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
size_t colorBindCount, size_t depthBindCount); size_t colorBindCount, size_t depthBindCount);
ObjToken<IShaderStage> ObjToken<IShaderStage> newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
newShaderStage(const uint8_t* data, size_t size, PipelineStage stage);
ObjToken<IShaderPipeline> ObjToken<IShaderPipeline> newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
newShaderPipeline(ObjToken<IShaderStage> vertex, ObjToken<IShaderStage> fragment,
ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control, ObjToken<IShaderStage> geometry, ObjToken<IShaderStage> control,
ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt, ObjToken<IShaderStage> evaluation, const VertexFormatInfo& vtxFmt,
const AdditionalPipelineInfo& additionalInfo); const AdditionalPipelineInfo& additionalInfo);
boo::ObjToken<IShaderDataBinding> boo::ObjToken<IShaderDataBinding> newShaderDataBinding(
newShaderDataBinding(const boo::ObjToken<IShaderPipeline>& pipeline, const boo::ObjToken<IShaderPipeline>& pipeline, const boo::ObjToken<IGraphicsBuffer>& vbo,
const boo::ObjToken<IGraphicsBuffer>& vbo, const boo::ObjToken<IGraphicsBuffer>& instVbo, const boo::ObjToken<IGraphicsBuffer>& ibo, size_t ubufCount,
const boo::ObjToken<IGraphicsBuffer>& instVbo, const boo::ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const size_t* ubufOffs,
const boo::ObjToken<IGraphicsBuffer>& ibo, const size_t* ubufSizes, size_t texCount, const boo::ObjToken<ITexture>* texs, const int* bindIdxs,
size_t ubufCount, const boo::ObjToken<IGraphicsBuffer>* ubufs, const PipelineStage* ubufStages, const bool* bindDepth, size_t baseVert = 0, size_t baseInst = 0);
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, const boo::ObjToken<ITexture>* texs,
const int* bindIdxs, const bool* bindDepth,
size_t baseVert = 0, size_t baseInst = 0);
}; };
static std::vector<uint8_t> CompileGLSL(const char* source, PipelineStage stage); static std::vector<uint8_t> CompileGLSL(const char* source, PipelineStage stage);
}; };
} } // namespace boo
#endif #endif

View File

@ -214,4 +214,3 @@ void init_dispatch_table_middle(VkInstance instance, bool include_bottom);
void init_dispatch_table_bottom(VkInstance instance, VkDevice dev); void init_dispatch_table_bottom(VkInstance instance, VkDevice dev);
} // namespace vk } // namespace vk

View File

@ -3,8 +3,7 @@
#include <string> #include <string>
/* These match mesa's internal stages */ /* These match mesa's internal stages */
enum class nx_shader_stage enum class nx_shader_stage {
{
NONE = -1, NONE = -1,
VERTEX = 0, VERTEX = 0,
TESS_CTRL = 1, TESS_CTRL = 1,
@ -14,8 +13,7 @@ enum class nx_shader_stage
COMPUTE = 5, COMPUTE = 5,
}; };
struct standalone_options struct standalone_options {
{
int glsl_version; int glsl_version;
int dump_ast; int dump_ast;
int dump_hir; int dump_hir;
@ -26,12 +24,12 @@ struct standalone_options
}; };
class nx_compiler; class nx_compiler;
class nx_shader_stage_object class nx_shader_stage_object {
{
friend class nx_compiler; friend class nx_compiler;
nx_compiler* m_parent = nullptr; nx_compiler* m_parent = nullptr;
struct gl_shader* m_shader = nullptr; struct gl_shader* m_shader = nullptr;
nx_shader_stage_object(nx_compiler& parent) : m_parent(&parent) {} nx_shader_stage_object(nx_compiler& parent) : m_parent(&parent) {}
public: public:
nx_shader_stage_object() = default; nx_shader_stage_object() = default;
nx_shader_stage_object(const nx_shader_stage_object&); nx_shader_stage_object(const nx_shader_stage_object&);
@ -43,12 +41,12 @@ public:
const char* info_log() const; const char* info_log() const;
}; };
class nx_linked_shader class nx_linked_shader {
{
friend class nx_compiler; friend class nx_compiler;
nx_compiler* m_parent = nullptr; nx_compiler* m_parent = nullptr;
struct gl_shader_program* m_program = nullptr; struct gl_shader_program* m_program = nullptr;
nx_linked_shader(nx_compiler& parent) : m_parent(&parent) {} nx_linked_shader(nx_compiler& parent) : m_parent(&parent) {}
public: public:
nx_linked_shader() = default; nx_linked_shader() = default;
nx_linked_shader(const nx_linked_shader&); nx_linked_shader(const nx_linked_shader&);
@ -59,8 +57,7 @@ public:
const struct gl_shader_program* program() const { return m_program; } const struct gl_shader_program* program() const { return m_program; }
}; };
class nx_compiler class nx_compiler {
{
friend class nx_shader_stage_object; friend class nx_shader_stage_object;
friend class nx_linked_shader; friend class nx_linked_shader;
struct pipe_screen* m_screen = nullptr; struct pipe_screen* m_screen = nullptr;
@ -68,14 +65,14 @@ class nx_compiler
struct standalone_options m_options = {}; struct standalone_options m_options = {};
bool m_ownsCtx = false; bool m_ownsCtx = false;
void compile_shader(struct gl_context* ctx, struct gl_shader* shader); void compile_shader(struct gl_context* ctx, struct gl_shader* shader);
public: public:
nx_compiler(); nx_compiler();
~nx_compiler(); ~nx_compiler();
bool initialize(struct pipe_screen *screen, struct st_context *st, bool initialize(struct pipe_screen* screen, struct st_context* st, const struct standalone_options* o = nullptr);
const struct standalone_options *o = nullptr);
bool initialize(const struct standalone_options* o = nullptr); bool initialize(const struct standalone_options* o = nullptr);
nx_shader_stage_object compile(nx_shader_stage type, const char* source); nx_shader_stage_object compile(nx_shader_stage type, const char* source);
nx_linked_shader link(unsigned num_stages, const nx_shader_stage_object** stages, std::string* infoLog = nullptr); nx_linked_shader link(unsigned num_stages, const nx_shader_stage_object** stages, std::string* infoLog = nullptr);
std::pair<std::shared_ptr<uint8_t[]>, size_t> std::pair<std::shared_ptr<uint8_t[]>, size_t> offline_link(unsigned num_stages, const nx_shader_stage_object** stages,
offline_link(unsigned num_stages, const nx_shader_stage_object **stages, std::string* infoLog = nullptr); std::string* infoLog = nullptr);
}; };

View File

@ -1,7 +1,3 @@
#pragma once #pragma once
namespace boo namespace boo {}
{
}

View File

@ -13,20 +13,13 @@
#include <hidsdi.h> #include <hidsdi.h>
#endif #endif
namespace boo namespace boo {
{
class DeviceToken; class DeviceToken;
class IHIDDevice; class IHIDDevice;
enum class HIDReportType enum class HIDReportType { Input, Output, Feature };
{
Input,
Output,
Feature
};
class DeviceBase : public std::enable_shared_from_this<DeviceBase> class DeviceBase : public std::enable_shared_from_this<DeviceBase> {
{
friend class DeviceToken; friend class DeviceToken;
friend struct DeviceSignature; friend struct DeviceSignature;
friend class HIDDeviceIOKit; friend class HIDDeviceIOKit;
@ -69,24 +62,24 @@ public:
std::vector<uint8_t> getReportDescriptor(); std::vector<uint8_t> getReportDescriptor();
#endif #endif
bool sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message = 0); bool sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message = 0);
size_t receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message=0); // Prefer callback version size_t receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp,
virtual void receivedHIDReport(const uint8_t* /*data*/, size_t /*length*/, HIDReportType /*tp*/, uint32_t /*message*/) {} uint32_t message = 0); // Prefer callback version
virtual void receivedHIDReport(const uint8_t* /*data*/, size_t /*length*/, HIDReportType /*tp*/,
uint32_t /*message*/) {}
}; };
template <class CB> template <class CB>
class TDeviceBase : public DeviceBase class TDeviceBase : public DeviceBase {
{
protected: protected:
std::mutex m_callbackLock; std::mutex m_callbackLock;
CB* m_callback = nullptr; CB* m_callback = nullptr;
public: public:
TDeviceBase(uint64_t typeHash, DeviceToken* token) : DeviceBase(typeHash, token) {} TDeviceBase(uint64_t typeHash, DeviceToken* token) : DeviceBase(typeHash, token) {}
void setCallback(CB* cb) void setCallback(CB* cb) {
{
std::lock_guard<std::mutex> lk(m_callbackLock); std::lock_guard<std::mutex> lk(m_callbackLock);
m_callback = cb; m_callback = cb;
} }
}; };
} } // namespace boo

View File

@ -16,11 +16,9 @@
#include <windows.h> #include <windows.h>
#endif #endif
namespace boo namespace boo {
{
class DeviceFinder class DeviceFinder {
{
public: public:
friend class HIDListenerIOKit; friend class HIDListenerIOKit;
friend class HIDListenerUdev; friend class HIDListenerUdev;
@ -43,31 +41,25 @@ private:
/* Friend methods for platform-listener to find/insert/remove /* Friend methods for platform-listener to find/insert/remove
* tokens with type-filtering */ * tokens with type-filtering */
inline bool _hasToken(const std::string& path) inline bool _hasToken(const std::string& path) {
{
auto preCheck = m_tokens.find(path); auto preCheck = m_tokens.find(path);
if (preCheck != m_tokens.end()) if (preCheck != m_tokens.end())
return true; return true;
return false; return false;
} }
inline bool _insertToken(std::unique_ptr<DeviceToken>&& token) inline bool _insertToken(std::unique_ptr<DeviceToken>&& token) {
{ if (DeviceSignature::DeviceMatchToken(*token, m_types)) {
if (DeviceSignature::DeviceMatchToken(*token, m_types))
{
m_tokensLock.lock(); m_tokensLock.lock();
TInsertedDeviceToken inseredTok = TInsertedDeviceToken inseredTok = m_tokens.insert(std::make_pair(token->getDevicePath(), std::move(token)));
m_tokens.insert(std::make_pair(token->getDevicePath(), std::move(token)));
m_tokensLock.unlock(); m_tokensLock.unlock();
deviceConnected(*inseredTok.first->second); deviceConnected(*inseredTok.first->second);
return true; return true;
} }
return false; return false;
} }
inline void _removeToken(const std::string& path) inline void _removeToken(const std::string& path) {
{
auto preCheck = m_tokens.find(path); auto preCheck = m_tokens.find(path);
if (preCheck != m_tokens.end()) if (preCheck != m_tokens.end()) {
{
DeviceToken& tok = *preCheck->second; DeviceToken& tok = *preCheck->second;
std::shared_ptr<DeviceBase> dev = tok.m_connectedDev; std::shared_ptr<DeviceBase> dev = tok.m_connectedDev;
tok._deviceClose(); tok._deviceClose();
@ -79,40 +71,33 @@ private:
} }
public: public:
class CDeviceTokensHandle {
class CDeviceTokensHandle
{
DeviceFinder& m_finder; DeviceFinder& m_finder;
public: public:
inline CDeviceTokensHandle(DeviceFinder& finder) : m_finder(finder) inline CDeviceTokensHandle(DeviceFinder& finder) : m_finder(finder) { m_finder.m_tokensLock.lock(); }
{m_finder.m_tokensLock.lock();}
inline ~CDeviceTokensHandle() { m_finder.m_tokensLock.unlock(); } inline ~CDeviceTokensHandle() { m_finder.m_tokensLock.unlock(); }
inline TDeviceTokens::iterator begin() { return m_finder.m_tokens.begin(); } inline TDeviceTokens::iterator begin() { return m_finder.m_tokens.begin(); }
inline TDeviceTokens::iterator end() { return m_finder.m_tokens.end(); } inline TDeviceTokens::iterator end() { return m_finder.m_tokens.end(); }
}; };
/* Application must specify its interested device-types */ /* Application must specify its interested device-types */
DeviceFinder(std::unordered_set<uint64_t> types) DeviceFinder(std::unordered_set<uint64_t> types) {
{ if (skDevFinder) {
if (skDevFinder)
{
fprintf(stderr, "only one instance of CDeviceFinder may be constructed"); fprintf(stderr, "only one instance of CDeviceFinder may be constructed");
abort(); abort();
} }
skDevFinder = this; skDevFinder = this;
for (const uint64_t& typeHash : types) for (const uint64_t& typeHash : types) {
{
const DeviceSignature* sigIter = BOO_DEVICE_SIGS; const DeviceSignature* sigIter = BOO_DEVICE_SIGS;
while (sigIter->m_name) while (sigIter->m_name) {
{
if (sigIter->m_typeHash == typeHash) if (sigIter->m_typeHash == typeHash)
m_types.push_back(sigIter); m_types.push_back(sigIter);
++sigIter; ++sigIter;
} }
} }
} }
virtual ~DeviceFinder() virtual ~DeviceFinder() {
{
if (m_listener) if (m_listener)
m_listener->stopScanning(); m_listener->stopScanning();
skDevFinder = NULL; skDevFinder = NULL;
@ -125,16 +110,14 @@ public:
inline CDeviceTokensHandle getTokens() { return CDeviceTokensHandle(*this); } inline CDeviceTokensHandle getTokens() { return CDeviceTokensHandle(*this); }
/* Automatic device scanning */ /* Automatic device scanning */
inline bool startScanning() inline bool startScanning() {
{
if (!m_listener) if (!m_listener)
m_listener = IHIDListenerNew(*this); m_listener = IHIDListenerNew(*this);
if (m_listener) if (m_listener)
return m_listener->startScanning(); return m_listener->startScanning();
return false; return false;
} }
inline bool stopScanning() inline bool stopScanning() {
{
if (!m_listener) if (!m_listener)
m_listener = IHIDListenerNew(*this); m_listener = IHIDListenerNew(*this);
if (m_listener) if (m_listener)
@ -143,8 +126,7 @@ public:
} }
/* Manual device scanning */ /* Manual device scanning */
inline bool scanNow() inline bool scanNow() {
{
if (!m_listener) if (!m_listener)
m_listener = IHIDListenerNew(*this); m_listener = IHIDListenerNew(*this);
if (m_listener) if (m_listener)
@ -159,8 +141,6 @@ public:
/* Windows-specific WM_DEVICECHANGED handler */ /* Windows-specific WM_DEVICECHANGED handler */
static LRESULT winDevChangedHandler(WPARAM wParam, LPARAM lParam); static LRESULT winDevChangedHandler(WPARAM wParam, LPARAM lParam);
#endif #endif
}; };
} } // namespace boo

View File

@ -6,25 +6,16 @@
#include <memory> #include <memory>
#include <string> #include <string>
namespace boo namespace boo {
{
enum class DeviceType enum class DeviceType { None = 0, USB = 1, Bluetooth = 2, HID = 3, XInput = 4 };
{
None = 0,
USB = 1,
Bluetooth = 2,
HID = 3,
XInput = 4
};
class DeviceToken; class DeviceToken;
class DeviceBase; class DeviceBase;
#define dev_typeid(type) std::hash<std::string>()(#type) #define dev_typeid(type) std::hash<std::string>()(#type)
struct DeviceSignature struct DeviceSignature {
{
typedef std::vector<const DeviceSignature*> TDeviceSignatureSet; typedef std::vector<const DeviceSignature*> TDeviceSignatureSet;
typedef std::function<std::shared_ptr<DeviceBase>(DeviceToken*)> TFactoryLambda; typedef std::function<std::shared_ptr<DeviceBase>(DeviceToken*)> TFactoryLambda;
const char* m_name; const char* m_name;
@ -33,10 +24,9 @@ struct DeviceSignature
TFactoryLambda m_factory; TFactoryLambda m_factory;
DeviceType m_type; DeviceType m_type;
DeviceSignature() : m_name(NULL), m_typeHash(dev_typeid(DeviceSignature)) {} /* Sentinel constructor */ DeviceSignature() : m_name(NULL), m_typeHash(dev_typeid(DeviceSignature)) {} /* Sentinel constructor */
DeviceSignature(const char* name, uint64_t typeHash, unsigned vid, unsigned pid, DeviceSignature(const char* name, uint64_t typeHash, unsigned vid, unsigned pid, TFactoryLambda&& factory,
TFactoryLambda&& factory, DeviceType type=DeviceType::None) DeviceType type = DeviceType::None)
: m_name(name), m_typeHash(typeHash), m_vid(vid), m_pid(pid), : m_name(name), m_typeHash(typeHash), m_vid(vid), m_pid(pid), m_factory(factory), m_type(type) {}
m_factory(factory), m_type(type) {}
static bool DeviceMatchToken(const DeviceToken& token, const TDeviceSignatureSet& sigSet); static bool DeviceMatchToken(const DeviceToken& token, const TDeviceSignatureSet& sigSet);
static std::shared_ptr<DeviceBase> DeviceNew(DeviceToken& token); static std::shared_ptr<DeviceBase> DeviceNew(DeviceToken& token);
}; };
@ -48,6 +38,4 @@ struct DeviceSignature
extern const DeviceSignature BOO_DEVICE_SIGS[]; extern const DeviceSignature BOO_DEVICE_SIGS[];
} } // namespace boo

View File

@ -4,11 +4,9 @@
#include "DeviceBase.hpp" #include "DeviceBase.hpp"
#include "DeviceSignature.hpp" #include "DeviceSignature.hpp"
namespace boo namespace boo {
{
class DeviceToken class DeviceToken {
{
friend struct DeviceSignature; friend struct DeviceSignature;
friend class HIDListenerWinUSB; friend class HIDListenerWinUSB;
DeviceType m_devType; DeviceType m_devType;
@ -22,32 +20,25 @@ class DeviceToken
std::shared_ptr<DeviceBase> m_connectedDev; std::shared_ptr<DeviceBase> m_connectedDev;
friend class DeviceFinder; friend class DeviceFinder;
inline void _deviceClose() inline void _deviceClose() {
{
if (m_connectedDev) if (m_connectedDev)
m_connectedDev->_deviceDisconnected(); m_connectedDev->_deviceDisconnected();
m_connectedDev = NULL; m_connectedDev = NULL;
} }
public: public:
DeviceToken(const DeviceToken&) = delete; DeviceToken(const DeviceToken&) = delete;
DeviceToken(const DeviceToken&& other) DeviceToken(const DeviceToken&& other)
: m_devType(other.m_devType), : m_devType(other.m_devType)
m_vendorId(other.m_vendorId), , m_vendorId(other.m_vendorId)
m_productId(other.m_productId), , m_productId(other.m_productId)
m_vendorName(other.m_vendorName), , m_vendorName(other.m_vendorName)
m_productName(other.m_productName), , m_productName(other.m_productName)
m_devPath(other.m_devPath), , m_devPath(other.m_devPath)
m_connectedDev(other.m_connectedDev) , m_connectedDev(other.m_connectedDev) {}
{} inline DeviceToken(DeviceType devType, unsigned vid, unsigned pid, const char* vname, const char* pname,
inline DeviceToken(DeviceType devType, unsigned vid, unsigned pid, const char* vname, const char* pname, const char* path) const char* path)
: m_devType(devType), : m_devType(devType), m_vendorId(vid), m_productId(pid), m_devPath(path), m_connectedDev(NULL) {
m_vendorId(vid),
m_productId(pid),
m_devPath(path),
m_connectedDev(NULL)
{
if (vname) if (vname)
m_vendorName = vname; m_vendorName = vname;
if (pname) if (pname)
@ -61,18 +52,14 @@ public:
inline std::string_view getProductName() const { return m_productName; } inline std::string_view getProductName() const { return m_productName; }
inline std::string_view getDevicePath() const { return m_devPath; } inline std::string_view getDevicePath() const { return m_devPath; }
inline bool isDeviceOpen() const { return (m_connectedDev != NULL); } inline bool isDeviceOpen() const { return (m_connectedDev != NULL); }
inline std::shared_ptr<DeviceBase> openAndGetDevice() inline std::shared_ptr<DeviceBase> openAndGetDevice() {
{
if (!m_connectedDev) if (!m_connectedDev)
m_connectedDev = DeviceSignature::DeviceNew(*this); m_connectedDev = DeviceSignature::DeviceNew(*this);
return m_connectedDev; return m_connectedDev;
} }
inline bool operator ==(const DeviceToken& rhs) const inline bool operator==(const DeviceToken& rhs) const { return m_devPath == rhs.m_devPath; }
{return m_devPath == rhs.m_devPath;} inline bool operator<(const DeviceToken& rhs) const { return m_devPath < rhs.m_devPath; }
inline bool operator <(const DeviceToken& rhs) const
{return m_devPath < rhs.m_devPath;}
}; };
} } // namespace boo

View File

@ -4,19 +4,16 @@
#include "DeviceBase.hpp" #include "DeviceBase.hpp"
#include "../System.hpp" #include "../System.hpp"
namespace boo namespace boo {
{
enum class EDolphinControllerType enum class EDolphinControllerType {
{
None = 0, None = 0,
Normal = 0x10, Normal = 0x10,
Wavebird = 0x20, Wavebird = 0x20,
}; };
ENABLE_BITWISE_ENUM(EDolphinControllerType) ENABLE_BITWISE_ENUM(EDolphinControllerType)
enum class EDolphinControllerButtons enum class EDolphinControllerButtons {
{
Start = 1 << 0, Start = 1 << 0,
Z = 1 << 1, Z = 1 << 1,
R = 1 << 2, R = 1 << 2,
@ -32,14 +29,12 @@ enum class EDolphinControllerButtons
}; };
ENABLE_BITWISE_ENUM(EDolphinControllerButtons) ENABLE_BITWISE_ENUM(EDolphinControllerButtons)
struct DolphinControllerState struct DolphinControllerState {
{
int16_t m_leftStick[2] = {0}; int16_t m_leftStick[2] = {0};
int16_t m_rightStick[2] = {0}; int16_t m_rightStick[2] = {0};
int16_t m_analogTriggers[2] = {0}; int16_t m_analogTriggers[2] = {0};
uint16_t m_btns = 0; uint16_t m_btns = 0;
void reset() void reset() {
{
m_leftStick[0] = 0; m_leftStick[0] = 0;
m_leftStick[1] = 0; m_leftStick[1] = 0;
m_rightStick[0] = 0; m_rightStick[0] = 0;
@ -51,16 +46,20 @@ struct DolphinControllerState
void clamp(); void clamp();
}; };
struct IDolphinSmashAdapterCallback struct IDolphinSmashAdapterCallback {
{ virtual void controllerConnected(unsigned idx, EDolphinControllerType type) {
virtual void controllerConnected(unsigned idx, EDolphinControllerType type) {(void)idx;(void)type;} (void)idx;
(void)type;
}
virtual void controllerDisconnected(unsigned idx) { (void)idx; } virtual void controllerDisconnected(unsigned idx) { (void)idx; }
virtual void controllerUpdate(unsigned idx, EDolphinControllerType type, virtual void controllerUpdate(unsigned idx, EDolphinControllerType type, const DolphinControllerState& state) {
const DolphinControllerState& state) {(void)idx;(void)type;(void)state;} (void)idx;
(void)type;
(void)state;
}
}; };
class DolphinSmashAdapter final : public TDeviceBase<IDolphinSmashAdapterCallback> class DolphinSmashAdapter final : public TDeviceBase<IDolphinSmashAdapterCallback> {
{
int16_t m_leftStickCal[2] = {0x7f}; int16_t m_leftStickCal[2] = {0x7f};
int16_t m_rightStickCal[2] = {0x7f}; int16_t m_rightStickCal[2] = {0x7f};
int16_t m_triggersCal[2] = {0x0}; int16_t m_triggersCal[2] = {0x0};
@ -72,20 +71,26 @@ class DolphinSmashAdapter final : public TDeviceBase<IDolphinSmashAdapterCallbac
void initialCycle(); void initialCycle();
void transferCycle(); void transferCycle();
void finalCycle(); void finalCycle();
public: public:
DolphinSmashAdapter(DeviceToken* token); DolphinSmashAdapter(DeviceToken* token);
~DolphinSmashAdapter(); ~DolphinSmashAdapter();
void setCallback(IDolphinSmashAdapterCallback* cb) void setCallback(IDolphinSmashAdapterCallback* cb) {
{
TDeviceBase<IDolphinSmashAdapterCallback>::setCallback(cb); TDeviceBase<IDolphinSmashAdapterCallback>::setCallback(cb);
m_knownControllers = 0; m_knownControllers = 0;
} }
void startRumble(unsigned idx) void startRumble(unsigned idx) {
{if (idx >= 4) return; m_rumbleRequest |= 1<<idx;} if (idx >= 4)
void stopRumble(unsigned idx, bool hard=false) return;
{if (idx >= 4) return; m_rumbleRequest &= ~(1<<idx); m_hardStop[idx] = hard;} m_rumbleRequest |= 1 << idx;
}
void stopRumble(unsigned idx, bool hard = false) {
if (idx >= 4)
return;
m_rumbleRequest &= ~(1 << idx);
m_hardStop[idx] = hard;
}
}; };
} } // namespace boo

View File

@ -4,11 +4,9 @@
#include "DeviceBase.hpp" #include "DeviceBase.hpp"
#include "boo/System.hpp" #include "boo/System.hpp"
namespace boo namespace boo {
{
struct DualshockLED struct DualshockLED {
{
uint8_t timeEnabled; uint8_t timeEnabled;
uint8_t dutyLength; uint8_t dutyLength;
uint8_t enabled; uint8_t enabled;
@ -16,8 +14,7 @@ struct DualshockLED
uint8_t dutyOn; uint8_t dutyOn;
}; };
struct DualshockRumble struct DualshockRumble {
{
uint8_t padding; uint8_t padding;
uint8_t rightDuration; uint8_t rightDuration;
bool rightOn; bool rightOn;
@ -25,10 +22,8 @@ struct DualshockRumble
uint8_t leftForce; uint8_t leftForce;
}; };
union DualshockOutReport union DualshockOutReport {
{ struct {
struct
{
uint8_t reportId; uint8_t reportId;
DualshockRumble rumble; DualshockRumble rumble;
uint8_t gyro1; uint8_t gyro1;
@ -41,8 +36,7 @@ union DualshockOutReport
uint8_t buf[49]; uint8_t buf[49];
}; };
enum class EDualshockPadButtons enum class EDualshockPadButtons {
{
Select = 1 << 0, Select = 1 << 0,
L3 = 1 << 1, L3 = 1 << 1,
R3 = 1 << 2, R3 = 1 << 2,
@ -61,26 +55,17 @@ enum class EDualshockPadButtons
Square = 1 << 15 Square = 1 << 15
}; };
enum class EDualshockMotor : uint8_t enum class EDualshockMotor : uint8_t {
{
None = 0, None = 0,
Right = 1 << 0, Right = 1 << 0,
Left = 1 << 1, Left = 1 << 1,
}; };
ENABLE_BITWISE_ENUM(EDualshockMotor) ENABLE_BITWISE_ENUM(EDualshockMotor)
enum class EDualshockLED enum class EDualshockLED { LED_OFF = 0, LED_1 = 1 << 1, LED_2 = 1 << 2, LED_3 = 1 << 3, LED_4 = 1 << 4 };
{
LED_OFF = 0,
LED_1 = 1<<1,
LED_2 = 1<<2,
LED_3 = 1<<3,
LED_4 = 1<<4
};
ENABLE_BITWISE_ENUM(EDualshockLED) ENABLE_BITWISE_ENUM(EDualshockLED)
struct DualshockPadState struct DualshockPadState {
{
uint8_t m_reportType; uint8_t m_reportType;
uint8_t m_reserved1; uint8_t m_reserved1;
uint16_t m_buttonState; uint16_t m_buttonState;
@ -115,14 +100,12 @@ struct DualshockPadState
}; };
class DualshockPad; class DualshockPad;
struct IDualshockPadCallback struct IDualshockPadCallback {
{
virtual void controllerDisconnected() {} virtual void controllerDisconnected() {}
virtual void controllerUpdate(DualshockPad&, const DualshockPadState&) {} virtual void controllerUpdate(DualshockPad&, const DualshockPadState&) {}
}; };
class DualshockPad final : public TDeviceBase<IDualshockPadCallback> class DualshockPad final : public TDeviceBase<IDualshockPadCallback> {
{
EDualshockMotor m_rumbleRequest; EDualshockMotor m_rumbleRequest;
EDualshockMotor m_rumbleState; EDualshockMotor m_rumbleState;
uint8_t m_rumbleDuration[2]; uint8_t m_rumbleDuration[2];
@ -134,37 +117,28 @@ class DualshockPad final : public TDeviceBase<IDualshockPadCallback>
void transferCycle(); void transferCycle();
void finalCycle(); void finalCycle();
void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message); void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message);
public: public:
DualshockPad(DeviceToken* token); DualshockPad(DeviceToken* token);
~DualshockPad(); ~DualshockPad();
void startRumble(EDualshockMotor motor, uint8_t duration = 254, uint8_t intensity=255) void startRumble(EDualshockMotor motor, uint8_t duration = 254, uint8_t intensity = 255) {
{
m_rumbleRequest |= motor; m_rumbleRequest |= motor;
if ((EDualshockMotor(motor) & EDualshockMotor::Left) != EDualshockMotor::None) if ((EDualshockMotor(motor) & EDualshockMotor::Left) != EDualshockMotor::None) {
{
m_rumbleDuration[0] = duration; m_rumbleDuration[0] = duration;
m_rumbleIntensity[0] = intensity; m_rumbleIntensity[0] = intensity;
} }
if ((EDualshockMotor(motor) & EDualshockMotor::Right) != EDualshockMotor::None) if ((EDualshockMotor(motor) & EDualshockMotor::Right) != EDualshockMotor::None) {
{
m_rumbleDuration[1] = duration; m_rumbleDuration[1] = duration;
m_rumbleIntensity[1] = intensity; m_rumbleIntensity[1] = intensity;
} }
} }
void stopRumble(int motor) void stopRumble(int motor) { m_rumbleRequest &= ~EDualshockMotor(motor); }
{
m_rumbleRequest &= ~EDualshockMotor(motor);
}
EDualshockLED getLED() EDualshockLED getLED() { return m_led; }
{
return m_led;
}
void setLED(EDualshockLED led, bool on = true) void setLED(EDualshockLED led, bool on = true) {
{
if (on) if (on)
m_led |= led; m_led |= led;
else else
@ -173,12 +147,10 @@ public:
setRawLED(int(led)); setRawLED(int(led));
} }
void setRawLED(int led) void setRawLED(int led) {
{
m_report.leds = led; m_report.leds = led;
sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01); sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01);
} }
}; };
} } // namespace boo

View File

@ -5,19 +5,17 @@
#include <map> #include <map>
#include <mutex> #include <mutex>
namespace boo namespace boo {
{
struct IGenericPadCallback struct IGenericPadCallback {
{
virtual void controllerConnected() {} virtual void controllerConnected() {}
virtual void controllerDisconnected() {} virtual void controllerDisconnected() {}
virtual void valueUpdate(const HIDMainItem& item, int32_t value) {} virtual void valueUpdate(const HIDMainItem& item, int32_t value) {}
}; };
class GenericPad final : public TDeviceBase<IGenericPadCallback> class GenericPad final : public TDeviceBase<IGenericPadCallback> {
{
HIDParser m_parser; HIDParser m_parser;
public: public:
GenericPad(DeviceToken* token); GenericPad(DeviceToken* token);
~GenericPad(); ~GenericPad();
@ -29,5 +27,4 @@ public:
void enumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const; void enumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const;
}; };
} } // namespace boo

View File

@ -10,14 +10,12 @@
#include <hidsdi.h> #include <hidsdi.h>
#endif #endif
namespace boo namespace boo {
{
struct HIDItemState; struct HIDItemState;
struct HIDCollectionItem; struct HIDCollectionItem;
struct HIDReports; struct HIDReports;
enum class HIDUsagePage : uint8_t enum class HIDUsagePage : uint8_t {
{
Undefined = 0, Undefined = 0,
GenericDesktop = 1, GenericDesktop = 1,
Simulation = 2, Simulation = 2,
@ -34,8 +32,7 @@ enum class HIDUsagePage : uint8_t
Digitizer = 13 Digitizer = 13
}; };
enum class HIDUsage : uint8_t enum class HIDUsage : uint8_t {
{
Undefined = 0, Undefined = 0,
/* Generic Desktop */ /* Generic Desktop */
@ -142,8 +139,7 @@ enum class HIDUsage : uint8_t
using HIDRange = std::pair<int32_t, int32_t>; using HIDRange = std::pair<int32_t, int32_t>;
/* [6.2.2.5] Input, Output, and Feature Items */ /* [6.2.2.5] Input, Output, and Feature Items */
struct HIDMainItem struct HIDMainItem {
{
uint16_t m_flags; uint16_t m_flags;
HIDUsagePage m_usagePage; HIDUsagePage m_usagePage;
HIDUsage m_usage; HIDUsage m_usage;
@ -161,23 +157,16 @@ struct HIDMainItem
HIDMainItem() = default; HIDMainItem() = default;
HIDMainItem(uint32_t flags, const HIDItemState& state, uint32_t reportIdx); HIDMainItem(uint32_t flags, const HIDItemState& state, uint32_t reportIdx);
HIDMainItem(uint32_t flags, HIDUsagePage usagePage, HIDUsage usage, HIDMainItem(uint32_t flags, HIDUsagePage usagePage, HIDUsage usage, HIDRange logicalRange, int32_t reportSize);
HIDRange logicalRange, int32_t reportSize);
const char* GetUsagePageName() const; const char* GetUsagePageName() const;
const char* GetUsageName() const; const char* GetUsageName() const;
}; };
class HIDParser class HIDParser {
{
public: public:
enum class ParserStatus enum class ParserStatus { OK, Done, Error };
{
OK,
Done,
Error
};
private:
private:
ParserStatus m_status = ParserStatus::OK; ParserStatus m_status = ParserStatus::OK;
#if _WIN32 #if _WIN32
#if !WINDOWS_STORE #if !WINDOWS_STORE
@ -193,10 +182,8 @@ private:
std::pair<uint32_t, uint32_t> m_outputReports = {}; std::pair<uint32_t, uint32_t> m_outputReports = {};
std::pair<uint32_t, uint32_t> m_featureReports = {}; std::pair<uint32_t, uint32_t> m_featureReports = {};
bool m_multipleReports = false; bool m_multipleReports = false;
static ParserStatus ParseItem(HIDReports& reportsOut, static ParserStatus ParseItem(HIDReports& reportsOut, std::stack<HIDItemState>& stateStack,
std::stack<HIDItemState>& stateStack, std::stack<HIDCollectionItem>& collectionStack, const uint8_t*& it, const uint8_t* end,
std::stack<HIDCollectionItem>& collectionStack,
const uint8_t*& it, const uint8_t* end,
bool& multipleReports); bool& multipleReports);
#endif #endif
@ -212,9 +199,8 @@ public:
#endif #endif
operator bool() const { return m_status == ParserStatus::Done; } operator bool() const { return m_status == ParserStatus::Done; }
void EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const; void EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const;
void ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB, void ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB, const uint8_t* data,
const uint8_t* data, size_t len) const; size_t len) const;
}; };
} } // namespace boo

View File

@ -4,15 +4,13 @@
#include <mutex> #include <mutex>
#include "DeviceToken.hpp" #include "DeviceToken.hpp"
namespace boo namespace boo {
{
typedef std::unordered_map<std::string, std::unique_ptr<DeviceToken>> TDeviceTokens; typedef std::unordered_map<std::string, std::unique_ptr<DeviceToken>> TDeviceTokens;
typedef std::pair<TDeviceTokens::iterator, bool> TInsertedDeviceToken; typedef std::pair<TDeviceTokens::iterator, bool> TInsertedDeviceToken;
class DeviceFinder; class DeviceFinder;
class IHIDListener class IHIDListener {
{
public: public:
virtual ~IHIDListener() = default; virtual ~IHIDListener() = default;
@ -28,11 +26,9 @@ public:
virtual bool _extDevConnect(const char* path) = 0; virtual bool _extDevConnect(const char* path) = 0;
virtual bool _extDevDisconnect(const char* path) = 0; virtual bool _extDevDisconnect(const char* path) = 0;
#endif #endif
}; };
/* Platform-specific constructor */ /* Platform-specific constructor */
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder); std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder);
} } // namespace boo

View File

@ -2,10 +2,8 @@
#include "DeviceBase.hpp" #include "DeviceBase.hpp"
#include "boo/System.hpp" #include "boo/System.hpp"
namespace boo namespace boo {
{ struct NintendoPowerAState {
struct NintendoPowerAState
{
uint8_t y : 1; uint8_t y : 1;
uint8_t b : 1; uint8_t b : 1;
uint8_t a : 1; uint8_t a : 1;
@ -30,23 +28,21 @@ struct NintendoPowerAState
}; };
class NintendoPowerA; class NintendoPowerA;
struct INintendoPowerACallback struct INintendoPowerACallback {
{
virtual void controllerDisconnected() {} virtual void controllerDisconnected() {}
virtual void controllerUpdate(const NintendoPowerAState& state) {} virtual void controllerUpdate(const NintendoPowerAState& state) {}
}; };
class NintendoPowerA final : public TDeviceBase<INintendoPowerACallback> class NintendoPowerA final : public TDeviceBase<INintendoPowerACallback> {
{
NintendoPowerAState m_last; NintendoPowerAState m_last;
void deviceDisconnected(); void deviceDisconnected();
void initialCycle(); void initialCycle();
void transferCycle(); void transferCycle();
void finalCycle(); void finalCycle();
void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message); void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message);
public: public:
NintendoPowerA(DeviceToken*); NintendoPowerA(DeviceToken*);
~NintendoPowerA(); ~NintendoPowerA();
}; };
} } // namespace boo

View File

@ -1,7 +1,3 @@
#pragma once #pragma once
namespace boo namespace boo {}
{
}

View File

@ -4,11 +4,9 @@
#include "DeviceSignature.hpp" #include "DeviceSignature.hpp"
#include "boo/System.hpp" #include "boo/System.hpp"
namespace boo namespace boo {
{
struct XInputPadState struct XInputPadState {
{
uint16_t wButtons; uint16_t wButtons;
uint8_t bLeftTrigger; uint8_t bLeftTrigger;
uint8_t bRightTrigger; uint8_t bRightTrigger;
@ -18,8 +16,7 @@ struct XInputPadState
int16_t sThumbRY; int16_t sThumbRY;
}; };
enum class EXInputMotor : uint8_t enum class EXInputMotor : uint8_t {
{
None = 0, None = 0,
Right = 1 << 0, Right = 1 << 0,
Left = 1 << 1, Left = 1 << 1,
@ -27,34 +24,30 @@ enum class EXInputMotor : uint8_t
ENABLE_BITWISE_ENUM(EXInputMotor) ENABLE_BITWISE_ENUM(EXInputMotor)
class XInputPad; class XInputPad;
struct IXInputPadCallback struct IXInputPadCallback {
{
virtual void controllerDisconnected() {} virtual void controllerDisconnected() {}
virtual void controllerUpdate(XInputPad& pad, const XInputPadState&) {} virtual void controllerUpdate(XInputPad& pad, const XInputPadState&) {}
}; };
class XInputPad final : public TDeviceBase<IXInputPadCallback> class XInputPad final : public TDeviceBase<IXInputPadCallback> {
{
friend class HIDListenerWinUSB; friend class HIDListenerWinUSB;
uint16_t m_rumbleRequest[2] = {}; uint16_t m_rumbleRequest[2] = {};
uint16_t m_rumbleState[2] = {}; uint16_t m_rumbleState[2] = {};
public: public:
XInputPad(DeviceToken* token) : TDeviceBase<IXInputPadCallback>(dev_typeid(XInputPad), token) {} XInputPad(DeviceToken* token) : TDeviceBase<IXInputPadCallback>(dev_typeid(XInputPad), token) {}
void deviceDisconnected() void deviceDisconnected() {
{
std::lock_guard<std::mutex> lk(m_callbackLock); std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback) if (m_callback)
m_callback->controllerDisconnected(); m_callback->controllerDisconnected();
} }
void startRumble(EXInputMotor motors, uint16_t intensity) void startRumble(EXInputMotor motors, uint16_t intensity) {
{
if ((motors & EXInputMotor::Left) != EXInputMotor::None) if ((motors & EXInputMotor::Left) != EXInputMotor::None)
m_rumbleRequest[0] = intensity; m_rumbleRequest[0] = intensity;
if ((motors & EXInputMotor::Right) != EXInputMotor::None) if ((motors & EXInputMotor::Right) != EXInputMotor::None)
m_rumbleRequest[1] = intensity; m_rumbleRequest[1] = intensity;
} }
void stopRumble(EXInputMotor motors) void stopRumble(EXInputMotor motors) {
{
if ((motors & EXInputMotor::Left) != EXInputMotor::None) if ((motors & EXInputMotor::Left) != EXInputMotor::None)
m_rumbleRequest[0] = 0; m_rumbleRequest[0] = 0;
if ((motors & EXInputMotor::Right) != EXInputMotor::None) if ((motors & EXInputMotor::Right) != EXInputMotor::None)
@ -62,5 +55,4 @@ public:
} }
}; };
} } // namespace boo

View File

@ -30,21 +30,16 @@ public:
} }
} }
static inline CFPointer<T> adopt(T CF_RELEASES_ARGUMENT ptr) { static inline CFPointer<T> adopt(T CF_RELEASES_ARGUMENT ptr) { return CFPointer<T>(ptr, CFPointer<T>::Adopt); }
return CFPointer<T>(ptr, CFPointer<T>::Adopt);
}
T get() const { T get() const { return fromStorageType(storage); }
return fromStorageType(storage);
}
CFPointer& operator=(CFPointer other) { CFPointer& operator=(CFPointer other) {
swap(other); swap(other);
return *this; return *this;
} }
T* operator&() T* operator&() {
{
if (CFTypeRef pointer = storage) { if (CFTypeRef pointer = storage) {
CFRelease(pointer); CFRelease(pointer);
} }
@ -52,10 +47,8 @@ public:
} }
operator bool() const { return storage != nullptr; } operator bool() const { return storage != nullptr; }
void reset() void reset() {
{ if (storage) {
if (storage)
{
CFRelease(storage); CFRelease(storage);
storage = nullptr; storage = nullptr;
} }
@ -67,17 +60,11 @@ private:
enum AdoptTag { Adopt }; enum AdoptTag { Adopt };
CFPointer(T ptr, AdoptTag) : storage(toStorageType(ptr)) {} CFPointer(T ptr, AdoptTag) : storage(toStorageType(ptr)) {}
inline CFTypeRef toStorageType(CFTypeRef ptr) const { inline CFTypeRef toStorageType(CFTypeRef ptr) const { return (CFTypeRef)ptr; }
return (CFTypeRef)ptr;
}
inline T fromStorageType(CFTypeRef pointer) const { inline T fromStorageType(CFTypeRef pointer) const { return (T)pointer; }
return (T)pointer;
}
void swap(CFPointer &other) { void swap(CFPointer& other) { std::swap(storage, other.storage); }
std::swap(storage, other.storage);
}
}; };
/// A smart pointer that can manage the lifecycle of CoreFoundation IUnknown objects. /// A smart pointer that can manage the lifecycle of CoreFoundation IUnknown objects.
@ -116,13 +103,9 @@ public:
} }
} }
static inline IUnknownPointer<T> adopt(T** ptr) { static inline IUnknownPointer<T> adopt(T** ptr) { return IUnknownPointer<T>(ptr, IUnknownPointer<T>::Adopt); }
return IUnknownPointer<T>(ptr, IUnknownPointer<T>::Adopt);
}
T* get() const { T* get() const { return fromStorageType(_storage); }
return fromStorageType(_storage);
}
T* operator->() const { return get(); } T* operator->() const { return get(); }
T** storage() const { return (T**)_storage; } T** storage() const { return (T**)_storage; }
@ -140,16 +123,9 @@ private:
enum AdoptTag { Adopt }; enum AdoptTag { Adopt };
IUnknownPointer(T** ptr, AdoptTag) : _storage(toStorageType(ptr)) {} IUnknownPointer(T** ptr, AdoptTag) : _storage(toStorageType(ptr)) {}
inline IUnknownVTbl** toStorageType(T** ptr) const { inline IUnknownVTbl** toStorageType(T** ptr) const { return (IUnknownVTbl**)ptr; }
return (IUnknownVTbl**)ptr;
}
inline T* fromStorageType(IUnknownVTbl** pointer) const { inline T* fromStorageType(IUnknownVTbl** pointer) const { return *(T**)pointer; }
return *(T**)pointer;
}
void swap(IUnknownPointer &other) { void swap(IUnknownPointer& other) { std::swap(_storage, other._storage); }
std::swap(_storage, other._storage);
}
}; };

View File

@ -3,14 +3,13 @@
#include "boo/BooObject.hpp" #include "boo/BooObject.hpp"
#include <iterator> #include <iterator>
namespace boo namespace boo {
{
/** Linked-list iterator shareable by ListNode types. */ /** Linked-list iterator shareable by ListNode types. */
template <class T> template <class T>
class ListIterator class ListIterator {
{
T* m_node; T* m_node;
public: public:
using iterator_category = std::bidirectional_iterator_tag; using iterator_category = std::bidirectional_iterator_tag;
using value_type = T; using value_type = T;
@ -21,8 +20,14 @@ public:
explicit ListIterator(T* node) : m_node(node) {} explicit ListIterator(T* node) : m_node(node) {}
T& operator*() const { return *m_node; } T& operator*() const { return *m_node; }
bool operator!=(const ListIterator& other) const { return m_node != other.m_node; } bool operator!=(const ListIterator& other) const { return m_node != other.m_node; }
ListIterator& operator++() { m_node = m_node->m_next; return *this; } ListIterator& operator++() {
ListIterator& operator--() { m_node = m_node->m_prev; return *this; } m_node = m_node->m_next;
return *this;
}
ListIterator& operator--() {
m_node = m_node->m_prev;
return *this;
}
}; };
/** Linked-list IObj node made part of objects participating in list. /** Linked-list IObj node made part of objects participating in list.
@ -30,8 +35,7 @@ public:
* to support the common list-management functionality. * to support the common list-management functionality.
*/ */
template <class N, class H, class P = IObj> template <class N, class H, class P = IObj>
struct ListNode : P struct ListNode : P {
{
using iterator = ListIterator<N>; using iterator = ListIterator<N>;
iterator begin() { return iterator(static_cast<N*>(this)); } iterator begin() { return iterator(static_cast<N*>(this)); }
iterator end() { return iterator(nullptr); } iterator end() { return iterator(nullptr); }
@ -39,25 +43,21 @@ struct ListNode : P
H m_head; H m_head;
N* m_next; N* m_next;
N* m_prev = nullptr; N* m_prev = nullptr;
ListNode(H head) : m_head(head) ListNode(H head) : m_head(head) {
{
auto lk = N::_getHeadLock(head); auto lk = N::_getHeadLock(head);
m_next = N::_getHeadPtr(head); m_next = N::_getHeadPtr(head);
if (m_next) if (m_next)
m_next->m_prev = static_cast<N*>(this); m_next->m_prev = static_cast<N*>(this);
N::_getHeadPtr(head) = static_cast<N*>(this); N::_getHeadPtr(head) = static_cast<N*>(this);
} }
protected: protected:
~ListNode() ~ListNode() {
{ if (m_prev) {
if (m_prev)
{
if (m_next) if (m_next)
m_next->m_prev = m_prev; m_next->m_prev = m_prev;
m_prev->m_next = m_next; m_prev->m_next = m_next;
} } else {
else
{
if (m_next) if (m_next)
m_next->m_prev = nullptr; m_next->m_prev = nullptr;
N::_getHeadPtr(m_head) = m_next; N::_getHeadPtr(m_head) = m_next;
@ -65,8 +65,7 @@ protected:
} }
}; };
static inline uint32_t flp2(uint32_t x) static inline uint32_t flp2(uint32_t x) {
{
x = x | (x >> 1); x = x | (x >> 1);
x = x | (x >> 2); x = x | (x >> 2);
x = x | (x >> 4); x = x | (x >> 4);
@ -75,5 +74,4 @@ static inline uint32_t flp2(uint32_t x)
return x - (x >> 1); return x - (x >> 1);
} }
} } // namespace boo

View File

@ -10,16 +10,13 @@
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
namespace boo namespace boo {
{
static logvisor::Module Log("boo::AQS"); static logvisor::Module Log("boo::AQS");
#define AQS_NUM_BUFFERS 24 #define AQS_NUM_BUFFERS 24
static AudioChannel AQSChannelToBooChannel(AudioChannelLabel ch) static AudioChannel AQSChannelToBooChannel(AudioChannelLabel ch) {
{ switch (ch) {
switch (ch)
{
case kAudioChannelLabel_Left: case kAudioChannelLabel_Left:
return AudioChannel::FrontLeft; return AudioChannel::FrontLeft;
case kAudioChannelLabel_Right: case kAudioChannelLabel_Right:
@ -40,8 +37,7 @@ static AudioChannel AQSChannelToBooChannel(AudioChannelLabel ch)
return AudioChannel::Unknown; return AudioChannel::Unknown;
} }
struct AQSAudioVoiceEngine : BaseAudioVoiceEngine struct AQSAudioVoiceEngine : BaseAudioVoiceEngine {
{
CFPointer<CFStringRef> m_runLoopMode; CFPointer<CFStringRef> m_runLoopMode;
CFPointer<CFStringRef> m_devName; CFPointer<CFStringRef> m_devName;
@ -54,20 +50,17 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
bool m_cbRunning = true; bool m_cbRunning = true;
bool m_needsRebuild = false; bool m_needsRebuild = false;
static void Callback(AQSAudioVoiceEngine* engine, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) static void Callback(AQSAudioVoiceEngine* engine, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
{
if (!engine->m_cbRunning) if (!engine->m_cbRunning)
return; return;
engine->_pumpAndMixVoices(engine->m_mixInfo.m_periodFrames, engine->_pumpAndMixVoices(engine->m_mixInfo.m_periodFrames, reinterpret_cast<float*>(inBuffer->mAudioData));
reinterpret_cast<float*>(inBuffer->mAudioData));
inBuffer->mAudioDataByteSize = engine->m_frameBytes; inBuffer->mAudioDataByteSize = engine->m_frameBytes;
AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nullptr); AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nullptr);
} }
static void DummyCallback(AQSAudioVoiceEngine* engine, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {} static void DummyCallback(AQSAudioVoiceEngine* engine, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {}
std::pair<AudioChannelSet, Float64> _getAvailableSetAndRate() std::pair<AudioChannelSet, Float64> _getAvailableSetAndRate() {
{
AudioObjectPropertyAddress propertyAddress; AudioObjectPropertyAddress propertyAddress;
UInt32 argSize; UInt32 argSize;
int numStreams; int numStreams;
@ -79,7 +72,8 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = kAudioObjectPropertyElementMaster; propertyAddress.mElement = kAudioObjectPropertyElementMaster;
argSize = sizeof(devId); argSize = sizeof(devId);
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, sizeof(devName), &devName, &argSize, &devId) != noErr) { if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, sizeof(devName), &devName, &argSize,
&devId) != noErr) {
Log.report(logvisor::Error, "unable to resolve audio device UID %s, using default", Log.report(logvisor::Error, "unable to resolve audio device UID %s, using default",
CFStringGetCStringPtr(devName, kCFStringEncodingUTF8)); CFStringGetCStringPtr(devName, kCFStringEncodingUTF8));
argSize = sizeof(devId); argSize = sizeof(devId);
@ -111,8 +105,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
AudioStreamBasicDescription asbd; AudioStreamBasicDescription asbd;
argSize = sizeof(asbd); argSize = sizeof(asbd);
if (AudioObjectGetPropertyData(streamIDs[stm], &propertyAddress, 0, NULL, &argSize, &asbd) == noErr) { if (AudioObjectGetPropertyData(streamIDs[stm], &propertyAddress, 0, NULL, &argSize, &asbd) == noErr) {
switch (asbd.mChannelsPerFrame) switch (asbd.mChannelsPerFrame) {
{
case 2: case 2:
return {AudioChannelSet::Stereo, asbd.mSampleRate}; return {AudioChannelSet::Stereo, asbd.mSampleRate};
case 4: case 4:
@ -121,7 +114,8 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
return {AudioChannelSet::Surround51, asbd.mSampleRate}; return {AudioChannelSet::Surround51, asbd.mSampleRate};
case 8: case 8:
return {AudioChannelSet::Surround71, asbd.mSampleRate}; return {AudioChannelSet::Surround71, asbd.mSampleRate};
default: break; default:
break;
} }
if (asbd.mChannelsPerFrame > 8) if (asbd.mChannelsPerFrame > 8)
return {AudioChannelSet::Surround71, asbd.mSampleRate}; return {AudioChannelSet::Surround71, asbd.mSampleRate};
@ -136,13 +130,9 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
return {AudioChannelSet::Unknown, 48000.0}; return {AudioChannelSet::Unknown, 48000.0};
} }
std::string getCurrentAudioOutput() const std::string getCurrentAudioOutput() const { return CFStringGetCStringPtr(m_devName.get(), kCFStringEncodingUTF8); }
{
return CFStringGetCStringPtr(m_devName.get(), kCFStringEncodingUTF8);
}
bool setCurrentAudioOutput(const char* name) bool setCurrentAudioOutput(const char* name) {
{
m_devName = CFPointer<CFStringRef>::adopt(CFStringCreateWithCString(nullptr, name, kCFStringEncodingUTF8)); m_devName = CFPointer<CFStringRef>::adopt(CFStringCreateWithCString(nullptr, name, kCFStringEncodingUTF8));
_rebuildAudioQueue(); _rebuildAudioQueue();
return true; return true;
@ -151,8 +141,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
/* /*
* https://stackoverflow.com/questions/1983984/how-to-get-audio-device-uid-to-pass-into-nssounds-setplaybackdeviceidentifier * https://stackoverflow.com/questions/1983984/how-to-get-audio-device-uid-to-pass-into-nssounds-setplaybackdeviceidentifier
*/ */
std::vector<std::pair<std::string, std::string>> enumerateAudioOutputs() const std::vector<std::pair<std::string, std::string>> enumerateAudioOutputs() const {
{
std::vector<std::pair<std::string, std::string>> ret; std::vector<std::pair<std::string, std::string>> ret;
AudioObjectPropertyAddress propertyAddress; AudioObjectPropertyAddress propertyAddress;
@ -171,7 +160,8 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
ret.reserve(numDevices); ret.reserve(numDevices);
deviceIDs.resize(numDevices); deviceIDs.resize(numDevices);
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &deviceIDs[0]) == noErr) { if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize,
&deviceIDs[0]) == noErr) {
char deviceName[64]; char deviceName[64];
for (int idx = 0; idx < numDevices; idx++) { for (int idx = 0; idx < numDevices; idx++) {
@ -180,13 +170,15 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
numStreams = propertySize / sizeof(AudioStreamID); numStreams = propertySize / sizeof(AudioStreamID);
streamIDs.resize(numStreams); streamIDs.resize(numStreams);
if (AudioObjectGetPropertyData(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize, &streamIDs[0]) == noErr) { if (AudioObjectGetPropertyData(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize, &streamIDs[0]) ==
noErr) {
propertyAddress.mSelector = kAudioStreamPropertyDirection; propertyAddress.mSelector = kAudioStreamPropertyDirection;
bool foundOutput = false; bool foundOutput = false;
for (int stm = 0; stm < numStreams; stm++) { for (int stm = 0; stm < numStreams; stm++) {
UInt32 streamDir; UInt32 streamDir;
propertySize = sizeof(streamDir); propertySize = sizeof(streamDir);
if (AudioObjectGetPropertyData(streamIDs[stm], &propertyAddress, 0, NULL, &propertySize, &streamDir) == noErr) { if (AudioObjectGetPropertyData(streamIDs[stm], &propertyAddress, 0, NULL, &propertySize, &streamDir) ==
noErr) {
if (streamDir == 0) { if (streamDir == 0) {
foundOutput = true; foundOutput = true;
break; break;
@ -200,12 +192,14 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
propertySize = sizeof(deviceName); propertySize = sizeof(deviceName);
propertyAddress.mSelector = kAudioDevicePropertyDeviceName; propertyAddress.mSelector = kAudioDevicePropertyDeviceName;
if (AudioObjectGetPropertyData(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize, deviceName) == noErr) { if (AudioObjectGetPropertyData(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize, deviceName) ==
noErr) {
CFPointer<CFStringRef> uidString; CFPointer<CFStringRef> uidString;
propertySize = sizeof(CFStringRef); propertySize = sizeof(CFStringRef);
propertyAddress.mSelector = kAudioDevicePropertyDeviceUID; propertyAddress.mSelector = kAudioDevicePropertyDeviceUID;
if (AudioObjectGetPropertyData(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize, &uidString) == noErr) { if (AudioObjectGetPropertyData(deviceIDs[idx], &propertyAddress, 0, NULL, &propertySize, &uidString) ==
noErr) {
ret.emplace_back(CFStringGetCStringPtr(uidString.get(), kCFStringEncodingUTF8), deviceName); ret.emplace_back(CFStringGetCStringPtr(uidString.get(), kCFStringEncodingUTF8), deviceName);
} }
} }
@ -216,8 +210,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
return ret; return ret;
} }
std::vector<std::pair<std::string, std::string>> enumerateMIDIInputs() const std::vector<std::pair<std::string, std::string>> enumerateMIDIInputs() const {
{
if (!m_midiClient) if (!m_midiClient)
return {}; return {};
@ -225,22 +218,18 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
ItemCount numDevices = MIDIGetNumberOfDevices(); ItemCount numDevices = MIDIGetNumberOfDevices();
ret.reserve(numDevices); ret.reserve(numDevices);
for (int i=int(numDevices)-1 ; i>=0 ; --i) for (int i = int(numDevices) - 1; i >= 0; --i) {
{
MIDIDeviceRef dev = MIDIGetDevice(i); MIDIDeviceRef dev = MIDIGetDevice(i);
if (!dev) if (!dev)
continue; continue;
bool isInput = false; bool isInput = false;
ItemCount numEnt = MIDIDeviceGetNumberOfEntities(dev); ItemCount numEnt = MIDIDeviceGetNumberOfEntities(dev);
for (ItemCount j=0 ; j<numEnt ; ++j) for (ItemCount j = 0; j < numEnt; ++j) {
{
MIDIEntityRef ent = MIDIDeviceGetEntity(dev, j); MIDIEntityRef ent = MIDIDeviceGetEntity(dev, j);
if (ent) if (ent) {
{
ItemCount numSrc = MIDIEntityGetNumberOfSources(ent); ItemCount numSrc = MIDIEntityGetNumberOfSources(ent);
if (numSrc) if (numSrc) {
{
isInput = true; isInput = true;
break; break;
} }
@ -263,23 +252,17 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
char idStr[9]; char idStr[9];
snprintf(idStr, 9, "%08X\n", idNum); snprintf(idStr, 9, "%08X\n", idNum);
ret.push_back(std::make_pair(std::string(idStr), ret.push_back(std::make_pair(std::string(idStr), std::string(nameCstr)));
std::string(nameCstr)));
} }
return ret; return ret;
} }
bool supportsVirtualMIDIIn() const bool supportsVirtualMIDIIn() const { return true; }
{
return true;
}
static MIDIDeviceRef LookupMIDIDevice(const char* name) static MIDIDeviceRef LookupMIDIDevice(const char* name) {
{
ItemCount numDevices = MIDIGetNumberOfDevices(); ItemCount numDevices = MIDIGetNumberOfDevices();
for (ItemCount i=0 ; i<numDevices ; ++i) for (ItemCount i = 0; i < numDevices; ++i) {
{
MIDIDeviceRef dev = MIDIGetDevice(i); MIDIDeviceRef dev = MIDIGetDevice(i);
if (!dev) if (!dev)
continue; continue;
@ -299,21 +282,17 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
return {}; return {};
} }
static MIDIEndpointRef LookupMIDISource(const char* name) static MIDIEndpointRef LookupMIDISource(const char* name) {
{
MIDIDeviceRef dev = LookupMIDIDevice(name); MIDIDeviceRef dev = LookupMIDIDevice(name);
if (!dev) if (!dev)
return {}; return {};
ItemCount numEnt = MIDIDeviceGetNumberOfEntities(dev); ItemCount numEnt = MIDIDeviceGetNumberOfEntities(dev);
for (ItemCount i=0 ; i<numEnt ; ++i) for (ItemCount i = 0; i < numEnt; ++i) {
{
MIDIEntityRef ent = MIDIDeviceGetEntity(dev, i); MIDIEntityRef ent = MIDIDeviceGetEntity(dev, i);
if (ent) if (ent) {
{
ItemCount numSrc = MIDIEntityGetNumberOfSources(ent); ItemCount numSrc = MIDIEntityGetNumberOfSources(ent);
for (ItemCount s=0 ; s<numSrc ; ++s) for (ItemCount s = 0; s < numSrc; ++s) {
{
MIDIEndpointRef src = MIDIEntityGetSource(ent, s); MIDIEndpointRef src = MIDIEntityGetSource(ent, s);
if (src) if (src)
return src; return src;
@ -324,21 +303,17 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
return {}; return {};
} }
static MIDIEndpointRef LookupMIDIDest(const char* name) static MIDIEndpointRef LookupMIDIDest(const char* name) {
{
MIDIDeviceRef dev = LookupMIDIDevice(name); MIDIDeviceRef dev = LookupMIDIDevice(name);
if (!dev) if (!dev)
return {}; return {};
ItemCount numEnt = MIDIDeviceGetNumberOfEntities(dev); ItemCount numEnt = MIDIDeviceGetNumberOfEntities(dev);
for (ItemCount i=0 ; i<numEnt ; ++i) for (ItemCount i = 0; i < numEnt; ++i) {
{
MIDIEntityRef ent = MIDIDeviceGetEntity(dev, i); MIDIEntityRef ent = MIDIDeviceGetEntity(dev, i);
if (ent) if (ent) {
{
ItemCount numDest = MIDIEntityGetNumberOfDestinations(ent); ItemCount numDest = MIDIEntityGetNumberOfDestinations(ent);
for (ItemCount d=0 ; d<numDest ; ++d) for (ItemCount d = 0; d < numDest; ++d) {
{
MIDIEndpointRef dst = MIDIEntityGetDestination(ent, d); MIDIEndpointRef dst = MIDIEntityGetDestination(ent, d);
if (dst) if (dst)
return dst; return dst;
@ -349,37 +324,30 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
return {}; return {};
} }
static void MIDIReceiveProc(const MIDIPacketList* pktlist, static void MIDIReceiveProc(const MIDIPacketList* pktlist, IMIDIReceiver* readProcRefCon, void*) {
IMIDIReceiver* readProcRefCon,
void*)
{
const MIDIPacket* packet = &pktlist->packet[0]; const MIDIPacket* packet = &pktlist->packet[0];
for (int i=0 ; i<pktlist->numPackets ; ++i) for (int i = 0; i < pktlist->numPackets; ++i) {
{
std::vector<uint8_t> bytes(std::cbegin(packet->data), std::cbegin(packet->data) + packet->length); std::vector<uint8_t> bytes(std::cbegin(packet->data), std::cbegin(packet->data) + packet->length);
readProcRefCon->m_receiver(std::move(bytes), AudioConvertHostTimeToNanos(packet->timeStamp) / 1.0e9); readProcRefCon->m_receiver(std::move(bytes), AudioConvertHostTimeToNanos(packet->timeStamp) / 1.0e9);
packet = MIDIPacketNext(packet); packet = MIDIPacketNext(packet);
} }
} }
struct MIDIIn : public IMIDIIn struct MIDIIn : public IMIDIIn {
{
MIDIEndpointRef m_midi = 0; MIDIEndpointRef m_midi = 0;
MIDIPortRef m_midiPort = 0; MIDIPortRef m_midiPort = 0;
MIDIIn(AQSAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) MIDIIn(AQSAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver)
: IMIDIIn(parent, virt, std::move(receiver)) {} : IMIDIIn(parent, virt, std::move(receiver)) {}
~MIDIIn() ~MIDIIn() {
{
if (m_midi) if (m_midi)
MIDIEndpointDispose(m_midi); MIDIEndpointDispose(m_midi);
if (m_midiPort) if (m_midiPort)
MIDIPortDispose(m_midiPort); MIDIPortDispose(m_midiPort);
} }
std::string description() const std::string description() const {
{
CFPointer<CFStringRef> namestr; CFPointer<CFStringRef> namestr;
const char* nameCstr; const char* nameCstr;
if (MIDIObjectGetStringProperty(m_midi, kMIDIPropertyName, &namestr)) if (MIDIObjectGetStringProperty(m_midi, kMIDIPropertyName, &namestr))
@ -392,24 +360,20 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
} }
}; };
struct MIDIOut : public IMIDIOut struct MIDIOut : public IMIDIOut {
{
MIDIEndpointRef m_midi = 0; MIDIEndpointRef m_midi = 0;
MIDIPortRef m_midiPort = 0; MIDIPortRef m_midiPort = 0;
MIDIOut(AQSAudioVoiceEngine* parent, bool virt) MIDIOut(AQSAudioVoiceEngine* parent, bool virt) : IMIDIOut(parent, virt) {}
: IMIDIOut(parent, virt) {}
~MIDIOut() ~MIDIOut() {
{
if (m_midi) if (m_midi)
MIDIEndpointDispose(m_midi); MIDIEndpointDispose(m_midi);
if (m_midiPort) if (m_midiPort)
MIDIPortDispose(m_midiPort); MIDIPortDispose(m_midiPort);
} }
std::string description() const std::string description() const {
{
CFPointer<CFStringRef> namestr; CFPointer<CFStringRef> namestr;
const char* nameCstr; const char* nameCstr;
if (MIDIObjectGetStringProperty(m_midi, kMIDIPropertyName, &namestr)) if (MIDIObjectGetStringProperty(m_midi, kMIDIPropertyName, &namestr))
@ -421,17 +385,14 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
return nameCstr; return nameCstr;
} }
size_t send(const void* buf, size_t len) const size_t send(const void* buf, size_t len) const {
{ union {
union
{
MIDIPacketList head; MIDIPacketList head;
Byte storage[512]; Byte storage[512];
} list; } list;
MIDIPacket* curPacket = MIDIPacketListInit(&list.head); MIDIPacket* curPacket = MIDIPacketListInit(&list.head);
if (MIDIPacketListAdd(&list.head, sizeof(list), curPacket, AudioGetCurrentHostTime(), if (MIDIPacketListAdd(&list.head, sizeof(list), curPacket, AudioGetCurrentHostTime(), len,
len, reinterpret_cast<const Byte*>(buf))) reinterpret_cast<const Byte*>(buf))) {
{
if (m_midiPort) if (m_midiPort)
MIDISend(m_midiPort, m_midi, &list.head); MIDISend(m_midiPort, m_midi, &list.head);
else else
@ -442,8 +403,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
} }
}; };
struct MIDIInOut : public IMIDIInOut struct MIDIInOut : public IMIDIInOut {
{
MIDIEndpointRef m_midiIn = 0; MIDIEndpointRef m_midiIn = 0;
MIDIPortRef m_midiPortIn = 0; MIDIPortRef m_midiPortIn = 0;
MIDIEndpointRef m_midiOut = 0; MIDIEndpointRef m_midiOut = 0;
@ -452,8 +412,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
MIDIInOut(AQSAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) MIDIInOut(AQSAudioVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver)
: IMIDIInOut(parent, virt, std::move(receiver)) {} : IMIDIInOut(parent, virt, std::move(receiver)) {}
~MIDIInOut() ~MIDIInOut() {
{
if (m_midiIn) if (m_midiIn)
MIDIEndpointDispose(m_midiIn); MIDIEndpointDispose(m_midiIn);
if (m_midiPortIn) if (m_midiPortIn)
@ -464,8 +423,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
MIDIPortDispose(m_midiPortOut); MIDIPortDispose(m_midiPortOut);
} }
std::string description() const std::string description() const {
{
CFPointer<CFStringRef> namestr; CFPointer<CFStringRef> namestr;
const char* nameCstr; const char* nameCstr;
if (MIDIObjectGetStringProperty(m_midiIn, kMIDIPropertyName, &namestr)) if (MIDIObjectGetStringProperty(m_midiIn, kMIDIPropertyName, &namestr))
@ -477,17 +435,14 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
return nameCstr; return nameCstr;
} }
size_t send(const void* buf, size_t len) const size_t send(const void* buf, size_t len) const {
{ union {
union
{
MIDIPacketList head; MIDIPacketList head;
Byte storage[512]; Byte storage[512];
} list; } list;
MIDIPacket* curPacket = MIDIPacketListInit(&list.head); MIDIPacket* curPacket = MIDIPacketListInit(&list.head);
if (MIDIPacketListAdd(&list.head, sizeof(list), curPacket, AudioGetCurrentHostTime(), if (MIDIPacketListAdd(&list.head, sizeof(list), curPacket, AudioGetCurrentHostTime(), len,
len, reinterpret_cast<const Byte*>(buf))) reinterpret_cast<const Byte*>(buf))) {
{
if (m_midiPortOut) if (m_midiPortOut)
MIDISend(m_midiPortOut, m_midiOut, &list.head); MIDISend(m_midiPortOut, m_midiOut, &list.head);
else else
@ -501,8 +456,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
unsigned m_midiInCounter = 0; unsigned m_midiInCounter = 0;
unsigned m_midiOutCounter = 0; unsigned m_midiOutCounter = 0;
std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver) std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver) {
{
if (!m_midiClient) if (!m_midiClient)
return {}; return {};
@ -521,15 +475,13 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
CFStringCreateWithCStringNoCopy(nullptr, name, kCFStringEncodingUTF8, kCFAllocatorNull)); CFStringCreateWithCStringNoCopy(nullptr, name, kCFStringEncodingUTF8, kCFAllocatorNull));
OSStatus stat; OSStatus stat;
if ((stat = MIDIDestinationCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc), if ((stat = MIDIDestinationCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc),
static_cast<IMIDIReceiver*>(ret.get()), static_cast<IMIDIReceiver*>(ret.get()), &static_cast<MIDIIn&>(*ret).m_midi)))
&static_cast<MIDIIn&>(*ret).m_midi)))
ret.reset(); ret.reset();
return ret; return ret;
} }
std::unique_ptr<IMIDIOut> newVirtualMIDIOut() std::unique_ptr<IMIDIOut> newVirtualMIDIOut() {
{
if (!m_midiClient) if (!m_midiClient)
return {}; return {};
@ -552,8 +504,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
return ret; return ret;
} }
std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver) std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver) {
{
if (!m_midiClient) if (!m_midiClient)
return {}; return {};
@ -571,8 +522,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
CFPointer<CFStringRef> midiName = CFPointer<CFStringRef>::adopt( CFPointer<CFStringRef> midiName = CFPointer<CFStringRef>::adopt(
CFStringCreateWithCStringNoCopy(nullptr, name, kCFStringEncodingUTF8, kCFAllocatorNull)); CFStringCreateWithCStringNoCopy(nullptr, name, kCFStringEncodingUTF8, kCFAllocatorNull));
if (MIDIDestinationCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc), if (MIDIDestinationCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc),
static_cast<IMIDIReceiver*>(ret.get()), static_cast<IMIDIReceiver*>(ret.get()), &static_cast<MIDIInOut&>(*ret).m_midiIn))
&static_cast<MIDIInOut&>(*ret).m_midiIn))
ret.reset(); ret.reset();
if (!ret) if (!ret)
@ -591,8 +541,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
return ret; return ret;
} }
std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) {
{
if (!m_midiClient) if (!m_midiClient)
return {}; return {};
@ -609,8 +558,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
CFPointer<CFStringRef> midiName = CFPointer<CFStringRef>::adopt( CFPointer<CFStringRef> midiName = CFPointer<CFStringRef>::adopt(
CFStringCreateWithCStringNoCopy(nullptr, mname, kCFStringEncodingUTF8, kCFAllocatorNull)); CFStringCreateWithCStringNoCopy(nullptr, mname, kCFStringEncodingUTF8, kCFAllocatorNull));
if (MIDIInputPortCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc), if (MIDIInputPortCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc),
static_cast<IMIDIReceiver*>(ret.get()), static_cast<IMIDIReceiver*>(ret.get()), &static_cast<MIDIIn&>(*ret).m_midiPort))
&static_cast<MIDIIn&>(*ret).m_midiPort))
ret.reset(); ret.reset();
else else
MIDIPortConnectSource(static_cast<MIDIIn&>(*ret).m_midiPort, src, nullptr); MIDIPortConnectSource(static_cast<MIDIIn&>(*ret).m_midiPort, src, nullptr);
@ -618,8 +566,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
return ret; return ret;
} }
std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name) std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name) {
{
if (!m_midiClient) if (!m_midiClient)
return {}; return {};
@ -643,8 +590,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
return ret; return ret;
} }
std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) {
{
if (!m_midiClient) if (!m_midiClient)
return {}; return {};
@ -665,8 +611,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
CFPointer<CFStringRef> midiName = CFPointer<CFStringRef>::adopt( CFPointer<CFStringRef> midiName = CFPointer<CFStringRef>::adopt(
CFStringCreateWithCStringNoCopy(nullptr, mname, kCFStringEncodingUTF8, kCFAllocatorNull)); CFStringCreateWithCStringNoCopy(nullptr, mname, kCFStringEncodingUTF8, kCFAllocatorNull));
if (MIDIInputPortCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc), if (MIDIInputPortCreate(m_midiClient, midiName.get(), MIDIReadProc(MIDIReceiveProc),
static_cast<IMIDIReceiver*>(ret.get()), static_cast<IMIDIReceiver*>(ret.get()), &static_cast<MIDIInOut&>(*ret).m_midiPortIn))
&static_cast<MIDIInOut&>(*ret).m_midiPortIn))
ret.reset(); ret.reset();
else else
MIDIPortConnectSource(static_cast<MIDIInOut&>(*ret).m_midiPortIn, src, nullptr); MIDIPortConnectSource(static_cast<MIDIInOut&>(*ret).m_midiPortIn, src, nullptr);
@ -687,17 +632,12 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
bool useMIDILock() const { return true; } bool useMIDILock() const { return true; }
static void SampleRateChanged(AQSAudioVoiceEngine* engine, static void SampleRateChanged(AQSAudioVoiceEngine* engine, AudioQueueRef inAQ, AudioQueuePropertyID inID) {
AudioQueueRef inAQ,
AudioQueuePropertyID inID)
{
engine->m_needsRebuild = true; engine->m_needsRebuild = true;
} }
void _rebuildAudioQueue() void _rebuildAudioQueue() {
{ if (m_queue) {
if (m_queue)
{
m_cbRunning = false; m_cbRunning = false;
AudioQueueDispose(m_queue, true); AudioQueueDispose(m_queue, true);
m_cbRunning = true; m_cbRunning = true;
@ -719,16 +659,14 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
desc.mBitsPerChannel = 32; desc.mBitsPerChannel = 32;
OSStatus err; OSStatus err;
if ((err = AudioQueueNewOutput(&desc, AudioQueueOutputCallback(Callback), if ((err = AudioQueueNewOutput(&desc, AudioQueueOutputCallback(Callback), this, CFRunLoopGetCurrent(),
this, CFRunLoopGetCurrent(), m_runLoopMode.get(), 0, &m_queue))) m_runLoopMode.get(), 0, &m_queue))) {
{
Log.report(logvisor::Fatal, "unable to create output audio queue"); Log.report(logvisor::Fatal, "unable to create output audio queue");
return; return;
} }
CFStringRef devName = m_devName.get(); CFStringRef devName = m_devName.get();
if ((err = AudioQueueSetProperty(m_queue, kAudioQueueProperty_CurrentDevice, &devName, sizeof(devName)))) if ((err = AudioQueueSetProperty(m_queue, kAudioQueueProperty_CurrentDevice, &devName, sizeof(devName)))) {
{
Log.report(logvisor::Fatal, "unable to set current device into audio queue"); Log.report(logvisor::Fatal, "unable to set current device into audio queue");
return; return;
} }
@ -743,15 +681,12 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
ChannelMap& chMapOut = m_mixInfo.m_channelMap; ChannelMap& chMapOut = m_mixInfo.m_channelMap;
chMapOut.m_channelCount = 0; chMapOut.m_channelCount = 0;
if (chCount > 2) if (chCount > 2) {
{
AudioChannelLayout layout; AudioChannelLayout layout;
UInt32 layoutSz = sizeof(layout); UInt32 layoutSz = sizeof(layout);
if (AudioQueueGetProperty(m_queue, kAudioQueueProperty_ChannelLayout, &layout, &layoutSz)) if (AudioQueueGetProperty(m_queue, kAudioQueueProperty_ChannelLayout, &layout, &layoutSz)) {
{
Log.report(logvisor::Warning, "unable to get channel layout from audio queue; using count's default"); Log.report(logvisor::Warning, "unable to get channel layout from audio queue; using count's default");
switch (m_mixInfo.m_channels) switch (m_mixInfo.m_channels) {
{
case AudioChannelSet::Stereo: case AudioChannelSet::Stereo:
default: default:
chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft;
@ -782,15 +717,11 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearRight; chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::RearRight;
break; break;
} }
} } else {
else switch (layout.mChannelLayoutTag) {
{
switch (layout.mChannelLayoutTag)
{
case kAudioChannelLayoutTag_UseChannelDescriptions: case kAudioChannelLayoutTag_UseChannelDescriptions:
chMapOut.m_channelCount = layout.mNumberChannelDescriptions; chMapOut.m_channelCount = layout.mNumberChannelDescriptions;
for (int i = 0; i < layout.mNumberChannelDescriptions; ++i) for (int i = 0; i < layout.mNumberChannelDescriptions; ++i) {
{
AudioChannel ch = AQSChannelToBooChannel(layout.mChannelDescriptions[i].mChannelLabel); AudioChannel ch = AQSChannelToBooChannel(layout.mChannelDescriptions[i].mChannelLabel);
chMapOut.m_channels[i] = ch; chMapOut.m_channels[i] = ch;
} }
@ -835,18 +766,14 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
chMapOut.m_channels[4] = AudioChannel::FrontCenter; chMapOut.m_channels[4] = AudioChannel::FrontCenter;
break; break;
default: default:
Log.report(logvisor::Warning, Log.report(logvisor::Warning, "unknown channel layout %u; using stereo", layout.mChannelLayoutTag);
"unknown channel layout %u; using stereo",
layout.mChannelLayoutTag);
chMapOut.m_channelCount = 2; chMapOut.m_channelCount = 2;
chMapOut.m_channels[0] = AudioChannel::FrontLeft; chMapOut.m_channels[0] = AudioChannel::FrontLeft;
chMapOut.m_channels[1] = AudioChannel::FrontRight; chMapOut.m_channels[1] = AudioChannel::FrontRight;
break; break;
} }
} }
} } else {
else
{
chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft; chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontLeft;
chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight; chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::FrontRight;
} }
@ -856,8 +783,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
m_mixInfo.m_periodFrames = m_5msFrames; m_mixInfo.m_periodFrames = m_5msFrames;
for (int i = 0; i < AQS_NUM_BUFFERS; ++i) for (int i = 0; i < AQS_NUM_BUFFERS; ++i)
if (AudioQueueAllocateBuffer(m_queue, m_mixInfo.m_periodFrames * chCount * 4, &m_buffers[i])) if (AudioQueueAllocateBuffer(m_queue, m_mixInfo.m_periodFrames * chCount * 4, &m_buffers[i])) {
{
Log.report(logvisor::Fatal, "unable to create audio queue buffer"); Log.report(logvisor::Fatal, "unable to create audio queue buffer");
AudioQueueDispose(m_queue, false); AudioQueueDispose(m_queue, false);
m_queue = nullptr; m_queue = nullptr;
@ -868,8 +794,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
_resetSampleRate(); _resetSampleRate();
for (unsigned i=0 ; i<AQS_NUM_BUFFERS ; ++i) for (unsigned i = 0; i < AQS_NUM_BUFFERS; ++i) {
{
memset(m_buffers[i]->mAudioData, 0, m_frameBytes); memset(m_buffers[i]->mAudioData, 0, m_frameBytes);
m_buffers[i]->mAudioDataByteSize = m_frameBytes; m_buffers[i]->mAudioDataByteSize = m_frameBytes;
AudioQueueEnqueueBuffer(m_queue, m_buffers[i], 0, nullptr); AudioQueueEnqueueBuffer(m_queue, m_buffers[i], 0, nullptr);
@ -878,11 +803,8 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
AudioQueueStart(m_queue, nullptr); AudioQueueStart(m_queue, nullptr);
} }
static OSStatus AudioDeviceChanged(AudioObjectID inObjectID, static OSStatus AudioDeviceChanged(AudioObjectID inObjectID, UInt32 inNumberAddresses,
UInt32 inNumberAddresses, const AudioObjectPropertyAddress* inAddresses, AQSAudioVoiceEngine* engine) {
const AudioObjectPropertyAddress* inAddresses,
AQSAudioVoiceEngine* engine)
{
AudioObjectID defaultDeviceId; AudioObjectID defaultDeviceId;
UInt32 argSize = sizeof(defaultDeviceId); UInt32 argSize = sizeof(defaultDeviceId);
if (AudioObjectGetPropertyData(inObjectID, inAddresses, 0, NULL, &argSize, &defaultDeviceId) == noErr) { if (AudioObjectGetPropertyData(inObjectID, inAddresses, 0, NULL, &argSize, &defaultDeviceId) == noErr) {
@ -897,8 +819,7 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
AQSAudioVoiceEngine() AQSAudioVoiceEngine()
: m_runLoopMode(CFPointer<CFStringRef>::adopt( : m_runLoopMode(CFPointer<CFStringRef>::adopt(
CFStringCreateWithCStringNoCopy(nullptr, "BooAQSMode", kCFStringEncodingUTF8, kCFAllocatorNull))) CFStringCreateWithCStringNoCopy(nullptr, "BooAQSMode", kCFStringEncodingUTF8, kCFAllocatorNull))) {
{
AudioObjectPropertyAddress propertyAddress; AudioObjectPropertyAddress propertyAddress;
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = kAudioObjectPropertyElementMaster; propertyAddress.mElement = kAudioObjectPropertyElementMaster;
@ -906,7 +827,8 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
AudioObjectID defaultDeviceId; AudioObjectID defaultDeviceId;
UInt32 argSize = sizeof(defaultDeviceId); UInt32 argSize = sizeof(defaultDeviceId);
propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &argSize, &defaultDeviceId) == noErr) { if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &argSize, &defaultDeviceId) ==
noErr) {
argSize = sizeof(CFStringRef); argSize = sizeof(CFStringRef);
AudioObjectPropertyAddress deviceAddress; AudioObjectPropertyAddress deviceAddress;
deviceAddress.mSelector = kAudioDevicePropertyDeviceUID; deviceAddress.mSelector = kAudioDevicePropertyDeviceUID;
@ -926,31 +848,27 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
MIDIClientCreate(CFSTR("Boo MIDI"), nullptr, nullptr, &m_midiClient); MIDIClientCreate(CFSTR("Boo MIDI"), nullptr, nullptr, &m_midiClient);
} }
~AQSAudioVoiceEngine() ~AQSAudioVoiceEngine() {
{
m_cbRunning = false; m_cbRunning = false;
AudioQueueDispose(m_queue, true); AudioQueueDispose(m_queue, true);
if (m_midiClient) if (m_midiClient)
MIDIClientDispose(m_midiClient); MIDIClientDispose(m_midiClient);
} }
void pumpAndMixVoices() void pumpAndMixVoices() {
{
while (CFRunLoopRunInMode(m_runLoopMode.get(), 0, true) == kCFRunLoopRunHandledSource) {} while (CFRunLoopRunInMode(m_runLoopMode.get(), 0, true) == kCFRunLoopRunHandledSource) {}
if (m_needsRebuild) if (m_needsRebuild) {
{
_rebuildAudioQueue(); _rebuildAudioQueue();
m_needsRebuild = false; m_needsRebuild = false;
} }
} }
}; };
std::unique_ptr<IAudioVoiceEngine> NewAudioVoiceEngine() std::unique_ptr<IAudioVoiceEngine> NewAudioVoiceEngine() {
{
std::unique_ptr<IAudioVoiceEngine> ret = std::make_unique<AQSAudioVoiceEngine>(); std::unique_ptr<IAudioVoiceEngine> ret = std::make_unique<AQSAudioVoiceEngine>();
if (!static_cast<AQSAudioVoiceEngine&>(*ret).m_queue) if (!static_cast<AQSAudioVoiceEngine&>(*ret).m_queue)
return {}; return {};
return ret; return ret;
} }
} } // namespace boo

View File

@ -2,16 +2,13 @@
#include "AudioVoiceEngine.hpp" #include "AudioVoiceEngine.hpp"
#include <cstring> #include <cstring>
namespace boo namespace boo {
{
void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet) void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet) {
{
m_curSlewFrame = 0; m_curSlewFrame = 0;
m_slewFrames = 0; m_slewFrames = 0;
memset(&m_coefs, 0, sizeof(m_coefs)); memset(&m_coefs, 0, sizeof(m_coefs));
switch (acSet) switch (acSet) {
{
case AudioChannelSet::Stereo: case AudioChannelSet::Stereo:
case AudioChannelSet::Quad: case AudioChannelSet::Quad:
m_coefs.v[int(AudioChannel::FrontLeft)] = 1.0; m_coefs.v[int(AudioChannel::FrontLeft)] = 1.0;
@ -21,40 +18,32 @@ void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet)
case AudioChannelSet::Surround71: case AudioChannelSet::Surround71:
m_coefs.v[int(AudioChannel::FrontCenter)] = 1.0; m_coefs.v[int(AudioChannel::FrontCenter)] = 1.0;
break; break;
default: break; default:
break;
} }
} }
int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const int16_t* dataIn,
const int16_t* dataIn, int16_t* dataOut, size_t samples) int16_t* dataOut, size_t samples) {
{
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t s=0 ; s<samples ; ++s, ++dataIn) for (size_t s = 0; s < samples; ++s, ++dataIn) {
{ if (m_slewFrames && m_curSlewFrame < m_slewFrames) {
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames); double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t; double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{
*dataOut = Clamp16(*dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt)); *dataOut = Clamp16(*dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt));
++dataOut; ++dataOut;
} }
} }
++m_curSlewFrame; ++m_curSlewFrame;
} } else {
else for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{
*dataOut = Clamp16(*dataOut + *dataIn * m_coefs.v[int(ch)]); *dataOut = Clamp16(*dataOut + *dataIn * m_coefs.v[int(ch)]);
++dataOut; ++dataOut;
} }
@ -64,36 +53,27 @@ int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
return dataOut; return dataOut;
} }
int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const int32_t* dataIn,
const int32_t* dataIn, int32_t* dataOut, size_t samples) int32_t* dataOut, size_t samples) {
{
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t s=0 ; s<samples ; ++s, ++dataIn) for (size_t s = 0; s < samples; ++s, ++dataIn) {
{ if (m_slewFrames && m_curSlewFrame < m_slewFrames) {
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames); double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t; double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{
*dataOut = Clamp32(*dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt)); *dataOut = Clamp32(*dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt));
++dataOut; ++dataOut;
} }
} }
++m_curSlewFrame; ++m_curSlewFrame;
} } else {
else for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{
*dataOut = Clamp32(*dataOut + *dataIn * m_coefs.v[int(ch)]); *dataOut = Clamp32(*dataOut + *dataIn * m_coefs.v[int(ch)]);
++dataOut; ++dataOut;
} }
@ -103,36 +83,27 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
return dataOut; return dataOut;
} }
float* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, float* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const float* dataIn, float* dataOut,
const float* dataIn, float* dataOut, size_t samples) size_t samples) {
{
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t s=0 ; s<samples ; ++s, ++dataIn) for (size_t s = 0; s < samples; ++s, ++dataIn) {
{ if (m_slewFrames && m_curSlewFrame < m_slewFrames) {
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames); double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t; double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{
*dataOut = *dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt); *dataOut = *dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt);
++dataOut; ++dataOut;
} }
} }
++m_curSlewFrame; ++m_curSlewFrame;
} } else {
else for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{
*dataOut = *dataOut + *dataIn * m_coefs.v[int(ch)]; *dataOut = *dataOut + *dataIn * m_coefs.v[int(ch)];
++dataOut; ++dataOut;
} }
@ -142,13 +113,11 @@ float* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
return dataOut; return dataOut;
} }
void AudioMatrixStereo::setDefaultMatrixCoefficients(AudioChannelSet acSet) void AudioMatrixStereo::setDefaultMatrixCoefficients(AudioChannelSet acSet) {
{
m_curSlewFrame = 0; m_curSlewFrame = 0;
m_slewFrames = 0; m_slewFrames = 0;
memset(&m_coefs, 0, sizeof(m_coefs)); memset(&m_coefs, 0, sizeof(m_coefs));
switch (acSet) switch (acSet) {
{
case AudioChannelSet::Stereo: case AudioChannelSet::Stereo:
case AudioChannelSet::Quad: case AudioChannelSet::Quad:
m_coefs.v[int(AudioChannel::FrontLeft)][0] = 1.0; m_coefs.v[int(AudioChannel::FrontLeft)][0] = 1.0;
@ -159,45 +128,34 @@ void AudioMatrixStereo::setDefaultMatrixCoefficients(AudioChannelSet acSet)
m_coefs.v[int(AudioChannel::FrontLeft)][0] = 1.0; m_coefs.v[int(AudioChannel::FrontLeft)][0] = 1.0;
m_coefs.v[int(AudioChannel::FrontRight)][1] = 1.0; m_coefs.v[int(AudioChannel::FrontRight)][1] = 1.0;
break; break;
default: break; default:
break;
} }
} }
int16_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, int16_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, const int16_t* dataIn,
const int16_t* dataIn, int16_t* dataOut, size_t frames) int16_t* dataOut, size_t frames) {
{
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t f=0 ; f<frames ; ++f, dataIn += 2) for (size_t f = 0; f < frames; ++f, dataIn += 2) {
{ if (m_slewFrames && m_curSlewFrame < m_slewFrames) {
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames); double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t; double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{ *dataOut = Clamp16(*dataOut + *dataIn * (m_coefs.v[int(ch)][0] * t + m_oldCoefs.v[int(ch)][0] * omt) +
*dataOut = Clamp16(*dataOut +
*dataIn * (m_coefs.v[int(ch)][0] * t + m_oldCoefs.v[int(ch)][0] * omt) +
*dataIn * (m_coefs.v[int(ch)][1] * t + m_oldCoefs.v[int(ch)][1] * omt)); *dataIn * (m_coefs.v[int(ch)][1] * t + m_oldCoefs.v[int(ch)][1] * omt));
++dataOut; ++dataOut;
} }
} }
++m_curSlewFrame; ++m_curSlewFrame;
} } else {
else for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{ *dataOut = Clamp16(*dataOut + dataIn[0] * m_coefs.v[int(ch)][0] + dataIn[1] * m_coefs.v[int(ch)][1]);
*dataOut = Clamp16(*dataOut +
dataIn[0] * m_coefs.v[int(ch)][0] +
dataIn[1] * m_coefs.v[int(ch)][1]);
++dataOut; ++dataOut;
} }
} }
@ -206,41 +164,29 @@ int16_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& i
return dataOut; return dataOut;
} }
int32_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, int32_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, const int32_t* dataIn,
const int32_t* dataIn, int32_t* dataOut, size_t frames) int32_t* dataOut, size_t frames) {
{
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t f=0 ; f<frames ; ++f, dataIn += 2) for (size_t f = 0; f < frames; ++f, dataIn += 2) {
{ if (m_slewFrames && m_curSlewFrame < m_slewFrames) {
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames); double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t; double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{ *dataOut = Clamp32(*dataOut + *dataIn * (m_coefs.v[int(ch)][0] * t + m_oldCoefs.v[int(ch)][0] * omt) +
*dataOut = Clamp32(*dataOut +
*dataIn * (m_coefs.v[int(ch)][0] * t + m_oldCoefs.v[int(ch)][0] * omt) +
*dataIn * (m_coefs.v[int(ch)][1] * t + m_oldCoefs.v[int(ch)][1] * omt)); *dataIn * (m_coefs.v[int(ch)][1] * t + m_oldCoefs.v[int(ch)][1] * omt));
++dataOut; ++dataOut;
} }
} }
++m_curSlewFrame; ++m_curSlewFrame;
} } else {
else for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{ *dataOut = Clamp32(*dataOut + dataIn[0] * m_coefs.v[int(ch)][0] + dataIn[1] * m_coefs.v[int(ch)][1]);
*dataOut = Clamp32(*dataOut +
dataIn[0] * m_coefs.v[int(ch)][0] +
dataIn[1] * m_coefs.v[int(ch)][1]);
++dataOut; ++dataOut;
} }
} }
@ -249,41 +195,29 @@ int32_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& i
return dataOut; return dataOut;
} }
float* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, float* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, const float* dataIn, float* dataOut,
const float* dataIn, float* dataOut, size_t frames) size_t frames) {
{
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t f=0 ; f<frames ; ++f, dataIn += 2) for (size_t f = 0; f < frames; ++f, dataIn += 2) {
{ if (m_slewFrames && m_curSlewFrame < m_slewFrames) {
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames); double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t; double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{ *dataOut = *dataOut + *dataIn * (m_coefs.v[int(ch)][0] * t + m_oldCoefs.v[int(ch)][0] * omt) +
*dataOut = *dataOut +
*dataIn * (m_coefs.v[int(ch)][0] * t + m_oldCoefs.v[int(ch)][0] * omt) +
*dataIn * (m_coefs.v[int(ch)][1] * t + m_oldCoefs.v[int(ch)][1] * omt); *dataIn * (m_coefs.v[int(ch)][1] * t + m_oldCoefs.v[int(ch)][1] * omt);
++dataOut; ++dataOut;
} }
} }
++m_curSlewFrame; ++m_curSlewFrame;
} } else {
else for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{ *dataOut = *dataOut + dataIn[0] * m_coefs.v[int(ch)][0] + dataIn[1] * m_coefs.v[int(ch)][1];
*dataOut = *dataOut +
dataIn[0] * m_coefs.v[int(ch)][0] +
dataIn[1] * m_coefs.v[int(ch)][1];
++dataOut; ++dataOut;
} }
} }
@ -292,5 +226,4 @@ float* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& inf
return dataOut; return dataOut;
} }
} } // namespace boo

View File

@ -10,12 +10,10 @@
#include <immintrin.h> #include <immintrin.h>
#endif #endif
namespace boo namespace boo {
{
struct AudioVoiceEngineMixInfo; struct AudioVoiceEngineMixInfo;
static inline int16_t Clamp16(float in) static inline int16_t Clamp16(float in) {
{
if (in < SHRT_MIN) if (in < SHRT_MIN)
return SHRT_MIN; return SHRT_MIN;
else if (in > SHRT_MAX) else if (in > SHRT_MAX)
@ -23,8 +21,7 @@ static inline int16_t Clamp16(float in)
return in; return in;
} }
static inline int32_t Clamp32(float in) static inline int32_t Clamp32(float in) {
{
if (in < INT_MIN) if (in < INT_MIN)
return INT_MIN; return INT_MIN;
else if (in > INT_MAX) else if (in > INT_MAX)
@ -32,10 +29,8 @@ static inline int32_t Clamp32(float in)
return in; return in;
} }
class AudioMatrixMono class AudioMatrixMono {
{ union Coefs {
union Coefs
{
float v[8]; float v[8];
#if __SSE__ #if __SSE__
__m128 q[2]; __m128 q[2];
@ -46,24 +41,22 @@ class AudioMatrixMono
Coefs m_oldCoefs = {}; Coefs m_oldCoefs = {};
size_t m_slewFrames = 0; size_t m_slewFrames = 0;
size_t m_curSlewFrame = ~size_t(0); size_t m_curSlewFrame = ~size_t(0);
public: public:
AudioMatrixMono() { setDefaultMatrixCoefficients(AudioChannelSet::Stereo); } AudioMatrixMono() { setDefaultMatrixCoefficients(AudioChannelSet::Stereo); }
void setDefaultMatrixCoefficients(AudioChannelSet acSet); void setDefaultMatrixCoefficients(AudioChannelSet acSet);
void setMatrixCoefficients(const float coefs[8], size_t slewFrames=0) void setMatrixCoefficients(const float coefs[8], size_t slewFrames = 0) {
{
m_slewFrames = slewFrames; m_slewFrames = slewFrames;
#if __SSE__ #if __SSE__
if (m_curSlewFrame != 0) if (m_curSlewFrame != 0) {
{
m_oldCoefs.q[0] = m_coefs.q[0]; m_oldCoefs.q[0] = m_coefs.q[0];
m_oldCoefs.q[1] = m_coefs.q[1]; m_oldCoefs.q[1] = m_coefs.q[1];
} }
m_coefs.q[0] = _mm_loadu_ps(coefs); m_coefs.q[0] = _mm_loadu_ps(coefs);
m_coefs.q[1] = _mm_loadu_ps(&coefs[4]); m_coefs.q[1] = _mm_loadu_ps(&coefs[4]);
#else #else
for (int i=0 ; i<8 ; ++i) for (int i = 0; i < 8; ++i) {
{
if (m_curSlewFrame != 0) if (m_curSlewFrame != 0)
m_oldCoefs.v[i] = m_coefs.v[i]; m_oldCoefs.v[i] = m_coefs.v[i];
m_coefs.v[i] = coefs[i]; m_coefs.v[i] = coefs[i];
@ -72,15 +65,13 @@ public:
m_curSlewFrame = 0; m_curSlewFrame = 0;
} }
int16_t* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, int16_t* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const int16_t* dataIn, int16_t* dataOut,
const int16_t* dataIn, int16_t* dataOut, size_t samples); size_t samples);
int32_t* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, int32_t* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const int32_t* dataIn, int32_t* dataOut,
const int32_t* dataIn, int32_t* dataOut, size_t samples); size_t samples);
float* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, float* mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const float* dataIn, float* dataOut, size_t samples);
const float* dataIn, float* dataOut, size_t samples);
bool isSilent() const bool isSilent() const {
{
if (m_curSlewFrame < m_slewFrames) if (m_curSlewFrame < m_slewFrames)
for (int i = 0; i < 8; ++i) for (int i = 0; i < 8; ++i)
if (m_oldCoefs.v[i] > FLT_EPSILON) if (m_oldCoefs.v[i] > FLT_EPSILON)
@ -92,10 +83,8 @@ public:
} }
}; };
class AudioMatrixStereo class AudioMatrixStereo {
{ union Coefs {
union Coefs
{
float v[8][2]; float v[8][2];
#if __SSE__ #if __SSE__
__m128 q[4]; __m128 q[4];
@ -106,16 +95,15 @@ class AudioMatrixStereo
Coefs m_oldCoefs = {}; Coefs m_oldCoefs = {};
size_t m_slewFrames = 0; size_t m_slewFrames = 0;
size_t m_curSlewFrame = ~size_t(0); size_t m_curSlewFrame = ~size_t(0);
public: public:
AudioMatrixStereo() { setDefaultMatrixCoefficients(AudioChannelSet::Stereo); } AudioMatrixStereo() { setDefaultMatrixCoefficients(AudioChannelSet::Stereo); }
void setDefaultMatrixCoefficients(AudioChannelSet acSet); void setDefaultMatrixCoefficients(AudioChannelSet acSet);
void setMatrixCoefficients(const float coefs[8][2], size_t slewFrames=0) void setMatrixCoefficients(const float coefs[8][2], size_t slewFrames = 0) {
{
m_slewFrames = slewFrames; m_slewFrames = slewFrames;
#if __SSE__ #if __SSE__
if (m_curSlewFrame != 0) if (m_curSlewFrame != 0) {
{
m_oldCoefs.q[0] = m_coefs.q[0]; m_oldCoefs.q[0] = m_coefs.q[0];
m_oldCoefs.q[1] = m_coefs.q[1]; m_oldCoefs.q[1] = m_coefs.q[1];
m_oldCoefs.q[2] = m_coefs.q[2]; m_oldCoefs.q[2] = m_coefs.q[2];
@ -126,10 +114,8 @@ public:
m_coefs.q[2] = _mm_loadu_ps(coefs[4]); m_coefs.q[2] = _mm_loadu_ps(coefs[4]);
m_coefs.q[3] = _mm_loadu_ps(coefs[6]); m_coefs.q[3] = _mm_loadu_ps(coefs[6]);
#else #else
for (int i=0 ; i<8 ; ++i) for (int i = 0; i < 8; ++i) {
{ if (m_curSlewFrame != 0) {
if (m_curSlewFrame != 0)
{
m_oldCoefs.v[i][0] = m_coefs.v[i][0]; m_oldCoefs.v[i][0] = m_coefs.v[i][0];
m_oldCoefs.v[i][1] = m_coefs.v[i][1]; m_oldCoefs.v[i][1] = m_coefs.v[i][1];
} }
@ -140,15 +126,13 @@ public:
m_curSlewFrame = 0; m_curSlewFrame = 0;
} }
int16_t* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, int16_t* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, const int16_t* dataIn, int16_t* dataOut,
const int16_t* dataIn, int16_t* dataOut, size_t frames); size_t frames);
int32_t* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, int32_t* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, const int32_t* dataIn, int32_t* dataOut,
const int32_t* dataIn, int32_t* dataOut, size_t frames); size_t frames);
float* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, float* mixStereoSampleData(const AudioVoiceEngineMixInfo& info, const float* dataIn, float* dataOut, size_t frames);
const float* dataIn, float* dataOut, size_t frames);
bool isSilent() const bool isSilent() const {
{
if (m_curSlewFrame < m_slewFrames) if (m_curSlewFrame < m_slewFrames)
for (int i = 0; i < 8; ++i) for (int i = 0; i < 8; ++i)
if (m_oldCoefs.v[i][0] > FLT_EPSILON || m_oldCoefs.v[i][1] > FLT_EPSILON) if (m_oldCoefs.v[i][0] > FLT_EPSILON || m_oldCoefs.v[i][1] > FLT_EPSILON)
@ -160,5 +144,4 @@ public:
} }
}; };
} } // namespace boo

View File

@ -4,11 +4,9 @@
#include <immintrin.h> #include <immintrin.h>
namespace boo namespace boo {
{
typedef union typedef union {
{
float v[4]; float v[4];
#if __SSE__ #if __SSE__
__m128 q; __m128 q;
@ -19,14 +17,12 @@ typedef union
static constexpr TVectorUnion Min32Vec = {{INT32_MIN, INT32_MIN, INT32_MIN, INT32_MIN}}; static constexpr TVectorUnion Min32Vec = {{INT32_MIN, INT32_MIN, INT32_MIN, INT32_MIN}};
static constexpr TVectorUnion Max32Vec = {{INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX}}; static constexpr TVectorUnion Max32Vec = {{INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX}};
void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet) void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet) {
{
m_curSlewFrame = 0; m_curSlewFrame = 0;
m_slewFrames = 0; m_slewFrames = 0;
m_coefs.q[0] = _mm_xor_ps(m_coefs.q[0], m_coefs.q[0]); m_coefs.q[0] = _mm_xor_ps(m_coefs.q[0], m_coefs.q[0]);
m_coefs.q[1] = _mm_xor_ps(m_coefs.q[1], m_coefs.q[1]); m_coefs.q[1] = _mm_xor_ps(m_coefs.q[1], m_coefs.q[1]);
switch (acSet) switch (acSet) {
{
case AudioChannelSet::Stereo: case AudioChannelSet::Stereo:
case AudioChannelSet::Quad: case AudioChannelSet::Quad:
m_coefs.v[int(AudioChannel::FrontLeft)] = 1.0; m_coefs.v[int(AudioChannel::FrontLeft)] = 1.0;
@ -36,40 +32,32 @@ void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet)
case AudioChannelSet::Surround71: case AudioChannelSet::Surround71:
m_coefs.v[int(AudioChannel::FrontCenter)] = 1.0; m_coefs.v[int(AudioChannel::FrontCenter)] = 1.0;
break; break;
default: break; default:
break;
} }
} }
int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const int16_t* dataIn,
const int16_t* dataIn, int16_t* dataOut, size_t samples) int16_t* dataOut, size_t samples) {
{
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t s=0 ; s<samples ; ++s, ++dataIn) for (size_t s = 0; s < samples; ++s, ++dataIn) {
{ if (m_slewFrames && m_curSlewFrame < m_slewFrames) {
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames); double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t; double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{
*dataOut = Clamp16(*dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt)); *dataOut = Clamp16(*dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt));
++dataOut; ++dataOut;
} }
} }
++m_curSlewFrame; ++m_curSlewFrame;
} } else {
else for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{
*dataOut = Clamp16(*dataOut + *dataIn * m_coefs.v[int(ch)]); *dataOut = Clamp16(*dataOut + *dataIn * m_coefs.v[int(ch)]);
++dataOut; ++dataOut;
} }
@ -79,28 +67,23 @@ int16_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
return dataOut; return dataOut;
} }
int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const int32_t* dataIn,
const int32_t* dataIn, int32_t* dataOut, size_t samples) int32_t* dataOut, size_t samples) {
{
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t s=0 ; s<samples ; ++s, ++dataIn) for (size_t s = 0; s < samples; ++s, ++dataIn) {
{ if (m_slewFrames && m_curSlewFrame < m_slewFrames) {
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
float t = m_curSlewFrame / float(m_slewFrames); float t = m_curSlewFrame / float(m_slewFrames);
float omt = 1.f - t; float omt = 1.f - t;
switch (chmap.m_channelCount) switch (chmap.m_channelCount) {
{ case 2: {
case 2:
{
++m_curSlewFrame; ++m_curSlewFrame;
float t2 = m_curSlewFrame / float(m_slewFrames); float t2 = m_curSlewFrame / float(m_slewFrames);
float omt2 = 1.f - t2; float omt2 = 1.f - t2;
TVectorUnion coefs, samps; TVectorUnion coefs, samps;
coefs.q = _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(m_coefs.q[0], m_coefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)), coefs.q = _mm_add_ps(
_mm_set_ps(t, t, t2, t2)), _mm_mul_ps(_mm_shuffle_ps(m_coefs.q[0], m_coefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)), _mm_set_ps(t, t, t2, t2)),
_mm_mul_ps(_mm_shuffle_ps(m_oldCoefs.q[0], m_oldCoefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)), _mm_mul_ps(_mm_shuffle_ps(m_oldCoefs.q[0], m_oldCoefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)),
_mm_set_ps(omt, omt, omt2, omt2))); _mm_set_ps(omt, omt, omt2, omt2)));
samps.q = _mm_cvtepi32_ps(_mm_set_epi32(dataIn[1], dataIn[0], dataIn[1], dataIn[0])); samps.q = _mm_cvtepi32_ps(_mm_set_epi32(dataIn[1], dataIn[0], dataIn[1], dataIn[0]));
@ -114,11 +97,9 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
++dataIn; ++dataIn;
break; break;
} }
case 4: case 4: {
{
TVectorUnion coefs, samps; TVectorUnion coefs, samps;
coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[0], _mm_set1_ps(t)), coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[0], _mm_set1_ps(t)), _mm_mul_ps(m_oldCoefs.q[0], _mm_set1_ps(omt)));
_mm_mul_ps(m_oldCoefs.q[0], _mm_set1_ps(omt)));
samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn))); samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn)));
__m128i* out = reinterpret_cast<__m128i*>(dataOut); __m128i* out = reinterpret_cast<__m128i*>(dataOut);
@ -128,11 +109,9 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
dataOut += 4; dataOut += 4;
break; break;
} }
case 6: case 6: {
{
TVectorUnion coefs, samps; TVectorUnion coefs, samps;
coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[0], _mm_set1_ps(t)), coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[0], _mm_set1_ps(t)), _mm_mul_ps(m_oldCoefs.q[0], _mm_set1_ps(omt)));
_mm_mul_ps(m_oldCoefs.q[0], _mm_set1_ps(omt)));
samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn))); samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn)));
__m128i* out = reinterpret_cast<__m128i*>(dataOut); __m128i* out = reinterpret_cast<__m128i*>(dataOut);
@ -141,8 +120,7 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
dataOut += 4; dataOut += 4;
coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[1], _mm_set1_ps(t)), coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[1], _mm_set1_ps(t)), _mm_mul_ps(m_oldCoefs.q[1], _mm_set1_ps(omt)));
_mm_mul_ps(m_oldCoefs.q[1], _mm_set1_ps(omt)));
samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn))); samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn)));
out = reinterpret_cast<__m128i*>(dataOut); out = reinterpret_cast<__m128i*>(dataOut);
@ -153,11 +131,9 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
dataOut += 2; dataOut += 2;
break; break;
} }
case 8: case 8: {
{
TVectorUnion coefs, samps; TVectorUnion coefs, samps;
coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[0], _mm_set1_ps(t)), coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[0], _mm_set1_ps(t)), _mm_mul_ps(m_oldCoefs.q[0], _mm_set1_ps(omt)));
_mm_mul_ps(m_oldCoefs.q[0], _mm_set1_ps(omt)));
samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn))); samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn)));
__m128i* out = reinterpret_cast<__m128i*>(dataOut); __m128i* out = reinterpret_cast<__m128i*>(dataOut);
@ -166,8 +142,7 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
dataOut += 4; dataOut += 4;
coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[1], _mm_set1_ps(t)), coefs.q = _mm_add_ps(_mm_mul_ps(m_coefs.q[1], _mm_set1_ps(t)), _mm_mul_ps(m_oldCoefs.q[1], _mm_set1_ps(omt)));
_mm_mul_ps(m_oldCoefs.q[1], _mm_set1_ps(omt)));
samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn))); samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn)));
out = reinterpret_cast<__m128i*>(dataOut); out = reinterpret_cast<__m128i*>(dataOut);
@ -177,13 +152,10 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
dataOut += 4; dataOut += 4;
break; break;
} }
default: default: {
{ for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{
*dataOut = Clamp32(*dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt)); *dataOut = Clamp32(*dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt));
++dataOut; ++dataOut;
} }
@ -193,13 +165,9 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
} }
++m_curSlewFrame; ++m_curSlewFrame;
} } else {
else switch (chmap.m_channelCount) {
{ case 2: {
switch (chmap.m_channelCount)
{
case 2:
{
TVectorUnion coefs, samps; TVectorUnion coefs, samps;
coefs.q = _mm_shuffle_ps(m_coefs.q[0], m_coefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)); coefs.q = _mm_shuffle_ps(m_coefs.q[0], m_coefs.q[0], _MM_SHUFFLE(1, 0, 1, 0));
samps.q = _mm_cvtepi32_ps(_mm_set_epi32(dataIn[1], dataIn[0], dataIn[1], dataIn[0])); samps.q = _mm_cvtepi32_ps(_mm_set_epi32(dataIn[1], dataIn[0], dataIn[1], dataIn[0]));
@ -215,8 +183,7 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
++dataIn; ++dataIn;
break; break;
} }
case 4: case 4: {
{
TVectorUnion samps; TVectorUnion samps;
samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn))); samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn)));
@ -227,8 +194,7 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
dataOut += 4; dataOut += 4;
break; break;
} }
case 6: case 6: {
{
TVectorUnion samps; TVectorUnion samps;
samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn))); samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn)));
@ -248,8 +214,7 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
dataOut += 2; dataOut += 2;
break; break;
} }
case 8: case 8: {
{
TVectorUnion samps; TVectorUnion samps;
samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn))); samps.q = _mm_cvtepi32_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(dataIn)));
@ -268,13 +233,10 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
dataOut += 4; dataOut += 4;
break; break;
} }
default: default: {
{ for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{
*dataOut = Clamp32(*dataOut + *dataIn * m_coefs.v[int(ch)]); *dataOut = Clamp32(*dataOut + *dataIn * m_coefs.v[int(ch)]);
++dataOut; ++dataOut;
} }
@ -287,28 +249,23 @@ int32_t* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
return dataOut; return dataOut;
} }
float* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, float* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info, const float* dataIn, float* dataOut,
const float* dataIn, float* dataOut, size_t samples) size_t samples) {
{
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t s=0 ; s<samples ; ++s, ++dataIn) for (size_t s = 0; s < samples; ++s, ++dataIn) {
{ if (m_slewFrames && m_curSlewFrame < m_slewFrames) {
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
float t = m_curSlewFrame / float(m_slewFrames); float t = m_curSlewFrame / float(m_slewFrames);
float omt = 1.f - t; float omt = 1.f - t;
switch (chmap.m_channelCount) switch (chmap.m_channelCount) {
{ case 2: {
case 2:
{
++m_curSlewFrame; ++m_curSlewFrame;
float t2 = m_curSlewFrame / float(m_slewFrames); float t2 = m_curSlewFrame / float(m_slewFrames);
float omt2 = 1.f - t2; float omt2 = 1.f - t2;
TVectorUnion coefs, samps; TVectorUnion coefs, samps;
coefs.q = _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(m_coefs.q[0], m_coefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)), coefs.q = _mm_add_ps(
_mm_set_ps(t, t, t2, t2)), _mm_mul_ps(_mm_shuffle_ps(m_coefs.q[0], m_coefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)), _mm_set_ps(t, t, t2, t2)),
_mm_mul_ps(_mm_shuffle_ps(m_oldCoefs.q[0], m_oldCoefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)), _mm_mul_ps(_mm_shuffle_ps(m_oldCoefs.q[0], m_oldCoefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)),
_mm_set_ps(omt, omt, omt2, omt2))); _mm_set_ps(omt, omt, omt2, omt2)));
samps.q = _mm_loadu_ps(dataIn); samps.q = _mm_loadu_ps(dataIn);
@ -322,13 +279,10 @@ float* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
++dataIn; ++dataIn;
break; break;
} }
default: default: {
{ for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{
*dataOut = *dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt); *dataOut = *dataOut + *dataIn * (m_coefs.v[int(ch)] * t + m_oldCoefs.v[int(ch)] * omt);
++dataOut; ++dataOut;
} }
@ -338,13 +292,9 @@ float* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
} }
++m_curSlewFrame; ++m_curSlewFrame;
} } else {
else switch (chmap.m_channelCount) {
{ case 2: {
switch (chmap.m_channelCount)
{
case 2:
{
TVectorUnion coefs, samps; TVectorUnion coefs, samps;
coefs.q = _mm_shuffle_ps(m_coefs.q[0], m_coefs.q[0], _MM_SHUFFLE(1, 0, 1, 0)); coefs.q = _mm_shuffle_ps(m_coefs.q[0], m_coefs.q[0], _MM_SHUFFLE(1, 0, 1, 0));
samps.q = _mm_loadu_ps(dataIn); samps.q = _mm_loadu_ps(dataIn);
@ -358,13 +308,10 @@ float* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
++dataIn; ++dataIn;
break; break;
} }
default: default: {
{ for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{
*dataOut = *dataOut + *dataIn * m_coefs.v[int(ch)]; *dataOut = *dataOut + *dataIn * m_coefs.v[int(ch)];
++dataOut; ++dataOut;
} }
@ -377,16 +324,14 @@ float* AudioMatrixMono::mixMonoSampleData(const AudioVoiceEngineMixInfo& info,
return dataOut; return dataOut;
} }
void AudioMatrixStereo::setDefaultMatrixCoefficients(AudioChannelSet acSet) void AudioMatrixStereo::setDefaultMatrixCoefficients(AudioChannelSet acSet) {
{
m_curSlewFrame = 0; m_curSlewFrame = 0;
m_slewFrames = 0; m_slewFrames = 0;
m_coefs.q[0] = _mm_xor_ps(m_coefs.q[0], m_coefs.q[0]); m_coefs.q[0] = _mm_xor_ps(m_coefs.q[0], m_coefs.q[0]);
m_coefs.q[1] = _mm_xor_ps(m_coefs.q[1], m_coefs.q[1]); m_coefs.q[1] = _mm_xor_ps(m_coefs.q[1], m_coefs.q[1]);
m_coefs.q[2] = _mm_xor_ps(m_coefs.q[2], m_coefs.q[2]); m_coefs.q[2] = _mm_xor_ps(m_coefs.q[2], m_coefs.q[2]);
m_coefs.q[3] = _mm_xor_ps(m_coefs.q[3], m_coefs.q[3]); m_coefs.q[3] = _mm_xor_ps(m_coefs.q[3], m_coefs.q[3]);
switch (acSet) switch (acSet) {
{
case AudioChannelSet::Stereo: case AudioChannelSet::Stereo:
case AudioChannelSet::Quad: case AudioChannelSet::Quad:
m_coefs.v[int(AudioChannel::FrontLeft)][0] = 1.0; m_coefs.v[int(AudioChannel::FrontLeft)][0] = 1.0;
@ -397,45 +342,34 @@ void AudioMatrixStereo::setDefaultMatrixCoefficients(AudioChannelSet acSet)
m_coefs.v[int(AudioChannel::FrontLeft)][0] = 1.0; m_coefs.v[int(AudioChannel::FrontLeft)][0] = 1.0;
m_coefs.v[int(AudioChannel::FrontRight)][1] = 1.0; m_coefs.v[int(AudioChannel::FrontRight)][1] = 1.0;
break; break;
default: break; default:
break;
} }
} }
int16_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, int16_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, const int16_t* dataIn,
const int16_t* dataIn, int16_t* dataOut, size_t frames) int16_t* dataOut, size_t frames) {
{
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t f=0 ; f<frames ; ++f, dataIn += 2) for (size_t f = 0; f < frames; ++f, dataIn += 2) {
{ if (m_slewFrames && m_curSlewFrame < m_slewFrames) {
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames); double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t; double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{ *dataOut = Clamp16(*dataOut + *dataIn * (m_coefs.v[int(ch)][0] * t + m_oldCoefs.v[int(ch)][0] * omt) +
*dataOut = Clamp16(*dataOut +
*dataIn * (m_coefs.v[int(ch)][0] * t + m_oldCoefs.v[int(ch)][0] * omt) +
*dataIn * (m_coefs.v[int(ch)][1] * t + m_oldCoefs.v[int(ch)][1] * omt)); *dataIn * (m_coefs.v[int(ch)][1] * t + m_oldCoefs.v[int(ch)][1] * omt));
++dataOut; ++dataOut;
} }
} }
++m_curSlewFrame; ++m_curSlewFrame;
} } else {
else for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{ *dataOut = Clamp16(*dataOut + dataIn[0] * m_coefs.v[int(ch)][0] + dataIn[1] * m_coefs.v[int(ch)][1]);
*dataOut = Clamp16(*dataOut +
dataIn[0] * m_coefs.v[int(ch)][0] +
dataIn[1] * m_coefs.v[int(ch)][1]);
++dataOut; ++dataOut;
} }
} }
@ -444,41 +378,29 @@ int16_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& i
return dataOut; return dataOut;
} }
int32_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, int32_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, const int32_t* dataIn,
const int32_t* dataIn, int32_t* dataOut, size_t frames) int32_t* dataOut, size_t frames) {
{
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t f=0 ; f<frames ; ++f, dataIn += 2) for (size_t f = 0; f < frames; ++f, dataIn += 2) {
{ if (m_slewFrames && m_curSlewFrame < m_slewFrames) {
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames); double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t; double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{ *dataOut = Clamp32(*dataOut + *dataIn * (m_coefs.v[int(ch)][0] * t + m_oldCoefs.v[int(ch)][0] * omt) +
*dataOut = Clamp32(*dataOut +
*dataIn * (m_coefs.v[int(ch)][0] * t + m_oldCoefs.v[int(ch)][0] * omt) +
*dataIn * (m_coefs.v[int(ch)][1] * t + m_oldCoefs.v[int(ch)][1] * omt)); *dataIn * (m_coefs.v[int(ch)][1] * t + m_oldCoefs.v[int(ch)][1] * omt));
++dataOut; ++dataOut;
} }
} }
++m_curSlewFrame; ++m_curSlewFrame;
} } else {
else for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{ *dataOut = Clamp32(*dataOut + dataIn[0] * m_coefs.v[int(ch)][0] + dataIn[1] * m_coefs.v[int(ch)][1]);
*dataOut = Clamp32(*dataOut +
dataIn[0] * m_coefs.v[int(ch)][0] +
dataIn[1] * m_coefs.v[int(ch)][1]);
++dataOut; ++dataOut;
} }
} }
@ -487,41 +409,29 @@ int32_t* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& i
return dataOut; return dataOut;
} }
float* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, float* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& info, const float* dataIn, float* dataOut,
const float* dataIn, float* dataOut, size_t frames) size_t frames) {
{
const ChannelMap& chmap = info.m_channelMap; const ChannelMap& chmap = info.m_channelMap;
for (size_t f=0 ; f<frames ; ++f, dataIn += 2) for (size_t f = 0; f < frames; ++f, dataIn += 2) {
{ if (m_slewFrames && m_curSlewFrame < m_slewFrames) {
if (m_slewFrames && m_curSlewFrame < m_slewFrames)
{
double t = m_curSlewFrame / double(m_slewFrames); double t = m_curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t; double omt = 1.0 - t;
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c) for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{ *dataOut = *dataOut + *dataIn * (m_coefs.v[int(ch)][0] * t + m_oldCoefs.v[int(ch)][0] * omt) +
*dataOut = *dataOut +
*dataIn * (m_coefs.v[int(ch)][0] * t + m_oldCoefs.v[int(ch)][0] * omt) +
*dataIn * (m_coefs.v[int(ch)][1] * t + m_oldCoefs.v[int(ch)][1] * omt); *dataIn * (m_coefs.v[int(ch)][1] * t + m_oldCoefs.v[int(ch)][1] * omt);
++dataOut; ++dataOut;
} }
} }
++m_curSlewFrame; ++m_curSlewFrame;
} } else {
else for (unsigned c = 0; c < chmap.m_channelCount; ++c) {
{
for (unsigned c=0 ; c<chmap.m_channelCount ; ++c)
{
AudioChannel ch = chmap.m_channels[c]; AudioChannel ch = chmap.m_channels[c];
if (ch != AudioChannel::Unknown) if (ch != AudioChannel::Unknown) {
{ *dataOut = *dataOut + dataIn[0] * m_coefs.v[int(ch)][0] + dataIn[1] * m_coefs.v[int(ch)][1];
*dataOut = *dataOut +
dataIn[0] * m_coefs.v[int(ch)][0] +
dataIn[1] * m_coefs.v[int(ch)][1];
++dataOut; ++dataOut;
} }
} }
@ -530,5 +440,4 @@ float* AudioMatrixStereo::mixStereoSampleData(const AudioVoiceEngineMixInfo& inf
return dataOut; return dataOut;
} }
} } // namespace boo

View File

@ -7,53 +7,41 @@
#undef min #undef min
#undef max #undef max
namespace boo namespace boo {
{
AudioSubmix::AudioSubmix(BaseAudioVoiceEngine& root, IAudioSubmixCallback* cb, int busId, bool mainOut) AudioSubmix::AudioSubmix(BaseAudioVoiceEngine& root, IAudioSubmixCallback* cb, int busId, bool mainOut)
: ListNode<AudioSubmix, BaseAudioVoiceEngine*, IAudioSubmix>(&root), m_busId(busId), m_mainOut(mainOut), m_cb(cb) : ListNode<AudioSubmix, BaseAudioVoiceEngine*, IAudioSubmix>(&root), m_busId(busId), m_mainOut(mainOut), m_cb(cb) {
{
if (mainOut) if (mainOut)
setSendLevel(m_head->m_mainSubmix.get(), 1.f, false); setSendLevel(m_head->m_mainSubmix.get(), 1.f, false);
} }
AudioSubmix::~AudioSubmix() AudioSubmix::~AudioSubmix() { m_head->m_submixesDirty = true; }
{
m_head->m_submixesDirty = true;
}
AudioSubmix*& AudioSubmix::_getHeadPtr(BaseAudioVoiceEngine* head) { return head->m_submixHead; } AudioSubmix*& AudioSubmix::_getHeadPtr(BaseAudioVoiceEngine* head) { return head->m_submixHead; }
std::unique_lock<std::recursive_mutex> AudioSubmix::_getHeadLock(BaseAudioVoiceEngine* head) std::unique_lock<std::recursive_mutex> AudioSubmix::_getHeadLock(BaseAudioVoiceEngine* head) {
{ return std::unique_lock<std::recursive_mutex>{head->m_dataMutex}; } return std::unique_lock<std::recursive_mutex>{head->m_dataMutex};
std::unique_lock<std::recursive_mutex> AudioSubmix::destructorLock() }
{ return std::unique_lock<std::recursive_mutex>{m_head->m_dataMutex}; } std::unique_lock<std::recursive_mutex> AudioSubmix::destructorLock() {
return std::unique_lock<std::recursive_mutex>{m_head->m_dataMutex};
bool AudioSubmix::_isDirectDependencyOf(AudioSubmix* send)
{
return m_sendGains.find(send) != m_sendGains.cend();
} }
bool AudioSubmix::_mergeC3(std::list<AudioSubmix*>& output, bool AudioSubmix::_isDirectDependencyOf(AudioSubmix* send) { return m_sendGains.find(send) != m_sendGains.cend(); }
std::vector<std::list<AudioSubmix*>>& lists)
{ bool AudioSubmix::_mergeC3(std::list<AudioSubmix*>& output, std::vector<std::list<AudioSubmix*>>& lists) {
for (auto outerIt = lists.begin() ; outerIt != lists.cend() ; ++outerIt) for (auto outerIt = lists.begin(); outerIt != lists.cend(); ++outerIt) {
{
if (outerIt->empty()) if (outerIt->empty())
continue; continue;
AudioSubmix* smx = outerIt->front(); AudioSubmix* smx = outerIt->front();
bool found = false; bool found = false;
for (auto innerIt = lists.begin() ; innerIt != lists.cend() ; ++innerIt) for (auto innerIt = lists.begin(); innerIt != lists.cend(); ++innerIt) {
{
if (innerIt->empty() || outerIt == innerIt) if (innerIt->empty() || outerIt == innerIt)
continue; continue;
if (smx == innerIt->front()) if (smx == innerIt->front()) {
{
innerIt->pop_front(); innerIt->pop_front();
found = true; found = true;
} }
} }
if (found) if (found) {
{
outerIt->pop_front(); outerIt->pop_front();
output.push_back(smx); output.push_back(smx);
return true; return true;
@ -62,12 +50,10 @@ bool AudioSubmix::_mergeC3(std::list<AudioSubmix*>& output,
return false; return false;
} }
std::list<AudioSubmix*> AudioSubmix::_linearizeC3() std::list<AudioSubmix*> AudioSubmix::_linearizeC3() {
{
std::vector<std::list<AudioSubmix*>> lists = {{}}; std::vector<std::list<AudioSubmix*>> lists = {{}};
if (m_head->m_submixHead) if (m_head->m_submixHead)
for (AudioSubmix& smx : *m_head->m_submixHead) for (AudioSubmix& smx : *m_head->m_submixHead) {
{
if (&smx == this) if (&smx == this)
continue; continue;
if (smx._isDirectDependencyOf(this)) if (smx._isDirectDependencyOf(this))
@ -83,8 +69,7 @@ std::list<AudioSubmix*> AudioSubmix::_linearizeC3()
} }
template <typename T> template <typename T>
void AudioSubmix::_zeroFill() void AudioSubmix::_zeroFill() {
{
if (_getScratch<T>().size()) if (_getScratch<T>().size())
std::fill(_getScratch<T>().begin(), _getScratch<T>().end(), 0); std::fill(_getScratch<T>().begin(), _getScratch<T>().end(), 0);
} }
@ -94,8 +79,7 @@ template void AudioSubmix::_zeroFill<int32_t>();
template void AudioSubmix::_zeroFill<float>(); template void AudioSubmix::_zeroFill<float>();
template <typename T> template <typename T>
T* AudioSubmix::_getMergeBuf(size_t frames) T* AudioSubmix::_getMergeBuf(size_t frames) {
{
if (_getRedirect<T>()) if (_getRedirect<T>())
return _getRedirect<T>(); return _getRedirect<T>();
@ -111,14 +95,10 @@ template int32_t* AudioSubmix::_getMergeBuf<int32_t>(size_t frames);
template float* AudioSubmix::_getMergeBuf<float>(size_t frames); template float* AudioSubmix::_getMergeBuf<float>(size_t frames);
template <typename T> template <typename T>
static inline T ClampInt(float in) static inline T ClampInt(float in) {
{ if (std::is_floating_point<T>()) {
if (std::is_floating_point<T>())
{
return in; // Allow subsequent mixing stages to work with over-saturated values return in; // Allow subsequent mixing stages to work with over-saturated values
} } else {
else
{
constexpr T MAX = std::numeric_limits<T>::max(); constexpr T MAX = std::numeric_limits<T>::max();
constexpr T MIN = std::numeric_limits<T>::min(); constexpr T MIN = std::numeric_limits<T>::min();
@ -132,19 +112,15 @@ static inline T ClampInt(float in)
} }
template <typename T> template <typename T>
size_t AudioSubmix::_pumpAndMix(size_t frames) size_t AudioSubmix::_pumpAndMix(size_t frames) {
{
const ChannelMap& chMap = m_head->clientMixInfo().m_channelMap; const ChannelMap& chMap = m_head->clientMixInfo().m_channelMap;
size_t chanCount = chMap.m_channelCount; size_t chanCount = chMap.m_channelCount;
if (_getRedirect<T>()) if (_getRedirect<T>()) {
{
if (m_cb && m_cb->canApplyEffect()) if (m_cb && m_cb->canApplyEffect())
m_cb->applyEffect(_getRedirect<T>(), frames, chMap, m_head->mixInfo().m_sampleRate); m_cb->applyEffect(_getRedirect<T>(), frames, chMap, m_head->mixInfo().m_sampleRate);
_getRedirect<T>() += chanCount * frames; _getRedirect<T>() += chanCount * frames;
} } else {
else
{
size_t sampleCount = frames * chanCount; size_t sampleCount = frames * chanCount;
if (_getScratch<T>().size() < sampleCount) if (_getScratch<T>().size() < sampleCount)
_getScratch<T>().resize(sampleCount); _getScratch<T>().resize(sampleCount);
@ -152,33 +128,26 @@ size_t AudioSubmix::_pumpAndMix(size_t frames)
m_cb->applyEffect(_getScratch<T>().data(), frames, chMap, m_head->mixInfo().m_sampleRate); m_cb->applyEffect(_getScratch<T>().data(), frames, chMap, m_head->mixInfo().m_sampleRate);
size_t curSlewFrame = m_slewFrames; size_t curSlewFrame = m_slewFrames;
for (auto& smx : m_sendGains) for (auto& smx : m_sendGains) {
{
curSlewFrame = m_curSlewFrame; curSlewFrame = m_curSlewFrame;
AudioSubmix& sm = *reinterpret_cast<AudioSubmix*>(smx.first); AudioSubmix& sm = *reinterpret_cast<AudioSubmix*>(smx.first);
auto it = _getScratch<T>().begin(); auto it = _getScratch<T>().begin();
T* dataOut = sm._getMergeBuf<T>(frames); T* dataOut = sm._getMergeBuf<T>(frames);
for (size_t f=0 ; f<frames ; ++f) for (size_t f = 0; f < frames; ++f) {
{ if (m_slewFrames && curSlewFrame < m_slewFrames) {
if (m_slewFrames && curSlewFrame < m_slewFrames)
{
double t = curSlewFrame / double(m_slewFrames); double t = curSlewFrame / double(m_slewFrames);
double omt = 1.0 - t; double omt = 1.0 - t;
for (unsigned c=0 ; c<chanCount ; ++c) for (unsigned c = 0; c < chanCount; ++c) {
{
*dataOut = ClampInt<T>(*dataOut + *it * (smx.second[1] * t + smx.second[0] * omt)); *dataOut = ClampInt<T>(*dataOut + *it * (smx.second[1] * t + smx.second[0] * omt));
++it; ++it;
++dataOut; ++dataOut;
} }
++curSlewFrame; ++curSlewFrame;
} } else {
else for (unsigned c = 0; c < chanCount; ++c) {
{
for (unsigned c=0 ; c<chanCount ; ++c)
{
*dataOut = ClampInt<T>(*dataOut + *it * smx.second[1]); *dataOut = ClampInt<T>(*dataOut + *it * smx.second[1]);
++it; ++it;
++dataOut; ++dataOut;
@ -196,25 +165,21 @@ template size_t AudioSubmix::_pumpAndMix<int16_t>(size_t frames);
template size_t AudioSubmix::_pumpAndMix<int32_t>(size_t frames); template size_t AudioSubmix::_pumpAndMix<int32_t>(size_t frames);
template size_t AudioSubmix::_pumpAndMix<float>(size_t frames); template size_t AudioSubmix::_pumpAndMix<float>(size_t frames);
void AudioSubmix::_resetOutputSampleRate() void AudioSubmix::_resetOutputSampleRate() {
{
if (m_cb) if (m_cb)
m_cb->resetOutputSampleRate(m_head->mixInfo().m_sampleRate); m_cb->resetOutputSampleRate(m_head->mixInfo().m_sampleRate);
} }
void AudioSubmix::resetSendLevels() void AudioSubmix::resetSendLevels() {
{
if (m_sendGains.empty()) if (m_sendGains.empty())
return; return;
m_sendGains.clear(); m_sendGains.clear();
m_head->m_submixesDirty = true; m_head->m_submixesDirty = true;
} }
void AudioSubmix::setSendLevel(IAudioSubmix* submix, float level, bool slew) void AudioSubmix::setSendLevel(IAudioSubmix* submix, float level, bool slew) {
{
auto search = m_sendGains.find(submix); auto search = m_sendGains.find(submix);
if (search == m_sendGains.cend()) if (search == m_sendGains.cend()) {
{
search = m_sendGains.emplace(submix, std::array<float, 2>{1.f, 1.f}).first; search = m_sendGains.emplace(submix, std::array<float, 2>{1.f, 1.f}).first;
m_head->m_submixesDirty = true; m_head->m_submixesDirty = true;
} }
@ -226,20 +191,12 @@ void AudioSubmix::setSendLevel(IAudioSubmix* submix, float level, bool slew)
search->second[1] = level; search->second[1] = level;
} }
const AudioVoiceEngineMixInfo& AudioSubmix::mixInfo() const const AudioVoiceEngineMixInfo& AudioSubmix::mixInfo() const { return m_head->mixInfo(); }
{
return m_head->mixInfo();
}
double AudioSubmix::getSampleRate() const double AudioSubmix::getSampleRate() const { return mixInfo().m_sampleRate; }
{
return mixInfo().m_sampleRate;
}
SubmixFormat AudioSubmix::getSampleFormat() const SubmixFormat AudioSubmix::getSampleFormat() const {
{ switch (mixInfo().m_sampleFormat) {
switch (mixInfo().m_sampleFormat)
{
case SOXR_INT16_I: case SOXR_INT16_I:
default: default:
return SubmixFormat::Int16; return SubmixFormat::Int16;
@ -250,4 +207,4 @@ SubmixFormat AudioSubmix::getSampleFormat() const
} }
} }
} } // namespace boo

View File

@ -15,15 +15,13 @@ struct AudioUnitVoiceEngine;
struct VSTVoiceEngine; struct VSTVoiceEngine;
struct WAVOutVoiceEngine; struct WAVOutVoiceEngine;
namespace boo namespace boo {
{
class BaseAudioVoiceEngine; class BaseAudioVoiceEngine;
class AudioVoice; class AudioVoice;
struct AudioVoiceEngineMixInfo; struct AudioVoiceEngineMixInfo;
/* Output gains for each mix-send/channel */ /* Output gains for each mix-send/channel */
class AudioSubmix : public ListNode<AudioSubmix, BaseAudioVoiceEngine*, IAudioSubmix> class AudioSubmix : public ListNode<AudioSubmix, BaseAudioVoiceEngine*, IAudioSubmix> {
{
friend class BaseAudioVoiceEngine; friend class BaseAudioVoiceEngine;
friend class AudioVoiceMono; friend class AudioVoiceMono;
friend class AudioVoiceStereo; friend class AudioVoiceStereo;
@ -50,28 +48,32 @@ class AudioSubmix : public ListNode<AudioSubmix, BaseAudioVoiceEngine*, IAudioSu
std::vector<int16_t> m_scratch16; std::vector<int16_t> m_scratch16;
std::vector<int32_t> m_scratch32; std::vector<int32_t> m_scratch32;
std::vector<float> m_scratchFlt; std::vector<float> m_scratchFlt;
template <typename T> std::vector<T>& _getScratch(); template <typename T>
std::vector<T>& _getScratch();
/* Override scratch buffers with alternate destination */ /* Override scratch buffers with alternate destination */
int16_t* m_redirect16 = nullptr; int16_t* m_redirect16 = nullptr;
int32_t* m_redirect32 = nullptr; int32_t* m_redirect32 = nullptr;
float* m_redirectFlt = nullptr; float* m_redirectFlt = nullptr;
template <typename T> T*& _getRedirect(); template <typename T>
T*& _getRedirect();
/* C3-linearization support (to mitigate a potential diamond problem on 'clever' submix routes) */ /* C3-linearization support (to mitigate a potential diamond problem on 'clever' submix routes) */
bool _isDirectDependencyOf(AudioSubmix* send); bool _isDirectDependencyOf(AudioSubmix* send);
std::list<AudioSubmix*> _linearizeC3(); std::list<AudioSubmix*> _linearizeC3();
static bool _mergeC3(std::list<AudioSubmix*>& output, static bool _mergeC3(std::list<AudioSubmix*>& output, std::vector<std::list<AudioSubmix*>>& lists);
std::vector<std::list<AudioSubmix*>>& lists);
/* Fill scratch buffers with silence for new mix cycle */ /* Fill scratch buffers with silence for new mix cycle */
template <typename T> void _zeroFill(); template <typename T>
void _zeroFill();
/* Receive audio from a single voice / submix */ /* Receive audio from a single voice / submix */
template <typename T> T* _getMergeBuf(size_t frames); template <typename T>
T* _getMergeBuf(size_t frames);
/* Mix scratch buffers into sends */ /* Mix scratch buffers into sends */
template <typename T> size_t _pumpAndMix(size_t frames); template <typename T>
size_t _pumpAndMix(size_t frames);
void _resetOutputSampleRate(); void _resetOutputSampleRate();
@ -90,13 +92,30 @@ public:
SubmixFormat getSampleFormat() const; SubmixFormat getSampleFormat() const;
}; };
template <> inline std::vector<int16_t>& AudioSubmix::_getScratch() { return m_scratch16; } template <>
template <> inline std::vector<int32_t>& AudioSubmix::_getScratch() { return m_scratch32; } inline std::vector<int16_t>& AudioSubmix::_getScratch() {
template <> inline std::vector<float>& AudioSubmix::_getScratch() { return m_scratchFlt; } return m_scratch16;
}
template <> inline int16_t*& AudioSubmix::_getRedirect<int16_t>() { return m_redirect16; } template <>
template <> inline int32_t*& AudioSubmix::_getRedirect<int32_t>() { return m_redirect32; } inline std::vector<int32_t>& AudioSubmix::_getScratch() {
template <> inline float*& AudioSubmix::_getRedirect<float>() { return m_redirectFlt; } return m_scratch32;
}
template <>
inline std::vector<float>& AudioSubmix::_getScratch() {
return m_scratchFlt;
} }
template <>
inline int16_t*& AudioSubmix::_getRedirect<int16_t>() {
return m_redirect16;
}
template <>
inline int32_t*& AudioSubmix::_getRedirect<int32_t>() {
return m_redirect32;
}
template <>
inline float*& AudioSubmix::_getRedirect<float>() {
return m_redirectFlt;
}
} // namespace boo

View File

@ -3,37 +3,30 @@
#include "logvisor/logvisor.hpp" #include "logvisor/logvisor.hpp"
#include <cmath> #include <cmath>
namespace boo namespace boo {
{
static logvisor::Module Log("boo::AudioVoice"); static logvisor::Module Log("boo::AudioVoice");
static AudioMatrixMono DefaultMonoMtx; static AudioMatrixMono DefaultMonoMtx;
static AudioMatrixStereo DefaultStereoMtx; static AudioMatrixStereo DefaultStereoMtx;
AudioVoice::AudioVoice(BaseAudioVoiceEngine& root, AudioVoice::AudioVoice(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, bool dynamicRate)
IAudioVoiceCallback* cb, bool dynamicRate) : ListNode<AudioVoice, BaseAudioVoiceEngine*, IAudioVoice>(&root), m_cb(cb), m_dynamicRate(dynamicRate) {}
: ListNode<AudioVoice, BaseAudioVoiceEngine*, IAudioVoice>(&root), m_cb(cb), m_dynamicRate(dynamicRate)
{}
AudioVoice::~AudioVoice() AudioVoice::~AudioVoice() { soxr_delete(m_src); }
{
soxr_delete(m_src);
}
AudioVoice*& AudioVoice::_getHeadPtr(BaseAudioVoiceEngine* head) { return head->m_voiceHead; } AudioVoice*& AudioVoice::_getHeadPtr(BaseAudioVoiceEngine* head) { return head->m_voiceHead; }
std::unique_lock<std::recursive_mutex> AudioVoice::_getHeadLock(BaseAudioVoiceEngine* head) std::unique_lock<std::recursive_mutex> AudioVoice::_getHeadLock(BaseAudioVoiceEngine* head) {
{ return std::unique_lock<std::recursive_mutex>{head->m_dataMutex}; } return std::unique_lock<std::recursive_mutex>{head->m_dataMutex};
std::unique_lock<std::recursive_mutex> AudioVoice::destructorLock() }
{ return std::unique_lock<std::recursive_mutex>{m_head->m_dataMutex}; } std::unique_lock<std::recursive_mutex> AudioVoice::destructorLock() {
return std::unique_lock<std::recursive_mutex>{m_head->m_dataMutex};
}
void AudioVoice::_setPitchRatio(double ratio, bool slew) void AudioVoice::_setPitchRatio(double ratio, bool slew) {
{ if (m_dynamicRate) {
if (m_dynamicRate)
{
m_sampleRatio = ratio * m_sampleRateIn / m_sampleRateOut; m_sampleRatio = ratio * m_sampleRateIn / m_sampleRateOut;
soxr_error_t err = soxr_set_io_ratio(m_src, m_sampleRatio, slew ? m_head->m_5msFrames : 0); soxr_error_t err = soxr_set_io_ratio(m_src, m_sampleRatio, slew ? m_head->m_5msFrames : 0);
if (err) if (err) {
{
Log.report(logvisor::Fatal, "unable to set resampler rate: %s", soxr_strerror(err)); Log.report(logvisor::Fatal, "unable to set resampler rate: %s", soxr_strerror(err));
m_setPitchRatio = false; m_setPitchRatio = false;
return; return;
@ -42,46 +35,34 @@ void AudioVoice::_setPitchRatio(double ratio, bool slew)
m_setPitchRatio = false; m_setPitchRatio = false;
} }
void AudioVoice::_midUpdate() void AudioVoice::_midUpdate() {
{
if (m_resetSampleRate) if (m_resetSampleRate)
_resetSampleRate(m_deferredSampleRate); _resetSampleRate(m_deferredSampleRate);
if (m_setPitchRatio) if (m_setPitchRatio)
_setPitchRatio(m_pitchRatio, m_slew); _setPitchRatio(m_pitchRatio, m_slew);
} }
void AudioVoice::setPitchRatio(double ratio, bool slew) void AudioVoice::setPitchRatio(double ratio, bool slew) {
{
m_setPitchRatio = true; m_setPitchRatio = true;
m_pitchRatio = ratio; m_pitchRatio = ratio;
m_slew = slew; m_slew = slew;
} }
void AudioVoice::resetSampleRate(double sampleRate) void AudioVoice::resetSampleRate(double sampleRate) {
{
m_resetSampleRate = true; m_resetSampleRate = true;
m_deferredSampleRate = sampleRate; m_deferredSampleRate = sampleRate;
} }
void AudioVoice::start() void AudioVoice::start() { m_running = true; }
{
m_running = true;
}
void AudioVoice::stop() void AudioVoice::stop() { m_running = false; }
{
m_running = false;
}
AudioVoiceMono::AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, AudioVoiceMono::AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, double sampleRate, bool dynamicRate)
double sampleRate, bool dynamicRate) : AudioVoice(root, cb, dynamicRate) {
: AudioVoice(root, cb, dynamicRate)
{
_resetSampleRate(sampleRate); _resetSampleRate(sampleRate);
} }
void AudioVoiceMono::_resetSampleRate(double sampleRate) void AudioVoiceMono::_resetSampleRate(double sampleRate) {
{
soxr_delete(m_src); soxr_delete(m_src);
double rateOut = m_head->mixInfo().m_sampleRate; double rateOut = m_head->mixInfo().m_sampleRate;
@ -90,11 +71,9 @@ void AudioVoiceMono::_resetSampleRate(double sampleRate)
soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, m_dynamicRate ? SOXR_VR : 0); soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, m_dynamicRate ? SOXR_VR : 0);
soxr_error_t err; soxr_error_t err;
m_src = soxr_create(sampleRate, rateOut, 1, m_src = soxr_create(sampleRate, rateOut, 1, &err, &ioSpec, &qSpec, nullptr);
&err, &ioSpec, &qSpec, nullptr);
if (err) if (err) {
{
Log.report(logvisor::Fatal, "unable to create soxr resampler: %s", soxr_strerror(err)); Log.report(logvisor::Fatal, "unable to create soxr resampler: %s", soxr_strerror(err));
m_resetSampleRate = false; m_resetSampleRate = false;
return; return;
@ -108,39 +87,31 @@ void AudioVoiceMono::_resetSampleRate(double sampleRate)
m_resetSampleRate = false; m_resetSampleRate = false;
} }
size_t AudioVoiceMono::SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t frames) size_t AudioVoiceMono::SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t frames) {
{
std::vector<int16_t>& scratchIn = ctx->m_head->m_scratchIn; std::vector<int16_t>& scratchIn = ctx->m_head->m_scratchIn;
if (scratchIn.size() < frames) if (scratchIn.size() < frames)
scratchIn.resize(frames); scratchIn.resize(frames);
*data = scratchIn.data(); *data = scratchIn.data();
if (ctx->m_silentOut) if (ctx->m_silentOut) {
{
memset(scratchIn.data(), 0, frames * 2); memset(scratchIn.data(), 0, frames * 2);
return frames; return frames;
} } else
else
return ctx->m_cb->supplyAudio(*ctx, frames, scratchIn.data()); return ctx->m_cb->supplyAudio(*ctx, frames, scratchIn.data());
} }
bool AudioVoiceMono::isSilent() const bool AudioVoiceMono::isSilent() const {
{ if (m_sendMatrices.size()) {
if (m_sendMatrices.size())
{
for (auto& mtx : m_sendMatrices) for (auto& mtx : m_sendMatrices)
if (!mtx.second.isSilent()) if (!mtx.second.isSilent())
return false; return false;
return true; return true;
} } else {
else
{
return DefaultMonoMtx.isSilent(); return DefaultMonoMtx.isSilent();
} }
} }
template <typename T> template <typename T>
size_t AudioVoiceMono::_pumpAndMix(size_t frames) size_t AudioVoiceMono::_pumpAndMix(size_t frames) {
{
auto& scratchPre = m_head->_getScratchPre<T>(); auto& scratchPre = m_head->_getScratchPre<T>();
if (scratchPre.size() < frames) if (scratchPre.size() < frames)
scratchPre.resize(frames + 2); scratchPre.resize(frames + 2);
@ -153,8 +124,7 @@ size_t AudioVoiceMono::_pumpAndMix(size_t frames)
m_cb->preSupplyAudio(*this, dt); m_cb->preSupplyAudio(*this, dt);
_midUpdate(); _midUpdate();
if (isSilent()) if (isSilent()) {
{
int16_t* dummy; int16_t* dummy;
SRCCallback(this, &dummy, size_t(std::ceil(frames * m_sampleRatio))); SRCCallback(this, &dummy, size_t(std::ceil(frames * m_sampleRatio)));
return 0; return 0;
@ -162,38 +132,29 @@ size_t AudioVoiceMono::_pumpAndMix(size_t frames)
size_t oDone = soxr_output(m_src, scratchPre.data(), frames); size_t oDone = soxr_output(m_src, scratchPre.data(), frames);
if (oDone) if (oDone) {
{ if (m_sendMatrices.size()) {
if (m_sendMatrices.size()) for (auto& mtx : m_sendMatrices) {
{
for (auto& mtx : m_sendMatrices)
{
AudioSubmix& smx = *reinterpret_cast<AudioSubmix*>(mtx.first); AudioSubmix& smx = *reinterpret_cast<AudioSubmix*>(mtx.first);
m_cb->routeAudio(oDone, 1, dt, smx.m_busId, scratchPre.data(), scratchPost.data()); m_cb->routeAudio(oDone, 1, dt, smx.m_busId, scratchPre.data(), scratchPost.data());
mtx.second.mixMonoSampleData(m_head->clientMixInfo(), scratchPost.data(), mtx.second.mixMonoSampleData(m_head->clientMixInfo(), scratchPost.data(), smx._getMergeBuf<T>(oDone), oDone);
smx._getMergeBuf<T>(oDone), oDone);
} }
} } else {
else
{
AudioSubmix& smx = *m_head->m_mainSubmix; AudioSubmix& smx = *m_head->m_mainSubmix;
m_cb->routeAudio(oDone, 1, dt, m_head->m_mainSubmix->m_busId, scratchPre.data(), scratchPost.data()); m_cb->routeAudio(oDone, 1, dt, m_head->m_mainSubmix->m_busId, scratchPre.data(), scratchPost.data());
DefaultMonoMtx.mixMonoSampleData(m_head->clientMixInfo(), scratchPost.data(), DefaultMonoMtx.mixMonoSampleData(m_head->clientMixInfo(), scratchPost.data(), smx._getMergeBuf<T>(oDone), oDone);
smx._getMergeBuf<T>(oDone), oDone);
} }
} }
return oDone; return oDone;
} }
void AudioVoiceMono::resetChannelLevels() void AudioVoiceMono::resetChannelLevels() {
{
m_head->m_submixesDirty = true; m_head->m_submixesDirty = true;
m_sendMatrices.clear(); m_sendMatrices.clear();
} }
void AudioVoiceMono::setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew) void AudioVoiceMono::setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew) {
{
if (!submix) if (!submix)
submix = m_head->m_mainSubmix.get(); submix = m_head->m_mainSubmix.get();
@ -203,19 +164,9 @@ void AudioVoiceMono::setMonoChannelLevels(IAudioSubmix* submix, const float coef
search->second.setMatrixCoefficients(coefs, slew ? m_head->m_5msFrames : 0); search->second.setMatrixCoefficients(coefs, slew ? m_head->m_5msFrames : 0);
} }
void AudioVoiceMono::setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew) void AudioVoiceMono::setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew) {
{ float newCoefs[8] = {coefs[0][0], coefs[1][0], coefs[2][0], coefs[3][0],
float newCoefs[8] = coefs[4][0], coefs[5][0], coefs[6][0], coefs[7][0]};
{
coefs[0][0],
coefs[1][0],
coefs[2][0],
coefs[3][0],
coefs[4][0],
coefs[5][0],
coefs[6][0],
coefs[7][0]
};
if (!submix) if (!submix)
submix = m_head->m_mainSubmix.get(); submix = m_head->m_mainSubmix.get();
@ -226,15 +177,13 @@ void AudioVoiceMono::setStereoChannelLevels(IAudioSubmix* submix, const float co
search->second.setMatrixCoefficients(newCoefs, slew ? m_head->m_5msFrames : 0); search->second.setMatrixCoefficients(newCoefs, slew ? m_head->m_5msFrames : 0);
} }
AudioVoiceStereo::AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, AudioVoiceStereo::AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, double sampleRate,
double sampleRate, bool dynamicRate) bool dynamicRate)
: AudioVoice(root, cb, dynamicRate) : AudioVoice(root, cb, dynamicRate) {
{
_resetSampleRate(sampleRate); _resetSampleRate(sampleRate);
} }
void AudioVoiceStereo::_resetSampleRate(double sampleRate) void AudioVoiceStereo::_resetSampleRate(double sampleRate) {
{
soxr_delete(m_src); soxr_delete(m_src);
double rateOut = m_head->mixInfo().m_sampleRate; double rateOut = m_head->mixInfo().m_sampleRate;
@ -243,11 +192,9 @@ void AudioVoiceStereo::_resetSampleRate(double sampleRate)
soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, m_dynamicRate ? SOXR_VR : 0); soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, m_dynamicRate ? SOXR_VR : 0);
soxr_error_t err; soxr_error_t err;
m_src = soxr_create(sampleRate, rateOut, 2, m_src = soxr_create(sampleRate, rateOut, 2, &err, &ioSpec, &qSpec, nullptr);
&err, &ioSpec, &qSpec, nullptr);
if (!m_src) if (!m_src) {
{
Log.report(logvisor::Fatal, "unable to create soxr resampler: %s", soxr_strerror(err)); Log.report(logvisor::Fatal, "unable to create soxr resampler: %s", soxr_strerror(err));
m_resetSampleRate = false; m_resetSampleRate = false;
return; return;
@ -261,40 +208,32 @@ void AudioVoiceStereo::_resetSampleRate(double sampleRate)
m_resetSampleRate = false; m_resetSampleRate = false;
} }
size_t AudioVoiceStereo::SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size_t frames) size_t AudioVoiceStereo::SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size_t frames) {
{
std::vector<int16_t>& scratchIn = ctx->m_head->m_scratchIn; std::vector<int16_t>& scratchIn = ctx->m_head->m_scratchIn;
size_t samples = frames * 2; size_t samples = frames * 2;
if (scratchIn.size() < samples) if (scratchIn.size() < samples)
scratchIn.resize(samples); scratchIn.resize(samples);
*data = scratchIn.data(); *data = scratchIn.data();
if (ctx->m_silentOut) if (ctx->m_silentOut) {
{
memset(scratchIn.data(), 0, samples * 2); memset(scratchIn.data(), 0, samples * 2);
return frames; return frames;
} } else
else
return ctx->m_cb->supplyAudio(*ctx, frames, scratchIn.data()); return ctx->m_cb->supplyAudio(*ctx, frames, scratchIn.data());
} }
bool AudioVoiceStereo::isSilent() const bool AudioVoiceStereo::isSilent() const {
{ if (m_sendMatrices.size()) {
if (m_sendMatrices.size())
{
for (auto& mtx : m_sendMatrices) for (auto& mtx : m_sendMatrices)
if (!mtx.second.isSilent()) if (!mtx.second.isSilent())
return false; return false;
return true; return true;
} } else {
else
{
return DefaultStereoMtx.isSilent(); return DefaultStereoMtx.isSilent();
} }
} }
template <typename T> template <typename T>
size_t AudioVoiceStereo::_pumpAndMix(size_t frames) size_t AudioVoiceStereo::_pumpAndMix(size_t frames) {
{
size_t samples = frames * 2; size_t samples = frames * 2;
auto& scratchPre = m_head->_getScratchPre<T>(); auto& scratchPre = m_head->_getScratchPre<T>();
@ -309,8 +248,7 @@ size_t AudioVoiceStereo::_pumpAndMix(size_t frames)
m_cb->preSupplyAudio(*this, dt); m_cb->preSupplyAudio(*this, dt);
_midUpdate(); _midUpdate();
if (isSilent()) if (isSilent()) {
{
int16_t* dummy; int16_t* dummy;
SRCCallback(this, &dummy, size_t(std::ceil(frames * m_sampleRatio))); SRCCallback(this, &dummy, size_t(std::ceil(frames * m_sampleRatio)));
return 0; return 0;
@ -318,49 +256,32 @@ size_t AudioVoiceStereo::_pumpAndMix(size_t frames)
size_t oDone = soxr_output(m_src, scratchPre.data(), frames); size_t oDone = soxr_output(m_src, scratchPre.data(), frames);
if (oDone) if (oDone) {
{ if (m_sendMatrices.size()) {
if (m_sendMatrices.size()) for (auto& mtx : m_sendMatrices) {
{
for (auto& mtx : m_sendMatrices)
{
AudioSubmix& smx = *reinterpret_cast<AudioSubmix*>(mtx.first); AudioSubmix& smx = *reinterpret_cast<AudioSubmix*>(mtx.first);
m_cb->routeAudio(oDone, 2, dt, smx.m_busId, scratchPre.data(), scratchPost.data()); m_cb->routeAudio(oDone, 2, dt, smx.m_busId, scratchPre.data(), scratchPost.data());
mtx.second.mixStereoSampleData(m_head->clientMixInfo(), scratchPost.data(), mtx.second.mixStereoSampleData(m_head->clientMixInfo(), scratchPost.data(), smx._getMergeBuf<T>(oDone), oDone);
smx._getMergeBuf<T>(oDone), oDone);
} }
} } else {
else
{
AudioSubmix& smx = *m_head->m_mainSubmix; AudioSubmix& smx = *m_head->m_mainSubmix;
m_cb->routeAudio(oDone, 2, dt, m_head->m_mainSubmix->m_busId, scratchPre.data(), scratchPost.data()); m_cb->routeAudio(oDone, 2, dt, m_head->m_mainSubmix->m_busId, scratchPre.data(), scratchPost.data());
DefaultStereoMtx.mixStereoSampleData(m_head->clientMixInfo(), scratchPost.data(), DefaultStereoMtx.mixStereoSampleData(m_head->clientMixInfo(), scratchPost.data(), smx._getMergeBuf<T>(oDone),
smx._getMergeBuf<T>(oDone), oDone); oDone);
} }
} }
return oDone; return oDone;
} }
void AudioVoiceStereo::resetChannelLevels() void AudioVoiceStereo::resetChannelLevels() {
{
m_head->m_submixesDirty = true; m_head->m_submixesDirty = true;
m_sendMatrices.clear(); m_sendMatrices.clear();
} }
void AudioVoiceStereo::setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew) void AudioVoiceStereo::setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew) {
{ float newCoefs[8][2] = {{coefs[0], coefs[0]}, {coefs[1], coefs[1]}, {coefs[2], coefs[2]}, {coefs[3], coefs[3]},
float newCoefs[8][2] = {coefs[4], coefs[4]}, {coefs[5], coefs[5]}, {coefs[6], coefs[6]}, {coefs[7], coefs[7]}};
{
{coefs[0], coefs[0]},
{coefs[1], coefs[1]},
{coefs[2], coefs[2]},
{coefs[3], coefs[3]},
{coefs[4], coefs[4]},
{coefs[5], coefs[5]},
{coefs[6], coefs[6]},
{coefs[7], coefs[7]}
};
if (!submix) if (!submix)
submix = m_head->m_mainSubmix.get(); submix = m_head->m_mainSubmix.get();
@ -371,8 +292,7 @@ void AudioVoiceStereo::setMonoChannelLevels(IAudioSubmix* submix, const float co
search->second.setMatrixCoefficients(newCoefs, slew ? m_head->m_5msFrames : 0); search->second.setMatrixCoefficients(newCoefs, slew ? m_head->m_5msFrames : 0);
} }
void AudioVoiceStereo::setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew) void AudioVoiceStereo::setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew) {
{
if (!submix) if (!submix)
submix = m_head->m_mainSubmix.get(); submix = m_head->m_mainSubmix.get();
@ -382,4 +302,4 @@ void AudioVoiceStereo::setStereoChannelLevels(IAudioSubmix* submix, const float
search->second.setMatrixCoefficients(coefs, slew ? m_head->m_5msFrames : 0); search->second.setMatrixCoefficients(coefs, slew ? m_head->m_5msFrames : 0);
} }
} } // namespace boo

View File

@ -12,14 +12,12 @@ struct AudioUnitVoiceEngine;
struct VSTVoiceEngine; struct VSTVoiceEngine;
struct WAVOutVoiceEngine; struct WAVOutVoiceEngine;
namespace boo namespace boo {
{
class BaseAudioVoiceEngine; class BaseAudioVoiceEngine;
struct AudioVoiceEngineMixInfo; struct AudioVoiceEngineMixInfo;
struct IAudioSubmix; struct IAudioSubmix;
class AudioVoice : public ListNode<AudioVoice, BaseAudioVoiceEngine*, IAudioVoice> class AudioVoice : public ListNode<AudioVoice, BaseAudioVoiceEngine*, IAudioVoice> {
{
friend class BaseAudioVoiceEngine; friend class BaseAudioVoiceEngine;
friend class AudioSubmix; friend class AudioSubmix;
friend struct WASAPIAudioVoiceEngine; friend struct WASAPIAudioVoiceEngine;
@ -58,7 +56,8 @@ protected:
virtual size_t pumpAndMix16(size_t frames) = 0; virtual size_t pumpAndMix16(size_t frames) = 0;
virtual size_t pumpAndMix32(size_t frames) = 0; virtual size_t pumpAndMix32(size_t frames) = 0;
virtual size_t pumpAndMixFlt(size_t frames) = 0; virtual size_t pumpAndMixFlt(size_t frames) = 0;
template <typename T> size_t pumpAndMix(size_t frames); template <typename T>
size_t pumpAndMix(size_t frames);
AudioVoice(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, bool dynamicRate); AudioVoice(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, bool dynamicRate);
@ -76,57 +75,61 @@ public:
double getSampleRateOut() const { return m_sampleRateOut; } double getSampleRateOut() const { return m_sampleRateOut; }
}; };
template <> inline size_t AudioVoice::pumpAndMix<int16_t>(size_t frames) { return pumpAndMix16(frames); } template <>
template <> inline size_t AudioVoice::pumpAndMix<int32_t>(size_t frames) { return pumpAndMix32(frames); } inline size_t AudioVoice::pumpAndMix<int16_t>(size_t frames) {
template <> inline size_t AudioVoice::pumpAndMix<float>(size_t frames) { return pumpAndMixFlt(frames); } return pumpAndMix16(frames);
}
template <>
inline size_t AudioVoice::pumpAndMix<int32_t>(size_t frames) {
return pumpAndMix32(frames);
}
template <>
inline size_t AudioVoice::pumpAndMix<float>(size_t frames) {
return pumpAndMixFlt(frames);
}
class AudioVoiceMono : public AudioVoice class AudioVoiceMono : public AudioVoice {
{
std::unordered_map<IAudioSubmix*, AudioMatrixMono> m_sendMatrices; std::unordered_map<IAudioSubmix*, AudioMatrixMono> m_sendMatrices;
bool m_silentOut = false; bool m_silentOut = false;
void _resetSampleRate(double sampleRate); void _resetSampleRate(double sampleRate);
static size_t SRCCallback(AudioVoiceMono* ctx, static size_t SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t requestedLen);
int16_t** data, size_t requestedLen);
bool isSilent() const; bool isSilent() const;
template <typename T> size_t _pumpAndMix(size_t frames); template <typename T>
size_t _pumpAndMix(size_t frames);
size_t pumpAndMix16(size_t frames) { return _pumpAndMix<int16_t>(frames); } size_t pumpAndMix16(size_t frames) { return _pumpAndMix<int16_t>(frames); }
size_t pumpAndMix32(size_t frames) { return _pumpAndMix<int32_t>(frames); } size_t pumpAndMix32(size_t frames) { return _pumpAndMix<int32_t>(frames); }
size_t pumpAndMixFlt(size_t frames) { return _pumpAndMix<float>(frames); } size_t pumpAndMixFlt(size_t frames) { return _pumpAndMix<float>(frames); }
public: public:
AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, double sampleRate, bool dynamicRate);
double sampleRate, bool dynamicRate);
void resetChannelLevels(); void resetChannelLevels();
void setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew); void setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew);
void setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew); void setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew);
}; };
class AudioVoiceStereo : public AudioVoice class AudioVoiceStereo : public AudioVoice {
{
std::unordered_map<IAudioSubmix*, AudioMatrixStereo> m_sendMatrices; std::unordered_map<IAudioSubmix*, AudioMatrixStereo> m_sendMatrices;
bool m_silentOut = false; bool m_silentOut = false;
void _resetSampleRate(double sampleRate); void _resetSampleRate(double sampleRate);
static size_t SRCCallback(AudioVoiceStereo* ctx, static size_t SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size_t requestedLen);
int16_t** data, size_t requestedLen);
bool isSilent() const; bool isSilent() const;
template <typename T> size_t _pumpAndMix(size_t frames); template <typename T>
size_t _pumpAndMix(size_t frames);
size_t pumpAndMix16(size_t frames) { return _pumpAndMix<int16_t>(frames); } size_t pumpAndMix16(size_t frames) { return _pumpAndMix<int16_t>(frames); }
size_t pumpAndMix32(size_t frames) { return _pumpAndMix<int32_t>(frames); } size_t pumpAndMix32(size_t frames) { return _pumpAndMix<int32_t>(frames); }
size_t pumpAndMixFlt(size_t frames) { return _pumpAndMix<float>(frames); } size_t pumpAndMixFlt(size_t frames) { return _pumpAndMix<float>(frames); }
public: public:
AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioVoiceCallback* cb, double sampleRate, bool dynamicRate);
double sampleRate, bool dynamicRate);
void resetChannelLevels(); void resetChannelLevels();
void setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew); void setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew);
void setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew); void setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew);
}; };
} } // namespace boo

View File

@ -1,52 +1,41 @@
#include "AudioVoiceEngine.hpp" #include "AudioVoiceEngine.hpp"
#include <cassert> #include <cassert>
namespace boo namespace boo {
{
BaseAudioVoiceEngine::~BaseAudioVoiceEngine() BaseAudioVoiceEngine::~BaseAudioVoiceEngine() {
{
m_mainSubmix.reset(); m_mainSubmix.reset();
assert(m_voiceHead == nullptr && "Dangling voices detected"); assert(m_voiceHead == nullptr && "Dangling voices detected");
assert(m_submixHead == nullptr && "Dangling submixes detected"); assert(m_submixHead == nullptr && "Dangling submixes detected");
} }
template <typename T> template <typename T>
void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, T* dataOut) void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, T* dataOut) {
{
if (dataOut) if (dataOut)
memset(dataOut, 0, sizeof(T) * frames * m_mixInfo.m_channelMap.m_channelCount); memset(dataOut, 0, sizeof(T) * frames * m_mixInfo.m_channelMap.m_channelCount);
if (m_ltRtProcessing) if (m_ltRtProcessing) {
{
size_t sampleCount = m_5msFrames * 5; size_t sampleCount = m_5msFrames * 5;
if (_getLtRtIn<T>().size() < sampleCount) if (_getLtRtIn<T>().size() < sampleCount)
_getLtRtIn<T>().resize(sampleCount); _getLtRtIn<T>().resize(sampleCount);
m_mainSubmix->_getRedirect<T>() = _getLtRtIn<T>().data(); m_mainSubmix->_getRedirect<T>() = _getLtRtIn<T>().data();
} } else {
else
{
m_mainSubmix->_getRedirect<T>() = dataOut; m_mainSubmix->_getRedirect<T>() = dataOut;
} }
if (m_submixesDirty) if (m_submixesDirty) {
{
m_linearizedSubmixes = m_mainSubmix->_linearizeC3(); m_linearizedSubmixes = m_mainSubmix->_linearizeC3();
m_submixesDirty = false; m_submixesDirty = false;
} }
size_t remFrames = frames; size_t remFrames = frames;
while (remFrames) while (remFrames) {
{
size_t thisFrames; size_t thisFrames;
if (remFrames < m_5msFrames) if (remFrames < m_5msFrames) {
{
thisFrames = remFrames; thisFrames = remFrames;
if (m_engineCallback) if (m_engineCallback)
m_engineCallback->on5MsInterval(*this, thisFrames / double(m_5msFrames) * 5.0 / 1000.0); m_engineCallback->on5MsInterval(*this, thisFrames / double(m_5msFrames) * 5.0 / 1000.0);
} } else {
else
{
thisFrames = m_5msFrames; thisFrames = m_5msFrames;
if (m_engineCallback) if (m_engineCallback)
m_engineCallback->on5MsInterval(*this, 5.0 / 1000.0); m_engineCallback->on5MsInterval(*this, 5.0 / 1000.0);
@ -70,8 +59,7 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, T* dataOut)
if (!dataOut) if (!dataOut)
continue; continue;
if (m_ltRtProcessing) if (m_ltRtProcessing) {
{
m_ltRtProcessing->Process(_getLtRtIn<T>().data(), dataOut, int(thisFrames)); m_ltRtProcessing->Process(_getLtRtIn<T>().data(), dataOut, int(thisFrames));
m_mainSubmix->_getRedirect<T>() = _getLtRtIn<T>().data(); m_mainSubmix->_getRedirect<T>() = _getLtRtIn<T>().data();
} }
@ -91,8 +79,7 @@ template void BaseAudioVoiceEngine::_pumpAndMixVoices<int16_t>(size_t frames, in
template void BaseAudioVoiceEngine::_pumpAndMixVoices<int32_t>(size_t frames, int32_t* dataOut); template void BaseAudioVoiceEngine::_pumpAndMixVoices<int32_t>(size_t frames, int32_t* dataOut);
template void BaseAudioVoiceEngine::_pumpAndMixVoices<float>(size_t frames, float* dataOut); template void BaseAudioVoiceEngine::_pumpAndMixVoices<float>(size_t frames, float* dataOut);
void BaseAudioVoiceEngine::_resetSampleRate() void BaseAudioVoiceEngine::_resetSampleRate() {
{
if (m_voiceHead) if (m_voiceHead)
for (boo::AudioVoice& vox : *m_voiceHead) for (boo::AudioVoice& vox : *m_voiceHead)
vox._resetSampleRate(vox.m_sampleRateIn); vox._resetSampleRate(vox.m_sampleRateIn);
@ -101,56 +88,36 @@ void BaseAudioVoiceEngine::_resetSampleRate()
smx._resetOutputSampleRate(); smx._resetOutputSampleRate();
} }
ObjToken<IAudioVoice> ObjToken<IAudioVoice> BaseAudioVoiceEngine::allocateNewMonoVoice(double sampleRate, IAudioVoiceCallback* cb,
BaseAudioVoiceEngine::allocateNewMonoVoice(double sampleRate, bool dynamicPitch) {
IAudioVoiceCallback* cb,
bool dynamicPitch)
{
return {new AudioVoiceMono(*this, cb, sampleRate, dynamicPitch)}; return {new AudioVoiceMono(*this, cb, sampleRate, dynamicPitch)};
} }
ObjToken<IAudioVoice> ObjToken<IAudioVoice> BaseAudioVoiceEngine::allocateNewStereoVoice(double sampleRate, IAudioVoiceCallback* cb,
BaseAudioVoiceEngine::allocateNewStereoVoice(double sampleRate, bool dynamicPitch) {
IAudioVoiceCallback* cb,
bool dynamicPitch)
{
return {new AudioVoiceStereo(*this, cb, sampleRate, dynamicPitch)}; return {new AudioVoiceStereo(*this, cb, sampleRate, dynamicPitch)};
} }
ObjToken<IAudioSubmix> ObjToken<IAudioSubmix> BaseAudioVoiceEngine::allocateNewSubmix(bool mainOut, IAudioSubmixCallback* cb, int busId) {
BaseAudioVoiceEngine::allocateNewSubmix(bool mainOut, IAudioSubmixCallback* cb, int busId)
{
return {new AudioSubmix(*this, cb, busId, mainOut)}; return {new AudioSubmix(*this, cb, busId, mainOut)};
} }
void BaseAudioVoiceEngine::setCallbackInterface(IAudioVoiceEngineCallback* cb) void BaseAudioVoiceEngine::setCallbackInterface(IAudioVoiceEngineCallback* cb) { m_engineCallback = cb; }
{
m_engineCallback = cb;
}
void BaseAudioVoiceEngine::setVolume(float vol) void BaseAudioVoiceEngine::setVolume(float vol) { m_totalVol = vol; }
{
m_totalVol = vol;
}
bool BaseAudioVoiceEngine::enableLtRt(bool enable) bool BaseAudioVoiceEngine::enableLtRt(bool enable) {
{ if (enable && m_mixInfo.m_channelMap.m_channelCount == 2 && m_mixInfo.m_channels == AudioChannelSet::Stereo)
if (enable && m_mixInfo.m_channelMap.m_channelCount == 2 &&
m_mixInfo.m_channels == AudioChannelSet::Stereo)
m_ltRtProcessing = std::make_unique<LtRtProcessing>(m_5msFrames, m_mixInfo); m_ltRtProcessing = std::make_unique<LtRtProcessing>(m_5msFrames, m_mixInfo);
else else
m_ltRtProcessing.reset(); m_ltRtProcessing.reset();
return m_ltRtProcessing.operator bool(); return m_ltRtProcessing.operator bool();
} }
const AudioVoiceEngineMixInfo& BaseAudioVoiceEngine::mixInfo() const const AudioVoiceEngineMixInfo& BaseAudioVoiceEngine::mixInfo() const { return m_mixInfo; }
{
return m_mixInfo;
}
const AudioVoiceEngineMixInfo& BaseAudioVoiceEngine::clientMixInfo() const const AudioVoiceEngineMixInfo& BaseAudioVoiceEngine::clientMixInfo() const {
{
return m_ltRtProcessing ? m_ltRtProcessing->inMixInfo() : m_mixInfo; return m_ltRtProcessing ? m_ltRtProcessing->inMixInfo() : m_mixInfo;
} }
} } // namespace boo

View File

@ -8,12 +8,10 @@
#include <functional> #include <functional>
#include <mutex> #include <mutex>
namespace boo namespace boo {
{
/** Base class for managing mixing and sample-rate-conversion amongst active voices */ /** Base class for managing mixing and sample-rate-conversion amongst active voices */
class BaseAudioVoiceEngine : public IAudioVoiceEngine class BaseAudioVoiceEngine : public IAudioVoiceEngine {
{
protected: protected:
friend class AudioVoice; friend class AudioVoice;
friend class AudioSubmix; friend class AudioSubmix;
@ -32,18 +30,21 @@ protected:
std::vector<int16_t> m_scratch16Pre; std::vector<int16_t> m_scratch16Pre;
std::vector<int32_t> m_scratch32Pre; std::vector<int32_t> m_scratch32Pre;
std::vector<float> m_scratchFltPre; std::vector<float> m_scratchFltPre;
template <typename T> std::vector<T>& _getScratchPre(); template <typename T>
std::vector<T>& _getScratchPre();
std::vector<int16_t> m_scratch16Post; std::vector<int16_t> m_scratch16Post;
std::vector<int32_t> m_scratch32Post; std::vector<int32_t> m_scratch32Post;
std::vector<float> m_scratchFltPost; std::vector<float> m_scratchFltPost;
template <typename T> std::vector<T>& _getScratchPost(); template <typename T>
std::vector<T>& _getScratchPost();
/* LtRt processing if enabled */ /* LtRt processing if enabled */
std::unique_ptr<LtRtProcessing> m_ltRtProcessing; std::unique_ptr<LtRtProcessing> m_ltRtProcessing;
std::vector<int16_t> m_ltRtIn16; std::vector<int16_t> m_ltRtIn16;
std::vector<int32_t> m_ltRtIn32; std::vector<int32_t> m_ltRtIn32;
std::vector<float> m_ltRtInFlt; std::vector<float> m_ltRtInFlt;
template <typename T> std::vector<T>& _getLtRtIn(); template <typename T>
std::vector<T>& _getLtRtIn();
std::unique_ptr<AudioSubmix> m_mainSubmix; std::unique_ptr<AudioSubmix> m_mainSubmix;
std::list<AudioSubmix*> m_linearizedSubmixes; std::list<AudioSubmix*> m_linearizedSubmixes;
@ -57,13 +58,9 @@ protected:
public: public:
BaseAudioVoiceEngine() : m_mainSubmix(std::make_unique<AudioSubmix>(*this, nullptr, -1, false)) {} BaseAudioVoiceEngine() : m_mainSubmix(std::make_unique<AudioSubmix>(*this, nullptr, -1, false)) {}
~BaseAudioVoiceEngine(); ~BaseAudioVoiceEngine();
ObjToken<IAudioVoice> allocateNewMonoVoice(double sampleRate, ObjToken<IAudioVoice> allocateNewMonoVoice(double sampleRate, IAudioVoiceCallback* cb, bool dynamicPitch = false);
IAudioVoiceCallback* cb,
bool dynamicPitch=false);
ObjToken<IAudioVoice> allocateNewStereoVoice(double sampleRate, ObjToken<IAudioVoice> allocateNewStereoVoice(double sampleRate, IAudioVoiceCallback* cb, bool dynamicPitch = false);
IAudioVoiceCallback* cb,
bool dynamicPitch=false);
ObjToken<IAudioSubmix> allocateNewSubmix(bool mainOut, IAudioSubmixCallback* cb, int busId); ObjToken<IAudioSubmix> allocateNewSubmix(bool mainOut, IAudioSubmixCallback* cb, int busId);
@ -78,17 +75,43 @@ public:
size_t get5MsFrames() const { return m_5msFrames; } size_t get5MsFrames() const { return m_5msFrames; }
}; };
template <> inline std::vector<int16_t>& BaseAudioVoiceEngine::_getScratchPre<int16_t>() { return m_scratch16Pre; } template <>
template <> inline std::vector<int32_t>& BaseAudioVoiceEngine::_getScratchPre<int32_t>() { return m_scratch32Pre; } inline std::vector<int16_t>& BaseAudioVoiceEngine::_getScratchPre<int16_t>() {
template <> inline std::vector<float>& BaseAudioVoiceEngine::_getScratchPre<float>() { return m_scratchFltPre; } return m_scratch16Pre;
}
template <> inline std::vector<int16_t>& BaseAudioVoiceEngine::_getScratchPost<int16_t>() { return m_scratch16Post; } template <>
template <> inline std::vector<int32_t>& BaseAudioVoiceEngine::_getScratchPost<int32_t>() { return m_scratch32Post; } inline std::vector<int32_t>& BaseAudioVoiceEngine::_getScratchPre<int32_t>() {
template <> inline std::vector<float>& BaseAudioVoiceEngine::_getScratchPost<float>() { return m_scratchFltPost; } return m_scratch32Pre;
}
template <> inline std::vector<int16_t>& BaseAudioVoiceEngine::_getLtRtIn<int16_t>() { return m_ltRtIn16; } template <>
template <> inline std::vector<int32_t>& BaseAudioVoiceEngine::_getLtRtIn<int32_t>() { return m_ltRtIn32; } inline std::vector<float>& BaseAudioVoiceEngine::_getScratchPre<float>() {
template <> inline std::vector<float>& BaseAudioVoiceEngine::_getLtRtIn<float>() { return m_ltRtInFlt; } return m_scratchFltPre;
} }
template <>
inline std::vector<int16_t>& BaseAudioVoiceEngine::_getScratchPost<int16_t>() {
return m_scratch16Post;
}
template <>
inline std::vector<int32_t>& BaseAudioVoiceEngine::_getScratchPost<int32_t>() {
return m_scratch32Post;
}
template <>
inline std::vector<float>& BaseAudioVoiceEngine::_getScratchPost<float>() {
return m_scratchFltPost;
}
template <>
inline std::vector<int16_t>& BaseAudioVoiceEngine::_getLtRtIn<int16_t>() {
return m_ltRtIn16;
}
template <>
inline std::vector<int32_t>& BaseAudioVoiceEngine::_getLtRtIn<int32_t>() {
return m_ltRtIn32;
}
template <>
inline std::vector<float>& BaseAudioVoiceEngine::_getLtRtIn<float>() {
return m_ltRtInFlt;
}
} // namespace boo

View File

@ -4,12 +4,10 @@
#include "../Common.hpp" #include "../Common.hpp"
#include "boo/audiodev/IAudioVoice.hpp" #include "boo/audiodev/IAudioVoice.hpp"
namespace boo namespace boo {
{
/** Pertinent information from audio backend about optimal mixed-audio representation */ /** Pertinent information from audio backend about optimal mixed-audio representation */
struct AudioVoiceEngineMixInfo struct AudioVoiceEngineMixInfo {
{
double m_sampleRate = 32000.0; double m_sampleRate = 32000.0;
soxr_datatype_t m_sampleFormat = SOXR_FLOAT32_I; soxr_datatype_t m_sampleFormat = SOXR_FLOAT32_I;
unsigned m_bitsPerSample = 32; unsigned m_bitsPerSample = 32;
@ -18,5 +16,4 @@ struct AudioVoiceEngineMixInfo
size_t m_periodFrames = 160; size_t m_periodFrames = 160;
}; };
} } // namespace boo

View File

@ -7,28 +7,17 @@
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include <signal.h> #include <signal.h>
namespace boo namespace boo {
{
extern logvisor::Module ALSALog; extern logvisor::Module ALSALog;
static inline double TimespecToDouble(struct timespec& ts) static inline double TimespecToDouble(struct timespec& ts) { return ts.tv_sec + ts.tv_nsec / 1.0e9; }
{
return ts.tv_sec + ts.tv_nsec / 1.0e9;
}
struct LinuxMidi : BaseAudioVoiceEngine struct LinuxMidi : BaseAudioVoiceEngine {
{
std::unordered_map<std::string, IMIDIPort*> m_openHandles; std::unordered_map<std::string, IMIDIPort*> m_openHandles;
void _addOpenHandle(const char* name, IMIDIPort* port) void _addOpenHandle(const char* name, IMIDIPort* port) { m_openHandles[name] = port; }
{ void _removeOpenHandle(IMIDIPort* port) {
m_openHandles[name] = port; for (auto it = m_openHandles.begin(); it != m_openHandles.end();) {
} if (it->second == port) {
void _removeOpenHandle(IMIDIPort* port)
{
for (auto it = m_openHandles.begin(); it != m_openHandles.end();)
{
if (it->second == port)
{
it = m_openHandles.erase(it); it = m_openHandles.erase(it);
continue; continue;
} }
@ -36,14 +25,12 @@ struct LinuxMidi : BaseAudioVoiceEngine
} }
} }
~LinuxMidi() ~LinuxMidi() {
{
for (auto& p : m_openHandles) for (auto& p : m_openHandles)
p.second->_disown(); 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;
int status; int status;
int card = -1; /* use -1 to prime the pump of iterating through card list */ int card = -1; /* use -1 to prime the pump of iterating through card list */
@ -56,8 +43,7 @@ struct LinuxMidi : BaseAudioVoiceEngine
snd_rawmidi_info_t* info; snd_rawmidi_info_t* info;
snd_rawmidi_info_malloc(&info); snd_rawmidi_info_malloc(&info);
while (card >= 0) while (card >= 0) {
{
snd_ctl_t* ctl; snd_ctl_t* ctl;
char name[32]; char name[32];
int device = -1; int device = -1;
@ -70,19 +56,16 @@ struct LinuxMidi : BaseAudioVoiceEngine
status = snd_ctl_rawmidi_next_device(ctl, &device); status = snd_ctl_rawmidi_next_device(ctl, &device);
if (status < 0) if (status < 0)
break; break;
if (device >= 0) if (device >= 0) {
{
sprintf(name + strlen(name), ",%d", device); sprintf(name + strlen(name), ",%d", device);
auto search = m_openHandles.find(name); auto search = m_openHandles.find(name);
if (search != m_openHandles.cend()) if (search != m_openHandles.cend()) {
{
ret.push_back(std::make_pair(name, search->second->description())); ret.push_back(std::make_pair(name, search->second->description()));
continue; continue;
} }
snd_rawmidi_t* midi; snd_rawmidi_t* midi;
if (!snd_rawmidi_open(&midi, nullptr, name, SND_RAWMIDI_NONBLOCK)) if (!snd_rawmidi_open(&midi, nullptr, name, SND_RAWMIDI_NONBLOCK)) {
{
snd_rawmidi_info(midi, info); snd_rawmidi_info(midi, info);
ret.push_back(std::make_pair(name, snd_rawmidi_info_get_name(info))); ret.push_back(std::make_pair(name, snd_rawmidi_info_get_name(info)));
snd_rawmidi_close(midi); snd_rawmidi_close(midi);
@ -101,34 +84,24 @@ struct LinuxMidi : BaseAudioVoiceEngine
return ret; return ret;
} }
bool supportsVirtualMIDIIn() const bool supportsVirtualMIDIIn() const { return true; }
{
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);
}
static void MIDIReceiveProc(snd_rawmidi_t* midi, const ReceiveFunctor& receiver) static void MIDIReceiveProc(snd_rawmidi_t* midi, const ReceiveFunctor& receiver) {
{
logvisor::RegisterThreadName("Boo MIDI"); logvisor::RegisterThreadName("Boo MIDI");
snd_rawmidi_status_t* midiStatus; snd_rawmidi_status_t* midiStatus;
snd_rawmidi_status_malloc(&midiStatus); snd_rawmidi_status_malloc(&midiStatus);
pthread_cleanup_push(MIDIFreeProc, midiStatus); pthread_cleanup_push(MIDIFreeProc, midiStatus);
uint8_t buf[512]; uint8_t buf[512];
while (true) while (true) {
{
snd_htimestamp_t ts; snd_htimestamp_t ts;
snd_rawmidi_status(midi, midiStatus); snd_rawmidi_status(midi, midiStatus);
snd_rawmidi_status_get_tstamp(midiStatus, &ts); snd_rawmidi_status_get_tstamp(midiStatus, &ts);
int rdBytes = snd_rawmidi_read(midi, buf, 512); int rdBytes = snd_rawmidi_read(midi, buf, 512);
if (rdBytes < 0) if (rdBytes < 0) {
{ if (rdBytes != -EINTR) {
if (rdBytes != -EINTR)
{
ALSALog.report(logvisor::Error, "MIDI connection lost"); ALSALog.report(logvisor::Error, "MIDI connection lost");
break; break;
} }
@ -145,17 +118,16 @@ struct LinuxMidi : BaseAudioVoiceEngine
pthread_cleanup_pop(1); pthread_cleanup_pop(1);
} }
struct MIDIIn : public IMIDIIn struct MIDIIn : public IMIDIIn {
{
snd_rawmidi_t* m_midi; snd_rawmidi_t* m_midi;
std::thread m_midiThread; std::thread m_midiThread;
MIDIIn(LinuxMidi* parent, snd_rawmidi_t* midi, bool virt, ReceiveFunctor&& receiver) MIDIIn(LinuxMidi* parent, snd_rawmidi_t* midi, bool virt, ReceiveFunctor&& receiver)
: IMIDIIn(parent, virt, std::move(receiver)), m_midi(midi), : IMIDIIn(parent, virt, std::move(receiver))
m_midiThread(std::bind(MIDIReceiveProc, m_midi, m_receiver)) {} , m_midi(midi)
, m_midiThread(std::bind(MIDIReceiveProc, m_midi, m_receiver)) {}
~MIDIIn() ~MIDIIn() {
{
if (m_parent) if (m_parent)
static_cast<LinuxMidi*>(m_parent)->_removeOpenHandle(this); static_cast<LinuxMidi*>(m_parent)->_removeOpenHandle(this);
pthread_cancel(m_midiThread.native_handle()); pthread_cancel(m_midiThread.native_handle());
@ -164,8 +136,7 @@ struct LinuxMidi : BaseAudioVoiceEngine
snd_rawmidi_close(m_midi); snd_rawmidi_close(m_midi);
} }
std::string description() const std::string description() const {
{
snd_rawmidi_info_t* info; snd_rawmidi_info_t* info;
snd_rawmidi_info_alloca(&info); snd_rawmidi_info_alloca(&info);
snd_rawmidi_info(m_midi, info); snd_rawmidi_info(m_midi, info);
@ -174,21 +145,17 @@ struct LinuxMidi : BaseAudioVoiceEngine
} }
}; };
struct MIDIOut : public IMIDIOut struct MIDIOut : public IMIDIOut {
{
snd_rawmidi_t* m_midi; snd_rawmidi_t* m_midi;
MIDIOut(LinuxMidi* parent, snd_rawmidi_t* midi, bool virt) MIDIOut(LinuxMidi* parent, snd_rawmidi_t* midi, bool virt) : IMIDIOut(parent, virt), m_midi(midi) {}
: IMIDIOut(parent, virt), m_midi(midi) {}
~MIDIOut() ~MIDIOut() {
{
if (m_parent) if (m_parent)
static_cast<LinuxMidi*>(m_parent)->_removeOpenHandle(this); static_cast<LinuxMidi*>(m_parent)->_removeOpenHandle(this);
snd_rawmidi_close(m_midi); snd_rawmidi_close(m_midi);
} }
std::string description() const std::string description() const {
{
snd_rawmidi_info_t* info; snd_rawmidi_info_t* info;
snd_rawmidi_info_alloca(&info); snd_rawmidi_info_alloca(&info);
snd_rawmidi_info(m_midi, info); snd_rawmidi_info(m_midi, info);
@ -196,24 +163,21 @@ struct LinuxMidi : BaseAudioVoiceEngine
return ret; return ret;
} }
size_t send(const void* buf, size_t len) const size_t send(const void* buf, size_t len) const { return size_t(std::max(0l, snd_rawmidi_write(m_midi, buf, len))); }
{
return size_t(std::max(0l, snd_rawmidi_write(m_midi, buf, len)));
}
}; };
struct MIDIInOut : public IMIDIInOut struct MIDIInOut : public IMIDIInOut {
{
snd_rawmidi_t* m_midiIn; snd_rawmidi_t* m_midiIn;
snd_rawmidi_t* m_midiOut; snd_rawmidi_t* m_midiOut;
std::thread m_midiThread; std::thread m_midiThread;
MIDIInOut(LinuxMidi* parent, 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(parent, virt, std::move(receiver)), m_midiIn(midiIn), m_midiOut(midiOut), : IMIDIInOut(parent, virt, std::move(receiver))
m_midiThread(std::bind(MIDIReceiveProc, m_midiIn, m_receiver)) {} , m_midiIn(midiIn)
, m_midiOut(midiOut)
, m_midiThread(std::bind(MIDIReceiveProc, m_midiIn, m_receiver)) {}
~MIDIInOut() ~MIDIInOut() {
{
if (m_parent) if (m_parent)
static_cast<LinuxMidi*>(m_parent)->_removeOpenHandle(this); static_cast<LinuxMidi*>(m_parent)->_removeOpenHandle(this);
pthread_cancel(m_midiThread.native_handle()); pthread_cancel(m_midiThread.native_handle());
@ -223,8 +187,7 @@ struct LinuxMidi : BaseAudioVoiceEngine
snd_rawmidi_close(m_midiOut); snd_rawmidi_close(m_midiOut);
} }
std::string description() const std::string description() const {
{
snd_rawmidi_info_t* info; snd_rawmidi_info_t* info;
snd_rawmidi_info_alloca(&info); snd_rawmidi_info_alloca(&info);
snd_rawmidi_info(m_midiIn, info); snd_rawmidi_info(m_midiIn, info);
@ -232,14 +195,12 @@ struct LinuxMidi : BaseAudioVoiceEngine
return ret; return ret;
} }
size_t send(const void* buf, size_t len) const size_t send(const void* buf, size_t len) const {
{
return size_t(std::max(0l, snd_rawmidi_write(m_midiOut, buf, len))); return size_t(std::max(0l, snd_rawmidi_write(m_midiOut, buf, len)));
} }
}; };
std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver) std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver) {
{
int status; int status;
snd_rawmidi_t* midi; snd_rawmidi_t* midi;
status = snd_rawmidi_open(&midi, nullptr, "virtual", 0); status = snd_rawmidi_open(&midi, nullptr, "virtual", 0);
@ -248,8 +209,7 @@ struct LinuxMidi : BaseAudioVoiceEngine
return std::make_unique<MIDIIn>(nullptr, 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() {
{
int status; int status;
snd_rawmidi_t* midi; snd_rawmidi_t* midi;
status = snd_rawmidi_open(nullptr, &midi, "virtual", 0); status = snd_rawmidi_open(nullptr, &midi, "virtual", 0);
@ -258,8 +218,7 @@ struct LinuxMidi : BaseAudioVoiceEngine
return std::make_unique<MIDIOut>(nullptr, midi, true); return std::make_unique<MIDIOut>(nullptr, midi, true);
} }
std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver) std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver) {
{
int status; int status;
snd_rawmidi_t* midiIn; snd_rawmidi_t* midiIn;
snd_rawmidi_t* midiOut; snd_rawmidi_t* midiOut;
@ -269,8 +228,7 @@ struct LinuxMidi : BaseAudioVoiceEngine
return std::make_unique<MIDIInOut>(nullptr, 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) {
{
snd_rawmidi_t* midi; snd_rawmidi_t* midi;
int status = snd_rawmidi_open(&midi, nullptr, name, 0); int status = snd_rawmidi_open(&midi, nullptr, name, 0);
if (status) if (status)
@ -280,8 +238,7 @@ struct LinuxMidi : BaseAudioVoiceEngine
return ret; return ret;
} }
std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name) std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name) {
{
snd_rawmidi_t* midi; snd_rawmidi_t* midi;
int status = snd_rawmidi_open(nullptr, &midi, name, 0); int status = snd_rawmidi_open(nullptr, &midi, name, 0);
if (status) if (status)
@ -291,8 +248,7 @@ struct LinuxMidi : BaseAudioVoiceEngine
return ret; return ret;
} }
std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) {
{
snd_rawmidi_t* midiIn; snd_rawmidi_t* midiIn;
snd_rawmidi_t* midiOut; snd_rawmidi_t* midiOut;
int status = snd_rawmidi_open(&midiIn, &midiOut, name, 0); int status = snd_rawmidi_open(&midiIn, &midiOut, name, 0);
@ -306,5 +262,4 @@ struct LinuxMidi : BaseAudioVoiceEngine
bool useMIDILock() const { return true; } bool useMIDILock() const { return true; }
}; };
} } // namespace boo

View File

@ -5,18 +5,13 @@
#undef min #undef min
#undef max #undef max
namespace boo namespace boo {
{
template <typename T> template <typename T>
inline T ClampFull(float in) inline T ClampFull(float in) {
{ if (std::is_floating_point<T>()) {
if(std::is_floating_point<T>())
{
return std::min<T>(std::max<T>(in, -1.f), 1.f); return std::min<T>(std::max<T>(in, -1.f), 1.f);
} } else {
else
{
constexpr T MAX = std::numeric_limits<T>::max(); constexpr T MAX = std::numeric_limits<T>::max();
constexpr T MIN = std::numeric_limits<T>::min(); constexpr T MIN = std::numeric_limits<T>::min();
@ -38,8 +33,7 @@ inline T ClampFull(float in)
#if USE_LPF #if USE_LPF
static constexpr int FirTaps = 27; static constexpr int FirTaps = 27;
FIRFilter12k::FIRFilter12k(int windowFrames, double sampleRate) FIRFilter12k::FIRFilter12k(int windowFrames, double sampleRate) {
{
Ipp64f* taps = ippsMalloc_64f(FirTaps); Ipp64f* taps = ippsMalloc_64f(FirTaps);
Ipp32f* taps32 = ippsMalloc_32f(FirTaps); Ipp32f* taps32 = ippsMalloc_32f(FirTaps);
int sizeSpec, sizeBuf; int sizeSpec, sizeBuf;
@ -62,32 +56,31 @@ FIRFilter12k::FIRFilter12k(int windowFrames, double sampleRate)
m_inBuf = ippsMalloc_32f(windowFrames); m_inBuf = ippsMalloc_32f(windowFrames);
} }
FIRFilter12k::~FIRFilter12k() FIRFilter12k::~FIRFilter12k() {
{
ippsFree(m_firSpec); ippsFree(m_firSpec);
ippsFree(m_firBuffer); ippsFree(m_firBuffer);
ippsFree(m_dlySrc); ippsFree(m_dlySrc);
ippsFree(m_inBuf); ippsFree(m_inBuf);
} }
void FIRFilter12k::Process(Ipp32f* buf, int windowFrames) void FIRFilter12k::Process(Ipp32f* buf, int windowFrames) {
{
ippsZero_32f(m_dlySrc, FirTaps); ippsZero_32f(m_dlySrc, FirTaps);
ippsMove_32f(buf, m_inBuf, windowFrames); ippsMove_32f(buf, m_inBuf, windowFrames);
ippsFIRSR_32f(m_inBuf, buf, windowFrames, m_firSpec, m_dlySrc, nullptr, m_firBuffer); ippsFIRSR_32f(m_inBuf, buf, windowFrames, m_firSpec, m_dlySrc, nullptr, m_firBuffer);
} }
#endif #endif
WindowedHilbert::WindowedHilbert(int windowFrames, double sampleRate) : WindowedHilbert::WindowedHilbert(int windowFrames, double sampleRate)
:
#if USE_LPF #if USE_LPF
m_fir(windowFrames, sampleRate), m_fir(windowFrames, sampleRate)
,
#endif #endif
m_windowFrames(windowFrames), m_windowFrames(windowFrames)
m_halfFrames(windowFrames / 2), , m_halfFrames(windowFrames / 2)
m_inputBuf(ippsMalloc_32f(m_windowFrames * 2 + m_halfFrames)), , m_inputBuf(ippsMalloc_32f(m_windowFrames * 2 + m_halfFrames))
m_outputBuf(ippsMalloc_32fc(m_windowFrames * 4)), , m_outputBuf(ippsMalloc_32fc(m_windowFrames * 4))
m_hammingTable(ippsMalloc_32f(m_halfFrames)) , m_hammingTable(ippsMalloc_32f(m_halfFrames)) {
{
ippsZero_32f(m_inputBuf, m_windowFrames * 2 + m_halfFrames); ippsZero_32f(m_inputBuf, m_windowFrames * 2 + m_halfFrames);
ippsZero_32fc(m_outputBuf, m_windowFrames * 4); ippsZero_32fc(m_outputBuf, m_windowFrames * 4);
m_output[0] = m_outputBuf; m_output[0] = m_outputBuf;
@ -104,8 +97,7 @@ WindowedHilbert::WindowedHilbert(int windowFrames, double sampleRate) :
m_hammingTable[i] = Ipp32f(std::cos(M_PI * (i / double(m_halfFrames) + 1.0)) * 0.5 + 0.5); m_hammingTable[i] = Ipp32f(std::cos(M_PI * (i / double(m_halfFrames) + 1.0)) * 0.5 + 0.5);
} }
WindowedHilbert::~WindowedHilbert() WindowedHilbert::~WindowedHilbert() {
{
ippFree(m_spec); ippFree(m_spec);
ippFree(m_buffer); ippFree(m_buffer);
ippsFree(m_inputBuf); ippsFree(m_inputBuf);
@ -113,51 +105,40 @@ WindowedHilbert::~WindowedHilbert()
ippsFree(m_hammingTable); ippsFree(m_hammingTable);
} }
void WindowedHilbert::_AddWindow() void WindowedHilbert::_AddWindow() {
{
#if USE_LPF #if USE_LPF
Ipp32f* inBufBase = &m_inputBuf[m_windowFrames * m_bufIdx + m_halfFrames]; Ipp32f* inBufBase = &m_inputBuf[m_windowFrames * m_bufIdx + m_halfFrames];
m_fir.Process(inBufBase, m_windowFrames); m_fir.Process(inBufBase, m_windowFrames);
#endif #endif
if (m_bufIdx) if (m_bufIdx) {
{
/* Mirror last half of samples to start of input buffer */ /* Mirror last half of samples to start of input buffer */
Ipp32f* bufBase = &m_inputBuf[m_windowFrames * 2]; Ipp32f* bufBase = &m_inputBuf[m_windowFrames * 2];
ippsCopy_32f(bufBase, m_inputBuf, m_halfFrames); ippsCopy_32f(bufBase, m_inputBuf, m_halfFrames);
ippsHilbert_32f32fc(&m_inputBuf[m_windowFrames], ippsHilbert_32f32fc(&m_inputBuf[m_windowFrames], m_output[2], m_spec, m_buffer);
m_output[2], m_spec, m_buffer); ippsHilbert_32f32fc(&m_inputBuf[m_windowFrames + m_halfFrames], m_output[3], m_spec, m_buffer);
ippsHilbert_32f32fc(&m_inputBuf[m_windowFrames + m_halfFrames], } else {
m_output[3], m_spec, m_buffer); ippsHilbert_32f32fc(&m_inputBuf[0], m_output[0], m_spec, m_buffer);
} ippsHilbert_32f32fc(&m_inputBuf[m_halfFrames], m_output[1], m_spec, m_buffer);
else
{
ippsHilbert_32f32fc(&m_inputBuf[0],
m_output[0], m_spec, m_buffer);
ippsHilbert_32f32fc(&m_inputBuf[m_halfFrames],
m_output[1], m_spec, m_buffer);
} }
m_bufIdx ^= 1; m_bufIdx ^= 1;
} }
void WindowedHilbert::AddWindow(const float* input, int stride) void WindowedHilbert::AddWindow(const float* input, int stride) {
{
Ipp32f* bufBase = &m_inputBuf[m_windowFrames * m_bufIdx + m_halfFrames]; Ipp32f* bufBase = &m_inputBuf[m_windowFrames * m_bufIdx + m_halfFrames];
for (int i = 0; i < m_windowFrames; ++i) for (int i = 0; i < m_windowFrames; ++i)
bufBase[i] = input[i * stride]; bufBase[i] = input[i * stride];
_AddWindow(); _AddWindow();
} }
void WindowedHilbert::AddWindow(const int32_t* input, int stride) void WindowedHilbert::AddWindow(const int32_t* input, int stride) {
{
Ipp32f* bufBase = &m_inputBuf[m_windowFrames * m_bufIdx + m_halfFrames]; Ipp32f* bufBase = &m_inputBuf[m_windowFrames * m_bufIdx + m_halfFrames];
for (int i = 0; i < m_windowFrames; ++i) for (int i = 0; i < m_windowFrames; ++i)
bufBase[i] = input[i * stride] / (float(INT32_MAX) + 1.f); bufBase[i] = input[i * stride] / (float(INT32_MAX) + 1.f);
_AddWindow(); _AddWindow();
} }
void WindowedHilbert::AddWindow(const int16_t* input, int stride) void WindowedHilbert::AddWindow(const int16_t* input, int stride) {
{
Ipp32f* bufBase = &m_inputBuf[m_windowFrames * m_bufIdx + m_halfFrames]; Ipp32f* bufBase = &m_inputBuf[m_windowFrames * m_bufIdx + m_halfFrames];
for (int i = 0; i < m_windowFrames; ++i) for (int i = 0; i < m_windowFrames; ++i)
bufBase[i] = input[i * stride] / (float(INT16_MAX) + 1.f); bufBase[i] = input[i * stride] / (float(INT16_MAX) + 1.f);
@ -165,17 +146,13 @@ void WindowedHilbert::AddWindow(const int16_t* input, int stride)
} }
template <typename T> template <typename T>
void WindowedHilbert::Output(T* output, float lCoef, float rCoef) const void WindowedHilbert::Output(T* output, float lCoef, float rCoef) const {
{
int first, middle, last; int first, middle, last;
if (m_bufIdx) if (m_bufIdx) {
{
first = 3; first = 3;
middle = 0; middle = 0;
last = 1; last = 1;
} } else {
else
{
first = 1; first = 1;
middle = 2; middle = 2;
last = 3; last = 3;
@ -192,23 +169,19 @@ void WindowedHilbert::Output(T* output, float lCoef, float rCoef) const
#endif #endif
int i, t; int i, t;
for (i=0, t=0 ; i<m_halfFrames ; ++i, ++t) for (i = 0, t = 0; i < m_halfFrames; ++i, ++t) {
{ float tmp =
float tmp = m_output[first][m_halfFrames + i].im * (1.f - m_hammingTable[t]) + m_output[first][m_halfFrames + i].im * (1.f - m_hammingTable[t]) + m_output[middle][i].im * m_hammingTable[t];
m_output[middle][i].im * m_hammingTable[t];
output[i * 2] = ClampFull<T>(output[i * 2] + tmp * lCoef); output[i * 2] = ClampFull<T>(output[i * 2] + tmp * lCoef);
output[i * 2 + 1] = ClampFull<T>(output[i * 2 + 1] + tmp * rCoef); output[i * 2 + 1] = ClampFull<T>(output[i * 2 + 1] + tmp * rCoef);
} }
for (; i<m_windowFrames-m_halfFrames ; ++i) for (; i < m_windowFrames - m_halfFrames; ++i) {
{
float tmp = m_output[middle][i].im; float tmp = m_output[middle][i].im;
output[i * 2] = ClampFull<T>(output[i * 2] + tmp * lCoef); output[i * 2] = ClampFull<T>(output[i * 2] + tmp * lCoef);
output[i * 2 + 1] = ClampFull<T>(output[i * 2 + 1] + tmp * rCoef); output[i * 2 + 1] = ClampFull<T>(output[i * 2 + 1] + tmp * rCoef);
} }
for (t=0 ; i<m_windowFrames ; ++i, ++t) for (t = 0; i < m_windowFrames; ++i, ++t) {
{ float tmp = m_output[middle][i].im * (1.f - m_hammingTable[t]) + m_output[last][t].im * m_hammingTable[t];
float tmp = m_output[middle][i].im * (1.f - m_hammingTable[t]) +
m_output[last][t].im * m_hammingTable[t];
output[i * 2] = ClampFull<T>(output[i * 2] + tmp * lCoef); output[i * 2] = ClampFull<T>(output[i * 2] + tmp * lCoef);
output[i * 2 + 1] = ClampFull<T>(output[i * 2 + 1] + tmp * rCoef); output[i * 2 + 1] = ClampFull<T>(output[i * 2 + 1] + tmp * rCoef);
} }
@ -220,20 +193,40 @@ template void WindowedHilbert::Output<float>(float* output, float lCoef, float r
#endif #endif
template <> int16_t* LtRtProcessing::_getInBuf<int16_t>() { return m_16Buffer.get(); } template <>
template <> int32_t* LtRtProcessing::_getInBuf<int32_t>() { return m_32Buffer.get(); } int16_t* LtRtProcessing::_getInBuf<int16_t>() {
template <> float* LtRtProcessing::_getInBuf<float>() { return m_fltBuffer.get(); } return m_16Buffer.get();
}
template <>
int32_t* LtRtProcessing::_getInBuf<int32_t>() {
return m_32Buffer.get();
}
template <>
float* LtRtProcessing::_getInBuf<float>() {
return m_fltBuffer.get();
}
template <> int16_t* LtRtProcessing::_getOutBuf<int16_t>() { return m_16Buffer.get() + m_outputOffset; } template <>
template <> int32_t* LtRtProcessing::_getOutBuf<int32_t>() { return m_32Buffer.get() + m_outputOffset; } int16_t* LtRtProcessing::_getOutBuf<int16_t>() {
template <> float* LtRtProcessing::_getOutBuf<float>() { return m_fltBuffer.get() + m_outputOffset; } return m_16Buffer.get() + m_outputOffset;
}
template <>
int32_t* LtRtProcessing::_getOutBuf<int32_t>() {
return m_32Buffer.get() + m_outputOffset;
}
template <>
float* LtRtProcessing::_getOutBuf<float>() {
return m_fltBuffer.get() + m_outputOffset;
}
LtRtProcessing::LtRtProcessing(int _5msFrames, const AudioVoiceEngineMixInfo& mixInfo) LtRtProcessing::LtRtProcessing(int _5msFrames, const AudioVoiceEngineMixInfo& mixInfo)
: m_inMixInfo(mixInfo), m_windowFrames(_5msFrames * 4), m_halfFrames(m_windowFrames / 2), : m_inMixInfo(mixInfo)
m_outputOffset(m_windowFrames * 5 * 2) , m_windowFrames(_5msFrames * 4)
, m_halfFrames(m_windowFrames / 2)
, m_outputOffset(m_windowFrames * 5 * 2)
#if INTEL_IPP #if INTEL_IPP
, m_hilbertSL(m_windowFrames, mixInfo.m_sampleRate), , m_hilbertSL(m_windowFrames, mixInfo.m_sampleRate)
m_hilbertSR(m_windowFrames, mixInfo.m_sampleRate) , m_hilbertSR(m_windowFrames, mixInfo.m_sampleRate)
#endif #endif
{ {
m_inMixInfo.m_channels = AudioChannelSet::Surround51; m_inMixInfo.m_channels = AudioChannelSet::Surround51;
@ -245,8 +238,7 @@ LtRtProcessing::LtRtProcessing(int _5msFrames, const AudioVoiceEngineMixInfo& mi
m_inMixInfo.m_channelMap.m_channels[4] = AudioChannel::RearRight; m_inMixInfo.m_channelMap.m_channels[4] = AudioChannel::RearRight;
int samples = m_windowFrames * (5 * 2 + 2 * 2); int samples = m_windowFrames * (5 * 2 + 2 * 2);
switch (mixInfo.m_sampleFormat) switch (mixInfo.m_sampleFormat) {
{
case SOXR_INT16_I: case SOXR_INT16_I:
m_16Buffer.reset(new int16_t[samples]); m_16Buffer.reset(new int16_t[samples]);
memset(m_16Buffer.get(), 0, sizeof(int16_t) * samples); memset(m_16Buffer.get(), 0, sizeof(int16_t) * samples);
@ -265,8 +257,7 @@ LtRtProcessing::LtRtProcessing(int _5msFrames, const AudioVoiceEngineMixInfo& mi
} }
template <typename T> template <typename T>
void LtRtProcessing::Process(const T* input, T* output, int frameCount) void LtRtProcessing::Process(const T* input, T* output, int frameCount) {
{
#if 0 #if 0
for (int i=0 ; i<frameCount ; ++i) for (int i=0 ; i<frameCount ; ++i)
{ {
@ -294,8 +285,7 @@ void LtRtProcessing::Process(const T* input, T* output, int frameCount)
outFramesRem -= head - m_bufferHead; outFramesRem -= head - m_bufferHead;
int bufIdx = m_bufferTail / m_windowFrames; int bufIdx = m_bufferTail / m_windowFrames;
if (tail / m_windowFrames > bufIdx) if (tail / m_windowFrames > bufIdx) {
{
T* in = &inBuf[bufIdx * m_windowFrames * 5]; T* in = &inBuf[bufIdx * m_windowFrames * 5];
T* out = &outBuf[bufIdx * m_windowFrames * 2]; T* out = &outBuf[bufIdx * m_windowFrames * 2];
#if INTEL_IPP #if INTEL_IPP
@ -305,29 +295,23 @@ void LtRtProcessing::Process(const T* input, T* output, int frameCount)
// x(:,1) + sqrt(.5)*x(:,3) + sqrt(19/25)*x(:,4) + sqrt(6/25)*x(:,5) // x(:,1) + sqrt(.5)*x(:,3) + sqrt(19/25)*x(:,4) + sqrt(6/25)*x(:,5)
// x(:,2) + sqrt(.5)*x(:,3) - sqrt(6/25)*x(:,4) - sqrt(19/25)*x(:,5) // x(:,2) + sqrt(.5)*x(:,3) - sqrt(6/25)*x(:,4) - sqrt(19/25)*x(:,5)
if (bufIdx) if (bufIdx) {
{
int delayI = -m_halfFrames; int delayI = -m_halfFrames;
for (int i=0 ; i<m_windowFrames ; ++i, ++delayI) for (int i = 0; i < m_windowFrames; ++i, ++delayI) {
{
out[i * 2] = ClampFull<T>(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]); out[i * 2] = ClampFull<T>(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]);
out[i * 2 + 1] = ClampFull<T>(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]); out[i * 2 + 1] = ClampFull<T>(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]);
// printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i); // printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i);
} }
} } else {
else
{
int delayI = m_windowFrames * 2 - m_halfFrames; int delayI = m_windowFrames * 2 - m_halfFrames;
int i; int i;
for (i=0 ; i<m_halfFrames ; ++i, ++delayI) for (i = 0; i < m_halfFrames; ++i, ++delayI) {
{
out[i * 2] = ClampFull<T>(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]); out[i * 2] = ClampFull<T>(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]);
out[i * 2 + 1] = ClampFull<T>(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]); out[i * 2 + 1] = ClampFull<T>(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]);
// printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i); // printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i);
} }
delayI = 0; delayI = 0;
for (; i<m_windowFrames ; ++i, ++delayI) for (; i < m_windowFrames; ++i, ++delayI) {
{
out[i * 2] = ClampFull<T>(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]); out[i * 2] = ClampFull<T>(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]);
out[i * 2 + 1] = ClampFull<T>(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]); out[i * 2 + 1] = ClampFull<T>(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]);
// printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i); // printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i);
@ -341,16 +325,14 @@ void LtRtProcessing::Process(const T* input, T* output, int frameCount)
m_bufferTail = (tail == m_windowFrames * 2) ? 0 : tail; m_bufferTail = (tail == m_windowFrames * 2) ? 0 : tail;
m_bufferHead = (head == m_windowFrames * 2) ? 0 : head; m_bufferHead = (head == m_windowFrames * 2) ? 0 : head;
if (frameCount) if (frameCount) {
{
samples = frameCount * 5; samples = frameCount * 5;
memmove(inBuf, input, samples * sizeof(T)); memmove(inBuf, input, samples * sizeof(T));
// printf("input %d to %d\n", frameCount, 0); // printf("input %d to %d\n", frameCount, 0);
m_bufferTail = frameCount; m_bufferTail = frameCount;
} }
if (outFramesRem) if (outFramesRem) {
{
samples = outFramesRem * 2; samples = outFramesRem * 2;
memmove(output, outBuf, samples * sizeof(T)); memmove(output, outBuf, samples * sizeof(T));
// printf("output %d from %d\n", outFramesRem, 0); // printf("output %d from %d\n", outFramesRem, 0);
@ -362,4 +344,4 @@ template void LtRtProcessing::Process<int16_t>(const int16_t* input, int16_t* ou
template void LtRtProcessing::Process<int32_t>(const int32_t* input, int32_t* output, int frameCount); template void LtRtProcessing::Process<int32_t>(const int32_t* input, int32_t* output, int frameCount);
template void LtRtProcessing::Process<float>(const float* input, float* output, int frameCount); template void LtRtProcessing::Process<float>(const float* input, float* output, int frameCount);
} } // namespace boo

View File

@ -9,19 +9,18 @@
#include "ipp.h" #include "ipp.h"
#endif #endif
namespace boo namespace boo {
{
#if INTEL_IPP #if INTEL_IPP
#define USE_LPF 0 #define USE_LPF 0
#if USE_LPF #if USE_LPF
class FIRFilter12k class FIRFilter12k {
{
IppsFIRSpec_32f* m_firSpec; IppsFIRSpec_32f* m_firSpec;
Ipp8u* m_firBuffer; Ipp8u* m_firBuffer;
Ipp32f* m_dlySrc; Ipp32f* m_dlySrc;
Ipp32f* m_inBuf; Ipp32f* m_inBuf;
public: public:
explicit FIRFilter12k(int windowFrames, double sampleRate); explicit FIRFilter12k(int windowFrames, double sampleRate);
~FIRFilter12k(); ~FIRFilter12k();
@ -29,8 +28,7 @@ public:
}; };
#endif #endif
class WindowedHilbert class WindowedHilbert {
{
#if USE_LPF #if USE_LPF
FIRFilter12k m_fir; FIRFilter12k m_fir;
#endif #endif
@ -43,6 +41,7 @@ class WindowedHilbert
Ipp32fc* m_output[4]; Ipp32fc* m_output[4];
Ipp32f* m_hammingTable; Ipp32f* m_hammingTable;
void _AddWindow(); void _AddWindow();
public: public:
explicit WindowedHilbert(int windowFrames, double sampleRate); explicit WindowedHilbert(int windowFrames, double sampleRate);
~WindowedHilbert(); ~WindowedHilbert();
@ -54,8 +53,7 @@ public:
}; };
#endif #endif
class LtRtProcessing class LtRtProcessing {
{
AudioVoiceEngineMixInfo m_inMixInfo; AudioVoiceEngineMixInfo m_inMixInfo;
int m_windowFrames; int m_windowFrames;
int m_halfFrames; int m_halfFrames;
@ -68,8 +66,11 @@ class LtRtProcessing
#if INTEL_IPP #if INTEL_IPP
WindowedHilbert m_hilbertSL, m_hilbertSR; WindowedHilbert m_hilbertSL, m_hilbertSR;
#endif #endif
template <typename T> T* _getInBuf(); template <typename T>
template <typename T> T* _getOutBuf(); T* _getInBuf();
template <typename T>
T* _getOutBuf();
public: public:
LtRtProcessing(int _5msFrames, const AudioVoiceEngineMixInfo& mixInfo); LtRtProcessing(int _5msFrames, const AudioVoiceEngineMixInfo& mixInfo);
template <typename T> template <typename T>
@ -77,5 +78,4 @@ public:
const AudioVoiceEngineMixInfo& inMixInfo() const { return m_inMixInfo; } const AudioVoiceEngineMixInfo& inMixInfo() const { return m_inMixInfo; }
}; };
} } // namespace boo

View File

@ -1,12 +1,11 @@
#include "MIDICommon.hpp" #include "MIDICommon.hpp"
#include "boo/audiodev/IMIDIPort.hpp" #include "boo/audiodev/IMIDIPort.hpp"
namespace boo namespace boo {
{
IMIDIPort::~IMIDIPort() {} IMIDIPort::~IMIDIPort() {}
IMIDIIn::~IMIDIIn() {} IMIDIIn::~IMIDIIn() {}
IMIDIOut::~IMIDIOut() {} IMIDIOut::~IMIDIOut() {}
IMIDIInOut::~IMIDIInOut() {} IMIDIInOut::~IMIDIInOut() {}
} } // namespace boo

View File

@ -1,10 +1,8 @@
#pragma once #pragma once
namespace boo namespace boo {
{
enum class Status enum class Status {
{
NoteOff = 0x80, NoteOff = 0x80,
NoteOn = 0x90, NoteOn = 0x90,
NotePressure = 0xA0, NotePressure = 0xA0,
@ -27,4 +25,3 @@ enum class Status
}; };
} }

View File

@ -3,28 +3,23 @@
#include <memory> #include <memory>
#include <algorithm> #include <algorithm>
namespace boo namespace boo {
{
static inline uint8_t clamp7(uint8_t val) { return std::max(0, std::min(127, int(val))); } static inline uint8_t clamp7(uint8_t val) { return std::max(0, std::min(127, int(val))); }
bool MIDIDecoder::_readContinuedValue(std::vector<uint8_t>::const_iterator& it, bool MIDIDecoder::_readContinuedValue(std::vector<uint8_t>::const_iterator& it,
std::vector<uint8_t>::const_iterator end, std::vector<uint8_t>::const_iterator end, uint32_t& valOut) {
uint32_t& valOut)
{
uint8_t a = *it++; uint8_t a = *it++;
valOut = a & 0x7f; valOut = a & 0x7f;
if (a & 0x80) if (a & 0x80) {
{
if (it == end) if (it == end)
return false; return false;
valOut <<= 7; valOut <<= 7;
a = *it++; a = *it++;
valOut |= a & 0x7f; valOut |= a & 0x7f;
if (a & 0x80) if (a & 0x80) {
{
if (it == end) if (it == end)
return false; return false;
valOut <<= 7; valOut <<= 7;
@ -36,13 +31,10 @@ bool MIDIDecoder::_readContinuedValue(std::vector<uint8_t>::const_iterator& it,
return true; return true;
} }
std::vector<uint8_t>::const_iterator std::vector<uint8_t>::const_iterator MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin,
MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin, std::vector<uint8_t>::const_iterator end) {
std::vector<uint8_t>::const_iterator end)
{
std::vector<uint8_t>::const_iterator it = begin; std::vector<uint8_t>::const_iterator it = begin;
while (it != end) while (it != end) {
{
uint8_t a = *it++; uint8_t a = *it++;
uint8_t b; uint8_t b;
if (a & 0x80) if (a & 0x80)
@ -50,8 +42,7 @@ MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin,
else else
it--; it--;
if (m_status == 0xff) if (m_status == 0xff) {
{
/* Meta events (ignored for now) */ /* Meta events (ignored for now) */
if (it == end) if (it == end)
return begin; return begin;
@ -60,13 +51,10 @@ MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin,
uint32_t length; uint32_t length;
_readContinuedValue(it, end, length); _readContinuedValue(it, end, length);
it += length; it += length;
} else } else {
{
uint8_t chan = m_status & 0xf; uint8_t chan = m_status & 0xf;
switch (Status(m_status & 0xf0)) switch (Status(m_status & 0xf0)) {
{ case Status::NoteOff: {
case Status::NoteOff:
{
if (it == end) if (it == end)
return begin; return begin;
a = *it++; a = *it++;
@ -76,8 +64,7 @@ MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin,
m_out.noteOff(chan, clamp7(a), clamp7(b)); m_out.noteOff(chan, clamp7(a), clamp7(b));
break; break;
} }
case Status::NoteOn: case Status::NoteOn: {
{
if (it == end) if (it == end)
return begin; return begin;
a = *it++; a = *it++;
@ -87,8 +74,7 @@ MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin,
m_out.noteOn(chan, clamp7(a), clamp7(b)); m_out.noteOn(chan, clamp7(a), clamp7(b));
break; break;
} }
case Status::NotePressure: case Status::NotePressure: {
{
if (it == end) if (it == end)
return begin; return begin;
a = *it++; a = *it++;
@ -98,8 +84,7 @@ MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin,
m_out.notePressure(chan, clamp7(a), clamp7(b)); m_out.notePressure(chan, clamp7(a), clamp7(b));
break; break;
} }
case Status::ControlChange: case Status::ControlChange: {
{
if (it == end) if (it == end)
return begin; return begin;
a = *it++; a = *it++;
@ -109,24 +94,21 @@ MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin,
m_out.controlChange(chan, clamp7(a), clamp7(b)); m_out.controlChange(chan, clamp7(a), clamp7(b));
break; break;
} }
case Status::ProgramChange: case Status::ProgramChange: {
{
if (it == end) if (it == end)
return begin; return begin;
a = *it++; a = *it++;
m_out.programChange(chan, clamp7(a)); m_out.programChange(chan, clamp7(a));
break; break;
} }
case Status::ChannelPressure: case Status::ChannelPressure: {
{
if (it == end) if (it == end)
return begin; return begin;
a = *it++; a = *it++;
m_out.channelPressure(chan, clamp7(a)); m_out.channelPressure(chan, clamp7(a));
break; break;
} }
case Status::PitchBend: case Status::PitchBend: {
{
if (it == end) if (it == end)
return begin; return begin;
a = *it++; a = *it++;
@ -136,28 +118,23 @@ MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin,
m_out.pitchBend(chan, clamp7(b) * 128 + clamp7(a)); m_out.pitchBend(chan, clamp7(b) * 128 + clamp7(a));
break; break;
} }
case Status::SysEx: case Status::SysEx: {
{ switch (Status(m_status & 0xff)) {
switch (Status(m_status & 0xff)) case Status::SysEx: {
{
case Status::SysEx:
{
uint32_t len; uint32_t len;
if (!_readContinuedValue(it, end, len) || end - it < len) if (!_readContinuedValue(it, end, len) || end - it < len)
return begin; return begin;
m_out.sysex(&*it, len); m_out.sysex(&*it, len);
break; break;
} }
case Status::TimecodeQuarterFrame: case Status::TimecodeQuarterFrame: {
{
if (it == end) if (it == end)
return begin; return begin;
a = *it++; a = *it++;
m_out.timeCodeQuarterFrame(a >> 4 & 0x7, a & 0xf); m_out.timeCodeQuarterFrame(a >> 4 & 0x7, a & 0xf);
break; break;
} }
case Status::SongPositionPointer: case Status::SongPositionPointer: {
{
if (it == end) if (it == end)
return begin; return begin;
a = *it++; a = *it++;
@ -167,8 +144,7 @@ MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin,
m_out.songPositionPointer(clamp7(b) * 128 + clamp7(a)); m_out.songPositionPointer(clamp7(b) * 128 + clamp7(a));
break; break;
} }
case Status::SongSelect: case Status::SongSelect: {
{
if (it == end) if (it == end)
return begin; return begin;
a = *it++; a = *it++;
@ -206,4 +182,4 @@ MIDIDecoder::receiveBytes(std::vector<uint8_t>::const_iterator begin,
return it; return it;
} }
} } // namespace boo

View File

@ -1,16 +1,13 @@
#include "boo/audiodev/MIDIEncoder.hpp" #include "boo/audiodev/MIDIEncoder.hpp"
#include "MIDICommon.hpp" #include "MIDICommon.hpp"
namespace boo namespace boo {
{
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::_sendMessage(const uint8_t* data, size_t len) void MIDIEncoder<Sender>::_sendMessage(const uint8_t* data, size_t len) {
{
if (data[0] == m_status) if (data[0] == m_status)
m_sender.send(data + 1, len - 1); m_sender.send(data + 1, len - 1);
else else {
{
if (data[0] & 0x80) if (data[0] & 0x80)
m_status = data[0]; m_status = data[0];
m_sender.send(data, len); m_sender.send(data, len);
@ -18,20 +15,17 @@ void MIDIEncoder<Sender>::_sendMessage(const uint8_t* data, size_t len)
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::_sendContinuedValue(uint32_t val) void MIDIEncoder<Sender>::_sendContinuedValue(uint32_t val) {
{
uint8_t send[3] = {}; uint8_t send[3] = {};
uint8_t* ptr = nullptr; uint8_t* ptr = nullptr;
if (val >= 0x4000) if (val >= 0x4000) {
{
ptr = &send[0]; ptr = &send[0];
send[0] = 0x80 | ((val / 0x4000) & 0x7f); send[0] = 0x80 | ((val / 0x4000) & 0x7f);
send[1] = 0x80; send[1] = 0x80;
val &= 0x3fff; val &= 0x3fff;
} }
if (val >= 0x80) if (val >= 0x80) {
{
if (!ptr) if (!ptr)
ptr = &send[1]; ptr = &send[1];
send[1] = 0x80 | ((val / 0x80) & 0x7f); send[1] = 0x80 | ((val / 0x80) & 0x7f);
@ -45,114 +39,86 @@ void MIDIEncoder<Sender>::_sendContinuedValue(uint32_t val)
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::noteOff(uint8_t chan, uint8_t key, uint8_t velocity) void MIDIEncoder<Sender>::noteOff(uint8_t chan, uint8_t key, uint8_t velocity) {
{ uint8_t cmd[3] = {uint8_t(int(Status::NoteOff) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)};
uint8_t cmd[3] = {uint8_t(int(Status::NoteOff) | (chan & 0xf)),
uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::noteOn(uint8_t chan, uint8_t key, uint8_t velocity) void MIDIEncoder<Sender>::noteOn(uint8_t chan, uint8_t key, uint8_t velocity) {
{ uint8_t cmd[3] = {uint8_t(int(Status::NoteOn) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)};
uint8_t cmd[3] = {uint8_t(int(Status::NoteOn) | (chan & 0xf)),
uint8_t(key & 0x7f), uint8_t(velocity & 0x7f)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::notePressure(uint8_t chan, uint8_t key, uint8_t pressure) void MIDIEncoder<Sender>::notePressure(uint8_t chan, uint8_t key, uint8_t pressure) {
{ uint8_t cmd[3] = {uint8_t(int(Status::NotePressure) | (chan & 0xf)), uint8_t(key & 0x7f), uint8_t(pressure & 0x7f)};
uint8_t cmd[3] = {uint8_t(int(Status::NotePressure) | (chan & 0xf)),
uint8_t(key & 0x7f), uint8_t(pressure & 0x7f)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::controlChange(uint8_t chan, uint8_t control, uint8_t value) void MIDIEncoder<Sender>::controlChange(uint8_t chan, uint8_t control, uint8_t value) {
{ uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(control & 0x7f), uint8_t(value & 0x7f)};
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)),
uint8_t(control & 0x7f), uint8_t(value & 0x7f)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::programChange(uint8_t chan, uint8_t program) void MIDIEncoder<Sender>::programChange(uint8_t chan, uint8_t program) {
{ uint8_t cmd[2] = {uint8_t(int(Status::ProgramChange) | (chan & 0xf)), uint8_t(program & 0x7f)};
uint8_t cmd[2] = {uint8_t(int(Status::ProgramChange) | (chan & 0xf)),
uint8_t(program & 0x7f)};
_sendMessage(cmd, 2); _sendMessage(cmd, 2);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::channelPressure(uint8_t chan, uint8_t pressure) void MIDIEncoder<Sender>::channelPressure(uint8_t chan, uint8_t pressure) {
{ uint8_t cmd[2] = {uint8_t(int(Status::ChannelPressure) | (chan & 0xf)), uint8_t(pressure & 0x7f)};
uint8_t cmd[2] = {uint8_t(int(Status::ChannelPressure) | (chan & 0xf)),
uint8_t(pressure & 0x7f)};
_sendMessage(cmd, 2); _sendMessage(cmd, 2);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::pitchBend(uint8_t chan, int16_t pitch) void MIDIEncoder<Sender>::pitchBend(uint8_t chan, int16_t pitch) {
{ uint8_t cmd[3] = {uint8_t(int(Status::PitchBend) | (chan & 0xf)), uint8_t((pitch % 128) & 0x7f),
uint8_t cmd[3] = {uint8_t(int(Status::PitchBend) | (chan & 0xf)), uint8_t((pitch / 128) & 0x7f)};
uint8_t((pitch % 128) & 0x7f), uint8_t((pitch / 128) & 0x7f)};
_sendMessage(cmd, 3);
}
template <class Sender>
void MIDIEncoder<Sender>::allSoundOff(uint8_t chan)
{
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)),
120, 0};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::resetAllControllers(uint8_t chan) void MIDIEncoder<Sender>::allSoundOff(uint8_t chan) {
{ uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 120, 0};
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)),
121, 0};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::localControl(uint8_t chan, bool on) void MIDIEncoder<Sender>::resetAllControllers(uint8_t chan) {
{ uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 121, 0};
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)),
122, uint8_t(on ? 127 : 0)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::allNotesOff(uint8_t chan) void MIDIEncoder<Sender>::localControl(uint8_t chan, bool on) {
{ uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 122, uint8_t(on ? 127 : 0)};
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)),
123, 0};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::omniMode(uint8_t chan, bool on) void MIDIEncoder<Sender>::allNotesOff(uint8_t chan) {
{ uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), 123, 0};
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)),
uint8_t(on ? 125 : 124), 0};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::polyMode(uint8_t chan, bool on) void MIDIEncoder<Sender>::omniMode(uint8_t chan, bool on) {
{ uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(on ? 125 : 124), 0};
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)),
uint8_t(on ? 127 : 126), 0};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
template <class Sender>
void MIDIEncoder<Sender>::polyMode(uint8_t chan, bool on) {
uint8_t cmd[3] = {uint8_t(int(Status::ControlChange) | (chan & 0xf)), uint8_t(on ? 127 : 126), 0};
_sendMessage(cmd, 3);
}
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::sysex(const void* data, size_t len) void MIDIEncoder<Sender>::sysex(const void* data, size_t len) {
{
uint8_t cmd = uint8_t(Status::SysEx); uint8_t cmd = uint8_t(Status::SysEx);
_sendMessage(&cmd, 1); _sendMessage(&cmd, 1);
_sendContinuedValue(len); _sendContinuedValue(len);
@ -162,62 +128,50 @@ void MIDIEncoder<Sender>::sysex(const void* data, size_t len)
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::timeCodeQuarterFrame(uint8_t message, uint8_t value) void MIDIEncoder<Sender>::timeCodeQuarterFrame(uint8_t message, uint8_t value) {
{ uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)), uint8_t((message & 0x7 << 4) | (value & 0xf))};
uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)),
uint8_t((message & 0x7 << 4) | (value & 0xf))};
_sendMessage(cmd, 2); _sendMessage(cmd, 2);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::songPositionPointer(uint16_t pointer) void MIDIEncoder<Sender>::songPositionPointer(uint16_t pointer) {
{ uint8_t cmd[3] = {uint8_t(int(Status::SongPositionPointer)), uint8_t((pointer % 128) & 0x7f),
uint8_t cmd[3] = {uint8_t(int(Status::SongPositionPointer)), uint8_t((pointer / 128) & 0x7f)};
uint8_t((pointer % 128) & 0x7f), uint8_t((pointer / 128) & 0x7f)};
_sendMessage(cmd, 3); _sendMessage(cmd, 3);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::songSelect(uint8_t song) void MIDIEncoder<Sender>::songSelect(uint8_t song) {
{ uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)), uint8_t(song & 0x7f)};
uint8_t cmd[2] = {uint8_t(int(Status::TimecodeQuarterFrame)),
uint8_t(song & 0x7f)};
_sendMessage(cmd, 2); _sendMessage(cmd, 2);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::tuneRequest() void MIDIEncoder<Sender>::tuneRequest() {
{
uint8_t cmd = uint8_t(Status::TuneRequest); uint8_t cmd = uint8_t(Status::TuneRequest);
_sendMessage(&cmd, 1); _sendMessage(&cmd, 1);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::startSeq() void MIDIEncoder<Sender>::startSeq() {
{
uint8_t cmd = uint8_t(Status::Start); uint8_t cmd = uint8_t(Status::Start);
_sendMessage(&cmd, 1); _sendMessage(&cmd, 1);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::continueSeq() void MIDIEncoder<Sender>::continueSeq() {
{
uint8_t cmd = uint8_t(Status::Continue); uint8_t cmd = uint8_t(Status::Continue);
_sendMessage(&cmd, 1); _sendMessage(&cmd, 1);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::stopSeq() void MIDIEncoder<Sender>::stopSeq() {
{
uint8_t cmd = uint8_t(Status::Stop); uint8_t cmd = uint8_t(Status::Stop);
_sendMessage(&cmd, 1); _sendMessage(&cmd, 1);
} }
template <class Sender> template <class Sender>
void MIDIEncoder<Sender>::reset() void MIDIEncoder<Sender>::reset() {
{
uint8_t cmd = uint8_t(Status::Reset); uint8_t cmd = uint8_t(Status::Reset);
_sendMessage(&cmd, 1); _sendMessage(&cmd, 1);
} }
@ -225,4 +179,4 @@ void MIDIEncoder<Sender>::reset()
template class MIDIEncoder<IMIDIOut>; template class MIDIEncoder<IMIDIOut>;
template class MIDIEncoder<IMIDIInOut>; template class MIDIEncoder<IMIDIInOut>;
} } // namespace boo

View File

@ -6,37 +6,25 @@
#include <pulse/pulseaudio.h> #include <pulse/pulseaudio.h>
#include <unistd.h> #include <unistd.h>
namespace boo namespace boo {
{
static logvisor::Module Log("boo::PulseAudio"); static logvisor::Module Log("boo::PulseAudio");
logvisor::Module ALSALog("boo::ALSA"); logvisor::Module ALSALog("boo::ALSA");
static const uint64_t StereoChans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | static const uint64_t StereoChans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | (1 << PA_CHANNEL_POSITION_FRONT_RIGHT);
(1 << PA_CHANNEL_POSITION_FRONT_RIGHT);
static const uint64_t QuadChans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | static const uint64_t QuadChans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | (1 << PA_CHANNEL_POSITION_FRONT_RIGHT) |
(1 << PA_CHANNEL_POSITION_FRONT_RIGHT) | (1 << PA_CHANNEL_POSITION_REAR_LEFT) | (1 << PA_CHANNEL_POSITION_REAR_RIGHT);
(1 << PA_CHANNEL_POSITION_REAR_LEFT) |
(1 << PA_CHANNEL_POSITION_REAR_RIGHT);
static const uint64_t S51Chans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | static const uint64_t S51Chans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | (1 << PA_CHANNEL_POSITION_FRONT_RIGHT) |
(1 << PA_CHANNEL_POSITION_FRONT_RIGHT) | (1 << PA_CHANNEL_POSITION_REAR_LEFT) | (1 << PA_CHANNEL_POSITION_REAR_RIGHT) |
(1 << PA_CHANNEL_POSITION_REAR_LEFT) | (1 << PA_CHANNEL_POSITION_FRONT_CENTER) | (1 << PA_CHANNEL_POSITION_LFE);
(1 << PA_CHANNEL_POSITION_REAR_RIGHT) |
(1 << PA_CHANNEL_POSITION_FRONT_CENTER) |
(1 << PA_CHANNEL_POSITION_LFE);
static const uint64_t S71Chans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | static const uint64_t S71Chans = (1 << PA_CHANNEL_POSITION_FRONT_LEFT) | (1 << PA_CHANNEL_POSITION_FRONT_RIGHT) |
(1 << PA_CHANNEL_POSITION_FRONT_RIGHT) | (1 << PA_CHANNEL_POSITION_REAR_LEFT) | (1 << PA_CHANNEL_POSITION_REAR_RIGHT) |
(1 << PA_CHANNEL_POSITION_REAR_LEFT) | (1 << PA_CHANNEL_POSITION_FRONT_CENTER) | (1 << PA_CHANNEL_POSITION_LFE) |
(1 << PA_CHANNEL_POSITION_REAR_RIGHT) | (1 << PA_CHANNEL_POSITION_SIDE_LEFT) | (1 << PA_CHANNEL_POSITION_SIDE_RIGHT);
(1 << PA_CHANNEL_POSITION_FRONT_CENTER) |
(1 << PA_CHANNEL_POSITION_LFE) |
(1 << PA_CHANNEL_POSITION_SIDE_LEFT) |
(1 << PA_CHANNEL_POSITION_SIDE_RIGHT);
struct PulseAudioVoiceEngine : LinuxMidi struct PulseAudioVoiceEngine : LinuxMidi {
{
pa_mainloop* m_mainloop = nullptr; pa_mainloop* m_mainloop = nullptr;
pa_context* m_ctx = nullptr; pa_context* m_ctx = nullptr;
pa_stream* m_stream = nullptr; pa_stream* m_stream = nullptr;
@ -45,34 +33,29 @@ struct PulseAudioVoiceEngine : LinuxMidi
pa_sample_spec m_sampleSpec = {}; pa_sample_spec m_sampleSpec = {};
pa_channel_map m_chanMap = {}; pa_channel_map m_chanMap = {};
int _paWaitReady() int _paWaitReady() {
{
int retval = 0; int retval = 0;
while (pa_context_get_state(m_ctx) < PA_CONTEXT_READY) while (pa_context_get_state(m_ctx) < PA_CONTEXT_READY)
pa_mainloop_iterate(m_mainloop, 1, &retval); pa_mainloop_iterate(m_mainloop, 1, &retval);
return retval; return retval;
} }
int _paStreamWaitReady() int _paStreamWaitReady() {
{
int retval = 0; int retval = 0;
while (pa_stream_get_state(m_stream) < PA_STREAM_READY) while (pa_stream_get_state(m_stream) < PA_STREAM_READY)
pa_mainloop_iterate(m_mainloop, 1, &retval); pa_mainloop_iterate(m_mainloop, 1, &retval);
return retval; return retval;
} }
int _paIterate(pa_operation* op) const int _paIterate(pa_operation* op) const {
{
int retval = 0; int retval = 0;
while (pa_operation_get_state(op) == PA_OPERATION_RUNNING) while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
pa_mainloop_iterate(m_mainloop, 1, &retval); pa_mainloop_iterate(m_mainloop, 1, &retval);
return retval; return retval;
} }
bool _setupSink() bool _setupSink() {
{ if (m_stream) {
if (m_stream)
{
pa_stream_disconnect(m_stream); pa_stream_disconnect(m_stream);
pa_stream_unref(m_stream); pa_stream_unref(m_stream);
m_stream = nullptr; m_stream = nullptr;
@ -84,8 +67,7 @@ struct PulseAudioVoiceEngine : LinuxMidi
_paIterate(op); _paIterate(op);
pa_operation_unref(op); pa_operation_unref(op);
if (m_sampleSpec.format == PA_SAMPLE_INVALID) if (m_sampleSpec.format == PA_SAMPLE_INVALID) {
{
Log.report(logvisor::Error, "Unable to setup audio stream"); Log.report(logvisor::Error, "Unable to setup audio stream");
goto err; goto err;
} }
@ -96,8 +78,7 @@ struct PulseAudioVoiceEngine : LinuxMidi
m_mixInfo.m_sampleFormat = SOXR_FLOAT32; m_mixInfo.m_sampleFormat = SOXR_FLOAT32;
m_mixInfo.m_bitsPerSample = 32; m_mixInfo.m_bitsPerSample = 32;
m_mixInfo.m_periodFrames = m_5msFrames; m_mixInfo.m_periodFrames = m_5msFrames;
if (!(m_stream = pa_stream_new(m_ctx, "master", &m_sampleSpec, &m_chanMap))) if (!(m_stream = pa_stream_new(m_ctx, "master", &m_sampleSpec, &m_chanMap))) {
{
Log.report(logvisor::Error, "Unable to pa_stream_new(): %s", pa_strerror(pa_context_errno(m_ctx))); Log.report(logvisor::Error, "Unable to pa_stream_new(): %s", pa_strerror(pa_context_errno(m_ctx)));
goto err; goto err;
} }
@ -110,9 +91,8 @@ struct PulseAudioVoiceEngine : LinuxMidi
bufAttr.fragsize = UINT32_MAX; bufAttr.fragsize = UINT32_MAX;
if (pa_stream_connect_playback(m_stream, m_sinkName.c_str(), &bufAttr, if (pa_stream_connect_playback(m_stream, m_sinkName.c_str(), &bufAttr,
pa_stream_flags_t(PA_STREAM_START_UNMUTED | PA_STREAM_EARLY_REQUESTS), pa_stream_flags_t(PA_STREAM_START_UNMUTED | PA_STREAM_EARLY_REQUESTS), nullptr,
nullptr, nullptr)) nullptr)) {
{
Log.report(logvisor::Error, "Unable to pa_stream_connect_playback()"); Log.report(logvisor::Error, "Unable to pa_stream_connect_playback()");
goto err; goto err;
} }
@ -124,8 +104,7 @@ struct PulseAudioVoiceEngine : LinuxMidi
_resetSampleRate(); _resetSampleRate();
return true; return true;
err: err:
if (m_stream) if (m_stream) {
{
pa_stream_disconnect(m_stream); pa_stream_disconnect(m_stream);
pa_stream_unref(m_stream); pa_stream_unref(m_stream);
m_stream = nullptr; m_stream = nullptr;
@ -133,10 +112,8 @@ struct PulseAudioVoiceEngine : LinuxMidi
return false; return false;
} }
PulseAudioVoiceEngine() PulseAudioVoiceEngine() {
{ if (!(m_mainloop = pa_mainloop_new())) {
if (!(m_mainloop = pa_mainloop_new()))
{
Log.report(logvisor::Error, "Unable to pa_mainloop_new()"); Log.report(logvisor::Error, "Unable to pa_mainloop_new()");
return; return;
} }
@ -147,8 +124,7 @@ struct PulseAudioVoiceEngine : LinuxMidi
char pidStr[16]; char pidStr[16];
snprintf(pidStr, 16, "%d", int(getpid())); snprintf(pidStr, 16, "%d", int(getpid()));
pa_proplist_sets(propList, PA_PROP_APPLICATION_PROCESS_ID, pidStr); pa_proplist_sets(propList, PA_PROP_APPLICATION_PROCESS_ID, pidStr);
if (!(m_ctx = pa_context_new_with_proplist(mlApi, APP->getFriendlyName().data(), propList))) if (!(m_ctx = pa_context_new_with_proplist(mlApi, APP->getFriendlyName().data(), propList))) {
{
Log.report(logvisor::Error, "Unable to pa_context_new_with_proplist()"); Log.report(logvisor::Error, "Unable to pa_context_new_with_proplist()");
pa_mainloop_free(m_mainloop); pa_mainloop_free(m_mainloop);
m_mainloop = nullptr; m_mainloop = nullptr;
@ -157,8 +133,7 @@ struct PulseAudioVoiceEngine : LinuxMidi
pa_operation* op; pa_operation* op;
if (pa_context_connect(m_ctx, nullptr, PA_CONTEXT_NOFLAGS, nullptr)) if (pa_context_connect(m_ctx, nullptr, PA_CONTEXT_NOFLAGS, nullptr)) {
{
Log.report(logvisor::Error, "Unable to pa_context_connect()"); Log.report(logvisor::Error, "Unable to pa_context_connect()");
goto err; goto err;
} }
@ -181,37 +156,30 @@ struct PulseAudioVoiceEngine : LinuxMidi
m_mainloop = nullptr; m_mainloop = nullptr;
} }
~PulseAudioVoiceEngine() ~PulseAudioVoiceEngine() {
{ if (m_stream) {
if (m_stream)
{
pa_stream_disconnect(m_stream); pa_stream_disconnect(m_stream);
pa_stream_unref(m_stream); pa_stream_unref(m_stream);
} }
if (m_ctx) if (m_ctx) {
{
pa_context_disconnect(m_ctx); pa_context_disconnect(m_ctx);
pa_context_unref(m_ctx); pa_context_unref(m_ctx);
} }
if (m_mainloop) if (m_mainloop) {
{
pa_mainloop_free(m_mainloop); pa_mainloop_free(m_mainloop);
} }
} }
static void _streamMoved(pa_stream* p, PulseAudioVoiceEngine* userdata) static void _streamMoved(pa_stream* p, PulseAudioVoiceEngine* userdata) {
{
userdata->m_sinkName = pa_stream_get_device_name(p); userdata->m_sinkName = pa_stream_get_device_name(p);
userdata->m_handleMove = true; userdata->m_handleMove = true;
} }
static void _getServerInfoReply(pa_context* c, const pa_server_info* i, PulseAudioVoiceEngine* userdata) static void _getServerInfoReply(pa_context* c, const pa_server_info* i, PulseAudioVoiceEngine* userdata) {
{
userdata->m_sinkName = i->default_sink_name; userdata->m_sinkName = i->default_sink_name;
} }
void _parseAudioChannelSet(const pa_channel_map* chm) void _parseAudioChannelSet(const pa_channel_map* chm) {
{
m_chanMap = *chm; m_chanMap = *chm;
ChannelMap& chmapOut = m_mixInfo.m_channelMap; ChannelMap& chmapOut = m_mixInfo.m_channelMap;
@ -219,11 +187,9 @@ struct PulseAudioVoiceEngine : LinuxMidi
uint64_t chBits = 0; uint64_t chBits = 0;
chmapOut.m_channelCount = chm->channels; chmapOut.m_channelCount = chm->channels;
for (unsigned c=0 ; c<chm->channels ; ++c) for (unsigned c = 0; c < chm->channels; ++c) {
{
chBits |= 1 << chm->map[c]; chBits |= 1 << chm->map[c];
switch (chm->map[c]) switch (chm->map[c]) {
{
case PA_CHANNEL_POSITION_FRONT_LEFT: case PA_CHANNEL_POSITION_FRONT_LEFT:
chmapOut.m_channels[c] = AudioChannel::FrontLeft; chmapOut.m_channels[c] = AudioChannel::FrontLeft;
break; break;
@ -254,56 +220,45 @@ struct PulseAudioVoiceEngine : LinuxMidi
} }
} }
static const std::array<AudioChannelSet, 4> testSets = static const std::array<AudioChannelSet, 4> testSets = {
{{AudioChannelSet::Surround71, AudioChannelSet::Surround51, {AudioChannelSet::Surround71, AudioChannelSet::Surround51, AudioChannelSet::Quad, AudioChannelSet::Stereo}};
AudioChannelSet::Quad, AudioChannelSet::Stereo}}; for (AudioChannelSet set : testSets) {
for (AudioChannelSet set : testSets) switch (set) {
{ case AudioChannelSet::Stereo: {
switch (set) if ((chBits & StereoChans) == StereoChans) {
{
case AudioChannelSet::Stereo:
{
if ((chBits & StereoChans) == StereoChans)
{
m_mixInfo.m_channels = AudioChannelSet::Stereo; m_mixInfo.m_channels = AudioChannelSet::Stereo;
return; return;
} }
break; break;
} }
case AudioChannelSet::Quad: case AudioChannelSet::Quad: {
{ if ((chBits & QuadChans) == QuadChans) {
if ((chBits & QuadChans) == QuadChans)
{
m_mixInfo.m_channels = AudioChannelSet::Quad; m_mixInfo.m_channels = AudioChannelSet::Quad;
return; return;
} }
break; break;
} }
case AudioChannelSet::Surround51: case AudioChannelSet::Surround51: {
{ if ((chBits & S51Chans) == S51Chans) {
if ((chBits & S51Chans) == S51Chans)
{
m_mixInfo.m_channels = AudioChannelSet::Surround51; m_mixInfo.m_channels = AudioChannelSet::Surround51;
return; return;
} }
break; break;
} }
case AudioChannelSet::Surround71: case AudioChannelSet::Surround71: {
{ if ((chBits & S71Chans) == S71Chans) {
if ((chBits & S71Chans) == S71Chans)
{
m_mixInfo.m_channels = AudioChannelSet::Surround71; m_mixInfo.m_channels = AudioChannelSet::Surround71;
return; return;
} }
break; break;
} }
default: break; default:
break;
} }
} }
} }
static void _getSinkInfoReply(pa_context* c, const pa_sink_info* i, int eol, PulseAudioVoiceEngine* userdata) static void _getSinkInfoReply(pa_context* c, const pa_sink_info* i, int eol, PulseAudioVoiceEngine* userdata) {
{
if (!i) if (!i)
return; return;
userdata->m_sampleSpec.format = PA_SAMPLE_FLOAT32; userdata->m_sampleSpec.format = PA_SAMPLE_FLOAT32;
@ -313,13 +268,11 @@ struct PulseAudioVoiceEngine : LinuxMidi
} }
mutable std::vector<std::pair<std::string, std::string>> m_sinks; mutable std::vector<std::pair<std::string, std::string>> m_sinks;
static void _getSinkInfoListReply(pa_context* c, const pa_sink_info* i, int eol, PulseAudioVoiceEngine* userdata) static void _getSinkInfoListReply(pa_context* c, const pa_sink_info* i, int eol, PulseAudioVoiceEngine* userdata) {
{
if (i) if (i)
userdata->m_sinks.push_back(std::make_pair(i->name, i->description)); userdata->m_sinks.push_back(std::make_pair(i->name, i->description));
} }
std::vector<std::pair<std::string, std::string>> enumerateAudioOutputs() const std::vector<std::pair<std::string, std::string>> enumerateAudioOutputs() const {
{
pa_operation* op = pa_context_get_sink_info_list(m_ctx, pa_sink_info_cb_t(_getSinkInfoListReply), (void*)this); pa_operation* op = pa_context_get_sink_info_list(m_ctx, pa_sink_info_cb_t(_getSinkInfoListReply), (void*)this);
_paIterate(op); _paIterate(op);
pa_operation_unref(op); pa_operation_unref(op);
@ -328,47 +281,37 @@ struct PulseAudioVoiceEngine : LinuxMidi
return ret; return ret;
} }
std::string getCurrentAudioOutput() const std::string getCurrentAudioOutput() const { return m_sinkName; }
{
return m_sinkName;
}
bool m_sinkOk = false; bool m_sinkOk = false;
static void _checkAudioSinkReply(pa_context* c, const pa_sink_info* i, int eol, PulseAudioVoiceEngine* userdata) static void _checkAudioSinkReply(pa_context* c, const pa_sink_info* i, int eol, PulseAudioVoiceEngine* userdata) {
{
if (i) if (i)
userdata->m_sinkOk = true; userdata->m_sinkOk = true;
} }
bool setCurrentAudioOutput(const char* name) bool setCurrentAudioOutput(const char* name) {
{
m_sinkOk = false; m_sinkOk = false;
pa_operation* op; pa_operation* op;
op = pa_context_get_sink_info_by_name(m_ctx, name, pa_sink_info_cb_t(_checkAudioSinkReply), this); op = pa_context_get_sink_info_by_name(m_ctx, name, pa_sink_info_cb_t(_checkAudioSinkReply), this);
_paIterate(op); _paIterate(op);
pa_operation_unref(op); pa_operation_unref(op);
if (m_sinkOk) if (m_sinkOk) {
{
m_sinkName = name; m_sinkName = name;
return _setupSink(); return _setupSink();
} }
return false; return false;
} }
void _doIterate() void _doIterate() {
{
int retval; int retval;
pa_mainloop_iterate(m_mainloop, 1, &retval); pa_mainloop_iterate(m_mainloop, 1, &retval);
if (m_handleMove) if (m_handleMove) {
{
m_handleMove = false; m_handleMove = false;
_setupSink(); _setupSink();
} }
} }
void pumpAndMixVoices() void pumpAndMixVoices() {
{ if (!m_stream) {
if (!m_stream)
{
/* Dummy pump mode - use failsafe defaults for 1/60sec of samples */ /* Dummy pump mode - use failsafe defaults for 1/60sec of samples */
m_mixInfo.m_sampleRate = 32000.0; m_mixInfo.m_sampleRate = 32000.0;
m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I; m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I;
@ -388,8 +331,7 @@ struct PulseAudioVoiceEngine : LinuxMidi
size_t writableFrames = writableSz / frameSz; size_t writableFrames = writableSz / frameSz;
size_t writablePeriods = writableFrames / m_mixInfo.m_periodFrames; size_t writablePeriods = writableFrames / m_mixInfo.m_periodFrames;
if (!writablePeriods) if (!writablePeriods) {
{
_doIterate(); _doIterate();
return; return;
} }
@ -397,11 +339,9 @@ struct PulseAudioVoiceEngine : LinuxMidi
void* data; void* data;
size_t periodSz = m_mixInfo.m_periodFrames * frameSz; size_t periodSz = m_mixInfo.m_periodFrames * frameSz;
size_t nbytes = writablePeriods * periodSz; size_t nbytes = writablePeriods * periodSz;
if (pa_stream_begin_write(m_stream, &data, &nbytes)) if (pa_stream_begin_write(m_stream, &data, &nbytes)) {
{
pa_stream_state_t st = pa_stream_get_state(m_stream); pa_stream_state_t st = pa_stream_get_state(m_stream);
Log.report(logvisor::Error, "Unable to pa_stream_begin_write(): %s %d", Log.report(logvisor::Error, "Unable to pa_stream_begin_write(): %s %d", pa_strerror(pa_context_errno(m_ctx)), st);
pa_strerror(pa_context_errno(m_ctx)), st);
_doIterate(); _doIterate();
return; return;
} }
@ -417,9 +357,6 @@ struct PulseAudioVoiceEngine : LinuxMidi
} }
}; };
std::unique_ptr<IAudioVoiceEngine> NewAudioVoiceEngine() std::unique_ptr<IAudioVoiceEngine> NewAudioVoiceEngine() { return std::make_unique<PulseAudioVoiceEngine>(); }
{
return std::make_unique<PulseAudioVoiceEngine>();
}
} } // namespace boo

View File

@ -12,8 +12,9 @@
#ifdef TE_VIRTUAL_MIDI #ifdef TE_VIRTUAL_MIDI
#include <teVirtualMIDI.h> #include <teVirtualMIDI.h>
typedef LPVM_MIDI_PORT (CALLBACK *pfnvirtualMIDICreatePortEx2) typedef LPVM_MIDI_PORT(CALLBACK* pfnvirtualMIDICreatePortEx2)(LPCWSTR portName, LPVM_MIDI_DATA_CB callback,
( LPCWSTR portName, LPVM_MIDI_DATA_CB callback, DWORD_PTR dwCallbackInstance, DWORD maxSysexLength, DWORD flags ); DWORD_PTR dwCallbackInstance, DWORD maxSysexLength,
DWORD flags);
typedef void(CALLBACK* pfnvirtualMIDIClosePort)(LPVM_MIDI_PORT midiPort); typedef void(CALLBACK* pfnvirtualMIDIClosePort)(LPVM_MIDI_PORT midiPort);
typedef BOOL(CALLBACK* pfnvirtualMIDISendData)(LPVM_MIDI_PORT midiPort, LPBYTE midiDataBytes, DWORD length); typedef BOOL(CALLBACK* pfnvirtualMIDISendData)(LPVM_MIDI_PORT midiPort, LPBYTE midiDataBytes, DWORD length);
typedef LPCWSTR(CALLBACK* pfnvirtualMIDIGetDriverVersion)(PWORD major, PWORD minor, PWORD release, PWORD build); typedef LPCWSTR(CALLBACK* pfnvirtualMIDIGetDriverVersion)(PWORD major, PWORD minor, PWORD release, PWORD build);
@ -33,16 +34,16 @@ using namespace Windows::Media::Devices;
const IID IID_IAudioClient = __uuidof(IAudioClient); const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
namespace boo namespace boo {
{
static logvisor::Module Log("boo::WASAPI"); static logvisor::Module Log("boo::WASAPI");
#define SAFE_RELEASE(punk) \ #define SAFE_RELEASE(punk) \
if ((punk) != NULL) \ if ((punk) != NULL) { \
{ (punk)->Release(); (punk) = NULL; } (punk)->Release(); \
(punk) = NULL; \
}
struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine {
{
#if !WINDOWS_STORE #if !WINDOWS_STORE
ComPtr<IMMDeviceEnumerator> m_enumerator; ComPtr<IMMDeviceEnumerator> m_enumerator;
ComPtr<IMMDevice> m_device; ComPtr<IMMDevice> m_device;
@ -57,57 +58,38 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
std::vector<float> m_5msBuffer; std::vector<float> m_5msBuffer;
#if !WINDOWS_STORE #if !WINDOWS_STORE
struct NotificationClient final : public IMMNotificationClient struct NotificationClient final : public IMMNotificationClient {
{
WASAPIAudioVoiceEngine& m_parent; WASAPIAudioVoiceEngine& m_parent;
LONG _cRef; LONG _cRef;
IMMDeviceEnumerator* _pEnumerator; IMMDeviceEnumerator* _pEnumerator;
NotificationClient(WASAPIAudioVoiceEngine& parent) NotificationClient(WASAPIAudioVoiceEngine& parent) : m_parent(parent), _cRef(1), _pEnumerator(nullptr) {}
: m_parent(parent),
_cRef(1),
_pEnumerator(nullptr)
{}
~NotificationClient()
{
SAFE_RELEASE(_pEnumerator)
}
~NotificationClient(){SAFE_RELEASE(_pEnumerator)}
// IUnknown methods -- AddRef, Release, and QueryInterface // IUnknown methods -- AddRef, Release, and QueryInterface
ULONG STDMETHODCALLTYPE AddRef() ULONG STDMETHODCALLTYPE AddRef() {
{
return InterlockedIncrement(&_cRef); return InterlockedIncrement(&_cRef);
} }
ULONG STDMETHODCALLTYPE Release() ULONG STDMETHODCALLTYPE Release() {
{
ULONG ulRef = InterlockedDecrement(&_cRef); ULONG ulRef = InterlockedDecrement(&_cRef);
if (0 == ulRef) if (0 == ulRef) {
{
delete this; delete this;
} }
return ulRef; return ulRef;
} }
HRESULT STDMETHODCALLTYPE QueryInterface( HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface) {
REFIID riid, VOID **ppvInterface) if (IID_IUnknown == riid) {
{
if (IID_IUnknown == riid)
{
AddRef(); AddRef();
*ppvInterface = (IUnknown*)this; *ppvInterface = (IUnknown*)this;
} } else if (__uuidof(IMMNotificationClient) == riid) {
else if (__uuidof(IMMNotificationClient) == riid)
{
AddRef(); AddRef();
*ppvInterface = (IMMNotificationClient*)this; *ppvInterface = (IMMNotificationClient*)this;
} } else {
else
{
*ppvInterface = NULL; *ppvInterface = NULL;
return E_NOINTERFACE; return E_NOINTERFACE;
} }
@ -116,55 +98,32 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
// Callback methods for device-event notifications. // Callback methods for device-event notifications.
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged( HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) {
EDataFlow flow, ERole role,
LPCWSTR pwstrDeviceId)
{
m_parent.m_rebuild = true; m_parent.m_rebuild = true;
return S_OK; return S_OK;
} }
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) { return S_OK; }
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) { return S_OK; }
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged( HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) { return S_OK; }
LPCWSTR pwstrDeviceId,
DWORD dwNewState)
{
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged( HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) { return S_OK; }
LPCWSTR pwstrDeviceId,
const PROPERTYKEY key)
{
return S_OK;
}
} m_notificationClient; } m_notificationClient;
#endif #endif
void _buildAudioRenderClient() void _buildAudioRenderClient() {
{
#if !WINDOWS_STORE #if !WINDOWS_STORE
if (!m_device) if (!m_device) {
{ if (FAILED(m_enumerator->GetDevice(MBSTWCS(m_sinkName.c_str()).c_str(), &m_device))) {
if (FAILED(m_enumerator->GetDevice(MBSTWCS(m_sinkName.c_str()).c_str(), &m_device)))
{
Log.report(logvisor::Error, "unable to obtain audio device %s", m_sinkName.c_str()); Log.report(logvisor::Error, "unable to obtain audio device %s", m_sinkName.c_str());
m_device.Reset(); m_device.Reset();
return; return;
} }
} }
if (FAILED(m_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, &m_audClient))) if (FAILED(m_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, &m_audClient))) {
{
Log.report(logvisor::Error, L"unable to create audio client from device"); Log.report(logvisor::Error, L"unable to create audio client from device");
m_device.Reset(); m_device.Reset();
return; return;
@ -172,8 +131,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
#endif #endif
WAVEFORMATEXTENSIBLE* pwfx; WAVEFORMATEXTENSIBLE* pwfx;
if (FAILED(m_audClient->GetMixFormat((WAVEFORMATEX**)&pwfx))) if (FAILED(m_audClient->GetMixFormat((WAVEFORMATEX**)&pwfx))) {
{
Log.report(logvisor::Error, L"unable to obtain audio mix format from device"); Log.report(logvisor::Error, L"unable to obtain audio mix format from device");
#if !WINDOWS_STORE #if !WINDOWS_STORE
m_device.Reset(); m_device.Reset();
@ -182,17 +140,17 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
/* Get channel information */ /* Get channel information */
if ((pwfx->dwChannelMask & (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)) == (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)) if ((pwfx->dwChannelMask & (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)) ==
{ (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)) {
m_mixInfo.m_channels = AudioChannelSet::Stereo; m_mixInfo.m_channels = AudioChannelSet::Stereo;
if ((pwfx->dwChannelMask & (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)) == (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)) if ((pwfx->dwChannelMask & (SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)) ==
{ (SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)) {
m_mixInfo.m_channels = AudioChannelSet::Quad; m_mixInfo.m_channels = AudioChannelSet::Quad;
if ((pwfx->dwChannelMask & (SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY)) == (SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY)) if ((pwfx->dwChannelMask & (SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY)) ==
{ (SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY)) {
m_mixInfo.m_channels = AudioChannelSet::Surround51; m_mixInfo.m_channels = AudioChannelSet::Surround51;
if ((pwfx->dwChannelMask & (SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)) == (SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)) if ((pwfx->dwChannelMask & (SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)) ==
{ (SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)) {
m_mixInfo.m_channels = AudioChannelSet::Surround71; m_mixInfo.m_channels = AudioChannelSet::Surround71;
} }
} }
@ -200,8 +158,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
ChannelMap& chMapOut = m_mixInfo.m_channelMap; ChannelMap& chMapOut = m_mixInfo.m_channelMap;
switch (pwfx->Format.nChannels) switch (pwfx->Format.nChannels) {
{
case 2: case 2:
chMapOut.m_channelCount = 2; chMapOut.m_channelCount = 2;
chMapOut.m_channels[0] = AudioChannel::FrontLeft; chMapOut.m_channels[0] = AudioChannel::FrontLeft;
@ -251,14 +208,8 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
/* Initialize audio client */ /* Initialize audio client */
if (FAILED(m_audClient->Initialize( if (FAILED(m_audClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 450000, /* 45ms */
AUDCLNT_SHAREMODE_SHARED, 0, (WAVEFORMATEX*)pwfx, nullptr))) {
0,
450000, /* 45ms */
0,
(WAVEFORMATEX*)pwfx,
nullptr)))
{
Log.report(logvisor::Error, L"unable to initialize audio client"); Log.report(logvisor::Error, L"unable to initialize audio client");
#if !WINDOWS_STORE #if !WINDOWS_STORE
m_device.Reset(); m_device.Reset();
@ -272,37 +223,27 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
m_5msBuffer.resize(m_5msFrames * chMapOut.m_channelCount); m_5msBuffer.resize(m_5msFrames * chMapOut.m_channelCount);
if (pwfx->Format.wFormatTag == WAVE_FORMAT_PCM || if (pwfx->Format.wFormatTag == WAVE_FORMAT_PCM ||
(pwfx->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && pwfx->SubFormat == KSDATAFORMAT_SUBTYPE_PCM)) (pwfx->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && pwfx->SubFormat == KSDATAFORMAT_SUBTYPE_PCM)) {
{ if (pwfx->Format.wBitsPerSample == 16) {
if (pwfx->Format.wBitsPerSample == 16)
{
m_mixInfo.m_sampleFormat = SOXR_INT16_I; m_mixInfo.m_sampleFormat = SOXR_INT16_I;
m_mixInfo.m_bitsPerSample = 16; m_mixInfo.m_bitsPerSample = 16;
} } else if (pwfx->Format.wBitsPerSample == 32) {
else if (pwfx->Format.wBitsPerSample == 32)
{
m_mixInfo.m_sampleFormat = SOXR_INT32_I; m_mixInfo.m_sampleFormat = SOXR_INT32_I;
m_mixInfo.m_bitsPerSample = 32; m_mixInfo.m_bitsPerSample = 32;
} } else {
else
{
Log.report(logvisor::Fatal, L"unsupported bits-per-sample %d", pwfx->Format.wBitsPerSample); Log.report(logvisor::Fatal, L"unsupported bits-per-sample %d", pwfx->Format.wBitsPerSample);
#if !WINDOWS_STORE #if !WINDOWS_STORE
m_device.Reset(); m_device.Reset();
#endif #endif
return; return;
} }
} } else if (pwfx->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
else if (pwfx->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT || (pwfx->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
(pwfx->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && pwfx->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) pwfx->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
{ if (pwfx->Format.wBitsPerSample == 32) {
if (pwfx->Format.wBitsPerSample == 32)
{
m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I; m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I;
m_mixInfo.m_bitsPerSample = 32; m_mixInfo.m_bitsPerSample = 32;
} } else {
else
{
Log.report(logvisor::Error, L"unsupported floating-point bits-per-sample %d", pwfx->Format.wBitsPerSample); Log.report(logvisor::Error, L"unsupported floating-point bits-per-sample %d", pwfx->Format.wBitsPerSample);
#if !WINDOWS_STORE #if !WINDOWS_STORE
m_device.Reset(); m_device.Reset();
@ -314,8 +255,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
CoTaskMemFree(pwfx); CoTaskMemFree(pwfx);
UINT32 bufferFrameCount; UINT32 bufferFrameCount;
if (FAILED(m_audClient->GetBufferSize(&bufferFrameCount))) if (FAILED(m_audClient->GetBufferSize(&bufferFrameCount))) {
{
Log.report(logvisor::Error, L"unable to get audio buffer frame count"); Log.report(logvisor::Error, L"unable to get audio buffer frame count");
#if !WINDOWS_STORE #if !WINDOWS_STORE
m_device.Reset(); m_device.Reset();
@ -324,8 +264,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
m_mixInfo.m_periodFrames = bufferFrameCount; m_mixInfo.m_periodFrames = bufferFrameCount;
if (FAILED(m_audClient->GetService(IID_IAudioRenderClient, &m_renderClient))) if (FAILED(m_audClient->GetService(IID_IAudioRenderClient, &m_renderClient))) {
{
Log.report(logvisor::Error, L"unable to create audio render client"); Log.report(logvisor::Error, L"unable to create audio render client");
#if !WINDOWS_STORE #if !WINDOWS_STORE
m_device.Reset(); m_device.Reset();
@ -335,55 +274,40 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
#if WINDOWS_STORE #if WINDOWS_STORE
struct CompletionHandler : IActivateAudioInterfaceCompletionHandler struct CompletionHandler : IActivateAudioInterfaceCompletionHandler {
{
WASAPIAudioVoiceEngine& e; WASAPIAudioVoiceEngine& e;
LONG _cRef = 1; LONG _cRef = 1;
CompletionHandler(WASAPIAudioVoiceEngine& e) : e(e) {} CompletionHandler(WASAPIAudioVoiceEngine& e) : e(e) {}
HRESULT ActivateCompleted(IActivateAudioInterfaceAsyncOperation* operation) HRESULT ActivateCompleted(IActivateAudioInterfaceAsyncOperation* operation) {
{
return e.ActivateCompleted(operation); return e.ActivateCompleted(operation);
} }
ULONG STDMETHODCALLTYPE AddRef() ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&_cRef); }
{
return InterlockedIncrement(&_cRef);
}
ULONG STDMETHODCALLTYPE Release() ULONG STDMETHODCALLTYPE Release() {
{
ULONG ulRef = InterlockedDecrement(&_cRef); ULONG ulRef = InterlockedDecrement(&_cRef);
if (0 == ulRef) if (0 == ulRef) {
{
delete this; delete this;
} }
return ulRef; return ulRef;
} }
HRESULT STDMETHODCALLTYPE QueryInterface( HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface) {
REFIID riid, VOID **ppvInterface) if (IID_IUnknown == riid) {
{
if (IID_IUnknown == riid)
{
AddRef(); AddRef();
*ppvInterface = (IUnknown*)this; *ppvInterface = (IUnknown*)this;
} } else if (__uuidof(IActivateAudioInterfaceCompletionHandler) == riid) {
else if (__uuidof(IActivateAudioInterfaceCompletionHandler) == riid)
{
AddRef(); AddRef();
*ppvInterface = (IActivateAudioInterfaceCompletionHandler*)this; *ppvInterface = (IActivateAudioInterfaceCompletionHandler*)this;
} } else {
else
{
*ppvInterface = NULL; *ppvInterface = NULL;
return E_NOINTERFACE; return E_NOINTERFACE;
} }
return S_OK; return S_OK;
} }
} m_completion = {*this}; } m_completion = {*this};
HRESULT ActivateCompleted(IActivateAudioInterfaceAsyncOperation* operation) HRESULT ActivateCompleted(IActivateAudioInterfaceAsyncOperation* operation) {
{
ComPtr<IUnknown> punkAudioInterface; ComPtr<IUnknown> punkAudioInterface;
HRESULT hrActivateResult; HRESULT hrActivateResult;
operation->GetActivateResult(&hrActivateResult, &punkAudioInterface); operation->GetActivateResult(&hrActivateResult, &punkAudioInterface);
@ -402,12 +326,13 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
#if !WINDOWS_STORE #if !WINDOWS_STORE
#ifdef TE_VIRTUAL_MIDI #ifdef TE_VIRTUAL_MIDI
HMODULE virtualMidiModule; HMODULE virtualMidiModule;
if (!virtualMIDICreatePortEx2PROC && (virtualMidiModule = LoadLibraryW(L"teVirtualMIDI64.dll"))) if (!virtualMIDICreatePortEx2PROC && (virtualMidiModule = LoadLibraryW(L"teVirtualMIDI64.dll"))) {
{ virtualMIDICreatePortEx2PROC =
virtualMIDICreatePortEx2PROC = (pfnvirtualMIDICreatePortEx2)GetProcAddress(virtualMidiModule, "virtualMIDICreatePortEx2"); (pfnvirtualMIDICreatePortEx2)GetProcAddress(virtualMidiModule, "virtualMIDICreatePortEx2");
virtualMIDIClosePortPROC = (pfnvirtualMIDIClosePort)GetProcAddress(virtualMidiModule, "virtualMIDIClosePort"); virtualMIDIClosePortPROC = (pfnvirtualMIDIClosePort)GetProcAddress(virtualMidiModule, "virtualMIDIClosePort");
virtualMIDISendDataPROC = (pfnvirtualMIDISendData)GetProcAddress(virtualMidiModule, "virtualMIDISendData"); virtualMIDISendDataPROC = (pfnvirtualMIDISendData)GetProcAddress(virtualMidiModule, "virtualMIDISendData");
virtualMIDIGetDriverVersionPROC = (pfnvirtualMIDIGetDriverVersion)GetProcAddress(virtualMidiModule, "virtualMIDIGetDriverVersion"); virtualMIDIGetDriverVersionPROC =
(pfnvirtualMIDIGetDriverVersion)GetProcAddress(virtualMidiModule, "virtualMIDIGetDriverVersion");
LARGE_INTEGER pf; LARGE_INTEGER pf;
QueryPerformanceFrequency(&pf); QueryPerformanceFrequency(&pf);
PerfFrequency = double(pf.QuadPart); PerfFrequency = double(pf.QuadPart);
@ -415,23 +340,19 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
#endif #endif
/* Enumerate default audio device */ /* Enumerate default audio device */
if (FAILED(CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, if (FAILED(
CLSCTX_ALL, IID_IMMDeviceEnumerator, CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, &m_enumerator))) {
&m_enumerator)))
{
Log.report(logvisor::Error, L"unable to create MMDeviceEnumerator instance"); Log.report(logvisor::Error, L"unable to create MMDeviceEnumerator instance");
return; return;
} }
if (FAILED(m_enumerator->RegisterEndpointNotificationCallback(&m_notificationClient))) if (FAILED(m_enumerator->RegisterEndpointNotificationCallback(&m_notificationClient))) {
{
Log.report(logvisor::Error, L"unable to register multimedia event callback"); Log.report(logvisor::Error, L"unable to register multimedia event callback");
m_device.Reset(); m_device.Reset();
return; return;
} }
if (FAILED(m_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_device))) if (FAILED(m_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_device))) {
{
Log.report(logvisor::Error, L"unable to obtain default audio device"); Log.report(logvisor::Error, L"unable to obtain default audio device");
m_device.Reset(); m_device.Reset();
return; return;
@ -452,8 +373,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
bool m_started = false; bool m_started = false;
bool m_rebuild = false; bool m_rebuild = false;
void _rebuildAudioRenderClient() void _rebuildAudioRenderClient() {
{
soxr_datatype_t oldFmt = m_mixInfo.m_sampleFormat; soxr_datatype_t oldFmt = m_mixInfo.m_sampleFormat;
_buildAudioRenderClient(); _buildAudioRenderClient();
@ -466,8 +386,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
_resetSampleRate(); _resetSampleRate();
} }
void pumpAndMixVoices() void pumpAndMixVoices() {
{
#if WINDOWS_STORE #if WINDOWS_STORE
if (!m_ready) if (!m_ready)
return; return;
@ -477,23 +396,19 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
#endif #endif
int attempt = 0; int attempt = 0;
while (true) while (true) {
{
if (attempt >= 10) if (attempt >= 10)
Log.report(logvisor::Fatal, L"unable to setup AudioRenderClient"); Log.report(logvisor::Fatal, L"unable to setup AudioRenderClient");
if (m_rebuild) if (m_rebuild) {
{
m_device.Reset(); m_device.Reset();
_rebuildAudioRenderClient(); _rebuildAudioRenderClient();
} }
HRESULT res; HRESULT res;
if (!m_started) if (!m_started) {
{
res = m_audClient->Start(); res = m_audClient->Start();
if (FAILED(res)) if (FAILED(res)) {
{
m_rebuild = true; m_rebuild = true;
++attempt; ++attempt;
continue; continue;
@ -503,8 +418,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
UINT32 numFramesPadding; UINT32 numFramesPadding;
res = m_audClient->GetCurrentPadding(&numFramesPadding); res = m_audClient->GetCurrentPadding(&numFramesPadding);
if (FAILED(res)) if (FAILED(res)) {
{
m_rebuild = true; m_rebuild = true;
++attempt; ++attempt;
continue; continue;
@ -516,24 +430,20 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
BYTE* bufOut; BYTE* bufOut;
res = m_renderClient->GetBuffer(frames, &bufOut); res = m_renderClient->GetBuffer(frames, &bufOut);
if (FAILED(res)) if (FAILED(res)) {
{
m_rebuild = true; m_rebuild = true;
++attempt; ++attempt;
continue; continue;
} }
for (size_t f=0 ; f<frames ;) for (size_t f = 0; f < frames;) {
{ if (m_curBufFrame == m_5msFrames) {
if (m_curBufFrame == m_5msFrames)
{
_pumpAndMixVoices(m_5msFrames, m_5msBuffer.data()); _pumpAndMixVoices(m_5msFrames, m_5msBuffer.data());
m_curBufFrame = 0; m_curBufFrame = 0;
} }
size_t remRenderFrames = std::min(frames - f, m_5msFrames - m_curBufFrame); size_t remRenderFrames = std::min(frames - f, m_5msFrames - m_curBufFrame);
if (remRenderFrames) if (remRenderFrames) {
{
memmove(reinterpret_cast<float*>(bufOut) + m_mixInfo.m_channelMap.m_channelCount * f, memmove(reinterpret_cast<float*>(bufOut) + m_mixInfo.m_channelMap.m_channelCount * f,
&m_5msBuffer[m_curBufFrame * m_mixInfo.m_channelMap.m_channelCount], &m_5msBuffer[m_curBufFrame * m_mixInfo.m_channelMap.m_channelCount],
remRenderFrames * m_mixInfo.m_channelMap.m_channelCount * sizeof(float)); remRenderFrames * m_mixInfo.m_channelMap.m_channelCount * sizeof(float));
@ -543,8 +453,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
res = m_renderClient->ReleaseBuffer(frames, 0); res = m_renderClient->ReleaseBuffer(frames, 0);
if (FAILED(res)) if (FAILED(res)) {
{
m_rebuild = true; m_rebuild = true;
++attempt; ++attempt;
continue; continue;
@ -554,16 +463,11 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
} }
std::string getCurrentAudioOutput() const std::string getCurrentAudioOutput() const { return m_sinkName; }
{
return m_sinkName;
}
bool setCurrentAudioOutput(const char* name) bool setCurrentAudioOutput(const char* name) {
{
ComPtr<IMMDevice> newDevice; ComPtr<IMMDevice> newDevice;
if (FAILED(m_enumerator->GetDevice(MBSTWCS(name).c_str(), &newDevice))) if (FAILED(m_enumerator->GetDevice(MBSTWCS(name).c_str(), &newDevice))) {
{
Log.report(logvisor::Error, "unable to obtain audio device %s", name); Log.report(logvisor::Error, "unable to obtain audio device %s", name);
return false; return false;
} }
@ -573,21 +477,18 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
return true; return true;
} }
std::vector<std::pair<std::string, std::string>> enumerateAudioOutputs() const std::vector<std::pair<std::string, std::string>> enumerateAudioOutputs() const {
{
std::vector<std::pair<std::string, std::string>> ret; std::vector<std::pair<std::string, std::string>> ret;
ComPtr<IMMDeviceCollection> collection; ComPtr<IMMDeviceCollection> collection;
if (FAILED(m_enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &collection))) if (FAILED(m_enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &collection))) {
{
Log.report(logvisor::Error, L"unable to enumerate audio outputs"); Log.report(logvisor::Error, L"unable to enumerate audio outputs");
return ret; return ret;
} }
UINT count = 0; UINT count = 0;
collection->GetCount(&count); collection->GetCount(&count);
for (UINT i = 0; i < count; ++i) for (UINT i = 0; i < count; ++i) {
{
ComPtr<IMMDevice> device; ComPtr<IMMDevice> device;
collection->Item(i, &device); collection->Item(i, &device);
LPWSTR devName; LPWSTR devName;
@ -606,15 +507,13 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
#if !WINDOWS_STORE #if !WINDOWS_STORE
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;
UINT numInDevices = midiInGetNumDevs(); UINT numInDevices = midiInGetNumDevs();
ret.reserve(numInDevices); ret.reserve(numInDevices);
for (UINT i=0 ; i<numInDevices ; ++i) for (UINT i = 0; i < numInDevices; ++i) {
{
char name[256]; char name[256];
snprintf(name, 256, "in%u", i); snprintf(name, 256, "in%u", i);
@ -650,8 +549,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
return ret; return ret;
} }
bool supportsVirtualMIDIIn() const bool supportsVirtualMIDIIn() const {
{
#ifdef TE_VIRTUAL_MIDI #ifdef TE_VIRTUAL_MIDI
WORD major, minor, release, build; WORD major, minor, release, build;
return virtualMIDIGetDriverVersionPROC && return virtualMIDIGetDriverVersionPROC &&
@ -662,11 +560,8 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
#ifdef TE_VIRTUAL_MIDI #ifdef TE_VIRTUAL_MIDI
static void CALLBACK VirtualMIDIReceiveProc(LPVM_MIDI_PORT midiPort, static void CALLBACK VirtualMIDIReceiveProc(LPVM_MIDI_PORT midiPort, LPBYTE midiDataBytes, DWORD length,
LPBYTE midiDataBytes, IMIDIReceiver* dwInstance) {
DWORD length,
IMIDIReceiver* dwInstance)
{
std::vector<uint8_t> bytes; std::vector<uint8_t> bytes;
bytes.resize(length); bytes.resize(length);
memcpy(&bytes[0], midiDataBytes, length); memcpy(&bytes[0], midiDataBytes, length);
@ -680,14 +575,9 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
#endif #endif
static void CALLBACK MIDIReceiveProc(HMIDIIN hMidiIn, static void CALLBACK MIDIReceiveProc(HMIDIIN hMidiIn, UINT wMsg, IMIDIReceiver* dwInstance, DWORD_PTR dwParam1,
UINT wMsg, DWORD_PTR dwParam2) {
IMIDIReceiver* dwInstance, if (wMsg == MIM_DATA) {
DWORD_PTR dwParam1,
DWORD_PTR dwParam2)
{
if (wMsg == MIM_DATA)
{
uint8_t(&ptr)[3] = reinterpret_cast<uint8_t(&)[3]>(dwParam1); uint8_t(&ptr)[3] = reinterpret_cast<uint8_t(&)[3]>(dwParam1);
std::vector<uint8_t> bytes(std::cbegin(ptr), std::cend(ptr)); std::vector<uint8_t> bytes(std::cbegin(ptr), std::cend(ptr));
dwInstance->m_receiver(std::move(bytes), dwParam2 / 1000.0); dwInstance->m_receiver(std::move(bytes), dwParam2 / 1000.0);
@ -695,84 +585,54 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
#ifdef TE_VIRTUAL_MIDI #ifdef TE_VIRTUAL_MIDI
struct VMIDIIn : public IMIDIIn struct VMIDIIn : public IMIDIIn {
{
LPVM_MIDI_PORT m_midi = 0; LPVM_MIDI_PORT m_midi = 0;
VMIDIIn(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) VMIDIIn(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) : IMIDIIn(parent, true, std::move(receiver)) {}
: IMIDIIn(parent, true, std::move(receiver)) {}
~VMIDIIn() ~VMIDIIn() { virtualMIDIClosePortPROC(m_midi); }
{
virtualMIDIClosePortPROC(m_midi);
}
std::string description() const std::string description() const { return "Virtual MIDI-In"; }
{
return "Virtual MIDI-In";
}
}; };
struct VMIDIOut : public IMIDIOut struct VMIDIOut : public IMIDIOut {
{
LPVM_MIDI_PORT m_midi = 0; LPVM_MIDI_PORT m_midi = 0;
VMIDIOut(WASAPIAudioVoiceEngine* parent) : IMIDIOut(parent, true) {} VMIDIOut(WASAPIAudioVoiceEngine* parent) : IMIDIOut(parent, true) {}
~VMIDIOut() ~VMIDIOut() { virtualMIDIClosePortPROC(m_midi); }
{
virtualMIDIClosePortPROC(m_midi);
}
std::string description() const std::string description() const { return "Virtual MIDI-Out"; }
{
return "Virtual MIDI-Out";
}
size_t send(const void* buf, size_t len) const size_t send(const void* buf, size_t len) const {
{
return virtualMIDISendDataPROC(m_midi, (LPBYTE)buf, len) ? len : 0; return virtualMIDISendDataPROC(m_midi, (LPBYTE)buf, len) ? len : 0;
} }
}; };
struct VMIDIInOut : public IMIDIInOut struct VMIDIInOut : public IMIDIInOut {
{
LPVM_MIDI_PORT m_midi = 0; LPVM_MIDI_PORT m_midi = 0;
VMIDIInOut(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) VMIDIInOut(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver)
: IMIDIInOut(parent, true, std::move(receiver)) {} : IMIDIInOut(parent, true, std::move(receiver)) {}
~VMIDIInOut() ~VMIDIInOut() { virtualMIDIClosePortPROC(m_midi); }
{
virtualMIDIClosePortPROC(m_midi);
}
std::string description() const std::string description() const { return "Virtual MIDI-In/Out"; }
{
return "Virtual MIDI-In/Out";
}
size_t send(const void* buf, size_t len) const size_t send(const void* buf, size_t len) const {
{
return virtualMIDISendDataPROC(m_midi, (LPBYTE)buf, len) ? len : 0; return virtualMIDISendDataPROC(m_midi, (LPBYTE)buf, len) ? len : 0;
} }
}; };
#endif #endif
struct MIDIIn : public IMIDIIn struct MIDIIn : public IMIDIIn {
{
HMIDIIN m_midi = 0; HMIDIIN m_midi = 0;
MIDIIn(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) MIDIIn(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) : IMIDIIn(parent, false, std::move(receiver)) {}
: IMIDIIn(parent, false, std::move(receiver)) {}
~MIDIIn() ~MIDIIn() { midiInClose(m_midi); }
{
midiInClose(m_midi);
}
std::string description() const std::string description() const {
{
UINT id = 0; UINT id = 0;
midiInGetID(m_midi, &id); midiInGetID(m_midi, &id);
MIDIINCAPS caps; MIDIINCAPS caps;
@ -787,8 +647,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
}; };
struct MIDIOut : public IMIDIOut struct MIDIOut : public IMIDIOut {
{
HMIDIOUT m_midi = 0; HMIDIOUT m_midi = 0;
HMIDISTRM m_strm = 0; HMIDISTRM m_strm = 0;
uint8_t m_buf[512]; uint8_t m_buf[512];
@ -796,8 +655,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
MIDIOut(WASAPIAudioVoiceEngine* parent) : IMIDIOut(parent, false) {} MIDIOut(WASAPIAudioVoiceEngine* parent) : IMIDIOut(parent, false) {}
void prepare() void prepare() {
{
UINT id = 0; UINT id = 0;
midiOutGetID(m_midi, &id); midiOutGetID(m_midi, &id);
@ -808,15 +666,13 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
midiStreamOpen(&m_strm, &id, 1, NULL, NULL, CALLBACK_NULL); midiStreamOpen(&m_strm, &id, 1, NULL, NULL, CALLBACK_NULL);
} }
~MIDIOut() ~MIDIOut() {
{
midiStreamClose(m_strm); midiStreamClose(m_strm);
midiOutUnprepareHeader(m_midi, &m_hdr, sizeof(m_hdr)); midiOutUnprepareHeader(m_midi, &m_hdr, sizeof(m_hdr));
midiOutClose(m_midi); midiOutClose(m_midi);
} }
std::string description() const std::string description() const {
{
UINT id = 0; UINT id = 0;
midiOutGetID(m_midi, &id); midiOutGetID(m_midi, &id);
MIDIOUTCAPS caps; MIDIOUTCAPS caps;
@ -830,8 +686,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
#endif #endif
} }
size_t send(const void* buf, size_t len) const size_t send(const void* buf, size_t len) const {
{
memcpy(const_cast<MIDIOut*>(this)->m_buf, buf, std::min(len, size_t(512))); memcpy(const_cast<MIDIOut*>(this)->m_buf, buf, std::min(len, size_t(512)));
const_cast<MIDIOut*>(this)->m_hdr.dwBytesRecorded = len; const_cast<MIDIOut*>(this)->m_hdr.dwBytesRecorded = len;
midiStreamOut(m_strm, LPMIDIHDR(&m_hdr), sizeof(m_hdr)); midiStreamOut(m_strm, LPMIDIHDR(&m_hdr), sizeof(m_hdr));
@ -839,8 +694,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
}; };
struct MIDIInOut : public IMIDIInOut struct MIDIInOut : public IMIDIInOut {
{
HMIDIIN m_midiIn = 0; HMIDIIN m_midiIn = 0;
HMIDIOUT m_midiOut = 0; HMIDIOUT m_midiOut = 0;
HMIDISTRM m_strm = 0; HMIDISTRM m_strm = 0;
@ -850,8 +704,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
MIDIInOut(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver) MIDIInOut(WASAPIAudioVoiceEngine* parent, ReceiveFunctor&& receiver)
: IMIDIInOut(parent, false, std::move(receiver)) {} : IMIDIInOut(parent, false, std::move(receiver)) {}
void prepare() void prepare() {
{
UINT id = 0; UINT id = 0;
midiOutGetID(m_midiOut, &id); midiOutGetID(m_midiOut, &id);
@ -862,16 +715,14 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
midiStreamOpen(&m_strm, &id, 1, NULL, NULL, CALLBACK_NULL); midiStreamOpen(&m_strm, &id, 1, NULL, NULL, CALLBACK_NULL);
} }
~MIDIInOut() ~MIDIInOut() {
{
midiInClose(m_midiIn); midiInClose(m_midiIn);
midiStreamClose(m_strm); midiStreamClose(m_strm);
midiOutUnprepareHeader(m_midiOut, &m_hdr, sizeof(m_hdr)); midiOutUnprepareHeader(m_midiOut, &m_hdr, sizeof(m_hdr));
midiOutClose(m_midiOut); midiOutClose(m_midiOut);
} }
std::string description() const std::string description() const {
{
UINT id = 0; UINT id = 0;
midiOutGetID(m_midiOut, &id); midiOutGetID(m_midiOut, &id);
MIDIOUTCAPS caps; MIDIOUTCAPS caps;
@ -885,8 +736,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
#endif #endif
} }
size_t send(const void* buf, size_t len) const size_t send(const void* buf, size_t len) const {
{
memcpy(const_cast<uint8_t*>(m_buf), buf, std::min(len, size_t(512))); memcpy(const_cast<uint8_t*>(m_buf), buf, std::min(len, size_t(512)));
const_cast<MIDIHDR&>(m_hdr).dwBytesRecorded = len; const_cast<MIDIHDR&>(m_hdr).dwBytesRecorded = len;
midiStreamOut(m_strm, LPMIDIHDR(&m_hdr), sizeof(m_hdr)); midiStreamOut(m_strm, LPMIDIHDR(&m_hdr), sizeof(m_hdr));
@ -894,8 +744,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
} }
}; };
std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver) std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver) {
{
#ifdef TE_VIRTUAL_MIDI #ifdef TE_VIRTUAL_MIDI
if (!virtualMIDICreatePortEx2PROC) if (!virtualMIDICreatePortEx2PROC)
return {}; return {};
@ -917,8 +766,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
#endif #endif
} }
std::unique_ptr<IMIDIOut> newVirtualMIDIOut() std::unique_ptr<IMIDIOut> newVirtualMIDIOut() {
{
#ifdef TE_VIRTUAL_MIDI #ifdef TE_VIRTUAL_MIDI
if (!virtualMIDICreatePortEx2PROC) if (!virtualMIDICreatePortEx2PROC)
return {}; return {};
@ -939,8 +787,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
#endif #endif
} }
std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver) std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver) {
{
#ifdef TE_VIRTUAL_MIDI #ifdef TE_VIRTUAL_MIDI
if (!virtualMIDICreatePortEx2PROC) if (!virtualMIDICreatePortEx2PROC)
return {}; return {};
@ -950,9 +797,9 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
return {}; return {};
SystemString name = SystemString(APP->getFriendlyName()) + _SYS_STR(" MIDI-In/Out"); SystemString name = SystemString(APP->getFriendlyName()) + _SYS_STR(" MIDI-In/Out");
auto port = virtualMIDICreatePortEx2PROC(name.c_str(), LPVM_MIDI_DATA_CB(VirtualMIDIReceiveProc), auto port =
DWORD_PTR(static_cast<IMIDIReceiver*>(ret.get())), 512, virtualMIDICreatePortEx2PROC(name.c_str(), LPVM_MIDI_DATA_CB(VirtualMIDIReceiveProc),
TE_VM_FLAGS_SUPPORTED); DWORD_PTR(static_cast<IMIDIReceiver*>(ret.get())), 512, TE_VM_FLAGS_SUPPORTED);
if (!port) if (!port)
return {}; return {};
static_cast<VMIDIInOut&>(*ret).m_midi = port; static_cast<VMIDIInOut&>(*ret).m_midi = port;
@ -962,8 +809,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
#endif #endif
} }
std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) {
{
if (strncmp(name, "in", 2)) if (strncmp(name, "in", 2))
return {}; return {};
long id = strtol(name + 2, nullptr, 10); long id = strtol(name + 2, nullptr, 10);
@ -980,8 +826,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
return ret; return ret;
} }
std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name) std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name) {
{
if (strncmp(name, "out", 3)) if (strncmp(name, "out", 3))
return {}; return {};
long id = strtol(name + 3, nullptr, 10); long id = strtol(name + 3, nullptr, 10);
@ -990,16 +835,14 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
if (!ret) if (!ret)
return {}; return {};
if (FAILED(midiOutOpen(&static_cast<MIDIOut&>(*ret).m_midi, id, NULL, if (FAILED(midiOutOpen(&static_cast<MIDIOut&>(*ret).m_midi, id, NULL, NULL, CALLBACK_NULL)))
NULL, CALLBACK_NULL)))
return {}; return {};
static_cast<MIDIOut&>(*ret).prepare(); static_cast<MIDIOut&>(*ret).prepare();
return ret; return ret;
} }
std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) {
{
const char* in = strstr(name, "in"); const char* in = strstr(name, "in");
const char* out = strstr(name, "out"); const char* out = strstr(name, "out");
@ -1018,8 +861,7 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
return {}; return {};
midiInStart(static_cast<MIDIInOut&>(*ret).m_midiIn); midiInStart(static_cast<MIDIInOut&>(*ret).m_midiIn);
if (FAILED(midiOutOpen(&static_cast<MIDIInOut&>(*ret).m_midiOut, outId, NULL, if (FAILED(midiOutOpen(&static_cast<MIDIInOut&>(*ret).m_midiOut, outId, NULL, NULL, CALLBACK_NULL)))
NULL, CALLBACK_NULL)))
return {}; return {};
static_cast<MIDIInOut&>(*ret).prepare(); static_cast<MIDIInOut&>(*ret).prepare();
@ -1028,48 +870,24 @@ struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
bool useMIDILock() const { return true; } bool useMIDILock() const { return true; }
#else #else
std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices() const std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices() const { return {}; }
{
return {};
}
std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver) std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver) { return {}; }
{
return {};
}
std::unique_ptr<IMIDIOut> newVirtualMIDIOut() std::unique_ptr<IMIDIOut> newVirtualMIDIOut() { return {}; }
{
return {};
}
std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver) std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver) { return {}; }
{
return {};
}
std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) { return {}; }
{
return {};
}
std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name) std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name) { return {}; }
{
return {};
}
std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) { return {}; }
{
return {};
}
bool useMIDILock() const { return false; } bool useMIDILock() const { return false; }
#endif #endif
}; };
std::unique_ptr<IAudioVoiceEngine> NewAudioVoiceEngine() std::unique_ptr<IAudioVoiceEngine> NewAudioVoiceEngine() { return std::make_unique<WASAPIAudioVoiceEngine>(); }
{
return std::make_unique<WASAPIAudioVoiceEngine>();
}
} } // namespace boo

View File

@ -2,101 +2,59 @@
#include "logvisor/logvisor.hpp" #include "logvisor/logvisor.hpp"
#include "boo/audiodev/IAudioVoiceEngine.hpp" #include "boo/audiodev/IAudioVoiceEngine.hpp"
namespace boo namespace boo {
{
static logvisor::Module Log("boo::WAVOut"); static logvisor::Module Log("boo::WAVOut");
struct WAVOutVoiceEngine : BaseAudioVoiceEngine struct WAVOutVoiceEngine : BaseAudioVoiceEngine {
{
std::vector<float> m_interleavedBuf; std::vector<float> m_interleavedBuf;
AudioChannelSet _getAvailableSet() AudioChannelSet _getAvailableSet() { return AudioChannelSet::Stereo; }
{
return AudioChannelSet::Stereo;
}
std::string getCurrentAudioOutput() const std::string getCurrentAudioOutput() const { return "wavout"; }
{
return "wavout";
}
bool setCurrentAudioOutput(const char* name) bool setCurrentAudioOutput(const char* name) { return false; }
{
return false;
}
std::vector<std::pair<std::string, std::string>> enumerateAudioOutputs() const std::vector<std::pair<std::string, std::string>> enumerateAudioOutputs() const { return {{"wavout", "WAVOut"}}; }
{
return {{"wavout", "WAVOut"}};
}
std::vector<std::pair<std::string, std::string>> enumerateMIDIInputs() const std::vector<std::pair<std::string, std::string>> enumerateMIDIInputs() const { return {}; }
{
return {};
}
bool supportsVirtualMIDIIn() const bool supportsVirtualMIDIIn() const { return false; }
{
return false;
}
ReceiveFunctor* m_midiReceiver = nullptr; ReceiveFunctor* m_midiReceiver = nullptr;
struct MIDIIn : public IMIDIIn struct MIDIIn : public IMIDIIn {
{
MIDIIn(WAVOutVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver) MIDIIn(WAVOutVoiceEngine* parent, bool virt, ReceiveFunctor&& receiver)
: IMIDIIn(parent, virt, std::move(receiver)) {} : IMIDIIn(parent, virt, std::move(receiver)) {}
std::string description() const std::string description() const { return "WAVOut MIDI"; }
{
return "WAVOut MIDI";
}
}; };
std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver) std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver) {
{
std::unique_ptr<IMIDIIn> ret = std::make_unique<MIDIIn>(nullptr, true, std::move(receiver)); std::unique_ptr<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;
} }
std::unique_ptr<IMIDIOut> newVirtualMIDIOut() std::unique_ptr<IMIDIOut> newVirtualMIDIOut() { return {}; }
{
return {};
}
std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver) std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver) { return {}; }
{
return {};
}
std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) { return {}; }
{
return {};
}
std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name) std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name) { return {}; }
{
return {};
}
std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) { return {}; }
{
return {};
}
bool useMIDILock() const { return false; } bool useMIDILock() const { return false; }
FILE* m_fp = nullptr; FILE* m_fp = nullptr;
size_t m_bytesWritten = 0; size_t m_bytesWritten = 0;
void prepareWAV(double sampleRate, int numChans) void prepareWAV(double sampleRate, int numChans) {
{
uint32_t speakerMask = 0; uint32_t speakerMask = 0;
switch (numChans) switch (numChans) {
{
default: default:
case 2: case 2:
numChans = 2; numChans = 2;
@ -140,12 +98,12 @@ struct WAVOutVoiceEngine : BaseAudioVoiceEngine
m_mixInfo.m_channelMap.m_channels[5] = AudioChannel::RearRight; m_mixInfo.m_channelMap.m_channels[5] = AudioChannel::RearRight;
m_mixInfo.m_channelMap.m_channels[6] = AudioChannel::SideLeft; m_mixInfo.m_channelMap.m_channels[6] = AudioChannel::SideLeft;
m_mixInfo.m_channelMap.m_channels[7] = AudioChannel::SideRight; m_mixInfo.m_channelMap.m_channels[7] = AudioChannel::SideRight;
speakerMask = 0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000010 | 0x00000020 | 0x00000200 | 0x00000400; speakerMask =
0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000010 | 0x00000020 | 0x00000200 | 0x00000400;
break; break;
} }
if (numChans == 2) if (numChans == 2) {
{
fwrite("RIFF", 1, 4, m_fp); fwrite("RIFF", 1, 4, m_fp);
uint32_t dataSize = 0; uint32_t dataSize = 0;
uint32_t chunkSize = 36 + dataSize; uint32_t chunkSize = 36 + dataSize;
@ -171,9 +129,7 @@ struct WAVOutVoiceEngine : BaseAudioVoiceEngine
fwrite("data", 1, 4, m_fp); fwrite("data", 1, 4, m_fp);
fwrite(&dataSize, 1, 4, m_fp); fwrite(&dataSize, 1, 4, m_fp);
} } else {
else
{
fwrite("RIFF", 1, 4, m_fp); fwrite("RIFF", 1, 4, m_fp);
uint32_t dataSize = 0; uint32_t dataSize = 0;
uint32_t chunkSize = 60 + dataSize; uint32_t chunkSize = 60 + dataSize;
@ -213,8 +169,7 @@ struct WAVOutVoiceEngine : BaseAudioVoiceEngine
_buildAudioRenderClient(); _buildAudioRenderClient();
} }
WAVOutVoiceEngine(const char* path, double sampleRate, int numChans) WAVOutVoiceEngine(const char* path, double sampleRate, int numChans) {
{
m_fp = fopen(path, "wb"); m_fp = fopen(path, "wb");
if (!m_fp) if (!m_fp)
return; return;
@ -222,8 +177,7 @@ struct WAVOutVoiceEngine : BaseAudioVoiceEngine
} }
#if _WIN32 #if _WIN32
WAVOutVoiceEngine(const wchar_t* path, double sampleRate, int numChans) WAVOutVoiceEngine(const wchar_t* path, double sampleRate, int numChans) {
{
m_fp = _wfopen(path, L"wb"); m_fp = _wfopen(path, L"wb");
if (!m_fp) if (!m_fp)
return; return;
@ -231,21 +185,17 @@ struct WAVOutVoiceEngine : BaseAudioVoiceEngine
} }
#endif #endif
void finishWav() void finishWav() {
{
uint32_t dataSize = m_bytesWritten; uint32_t dataSize = m_bytesWritten;
if (m_mixInfo.m_channelMap.m_channelCount == 2) if (m_mixInfo.m_channelMap.m_channelCount == 2) {
{
fseek(m_fp, 4, SEEK_SET); fseek(m_fp, 4, SEEK_SET);
uint32_t chunkSize = 36 + dataSize; uint32_t chunkSize = 36 + dataSize;
fwrite(&chunkSize, 1, 4, m_fp); fwrite(&chunkSize, 1, 4, m_fp);
fseek(m_fp, 40, SEEK_SET); fseek(m_fp, 40, SEEK_SET);
fwrite(&dataSize, 1, 4, m_fp); fwrite(&dataSize, 1, 4, m_fp);
} } else {
else
{
fseek(m_fp, 4, SEEK_SET); fseek(m_fp, 4, SEEK_SET);
uint32_t chunkSize = 60 + dataSize; uint32_t chunkSize = 60 + dataSize;
fwrite(&chunkSize, 1, 4, m_fp); fwrite(&chunkSize, 1, 4, m_fp);
@ -257,27 +207,21 @@ struct WAVOutVoiceEngine : BaseAudioVoiceEngine
fclose(m_fp); fclose(m_fp);
} }
~WAVOutVoiceEngine() ~WAVOutVoiceEngine() { finishWav(); }
{
finishWav();
}
void _buildAudioRenderClient() void _buildAudioRenderClient() {
{
m_5msFrames = m_mixInfo.m_sampleRate * 5 / 1000; m_5msFrames = m_mixInfo.m_sampleRate * 5 / 1000;
m_interleavedBuf.resize(m_mixInfo.m_channelMap.m_channelCount * m_5msFrames); m_interleavedBuf.resize(m_mixInfo.m_channelMap.m_channelCount * m_5msFrames);
} }
void _rebuildAudioRenderClient(double sampleRate, size_t periodFrames) void _rebuildAudioRenderClient(double sampleRate, size_t periodFrames) {
{
m_mixInfo.m_periodFrames = periodFrames; m_mixInfo.m_periodFrames = periodFrames;
m_mixInfo.m_sampleRate = sampleRate; m_mixInfo.m_sampleRate = sampleRate;
_buildAudioRenderClient(); _buildAudioRenderClient();
_resetSampleRate(); _resetSampleRate();
} }
void pumpAndMixVoices() void pumpAndMixVoices() {
{
size_t frameSz = 4 * m_mixInfo.m_channelMap.m_channelCount; size_t frameSz = 4 * m_mixInfo.m_channelMap.m_channelCount;
_pumpAndMixVoices(m_5msFrames, m_interleavedBuf.data()); _pumpAndMixVoices(m_5msFrames, m_interleavedBuf.data());
fwrite(m_interleavedBuf.data(), 1, m_5msFrames * frameSz, m_fp); fwrite(m_interleavedBuf.data(), 1, m_5msFrames * frameSz, m_fp);
@ -285,8 +229,7 @@ struct WAVOutVoiceEngine : BaseAudioVoiceEngine
} }
}; };
std::unique_ptr<IAudioVoiceEngine> NewWAVAudioVoiceEngine(const char* path, double sampleRate, int numChans) std::unique_ptr<IAudioVoiceEngine> NewWAVAudioVoiceEngine(const char* path, double sampleRate, int numChans) {
{
std::unique_ptr<IAudioVoiceEngine> ret = std::make_unique<WAVOutVoiceEngine>(path, sampleRate, numChans); std::unique_ptr<IAudioVoiceEngine> ret = std::make_unique<WAVOutVoiceEngine>(path, sampleRate, numChans);
if (!static_cast<WAVOutVoiceEngine&>(*ret).m_fp) if (!static_cast<WAVOutVoiceEngine&>(*ret).m_fp)
return {}; return {};
@ -294,8 +237,7 @@ std::unique_ptr<IAudioVoiceEngine> NewWAVAudioVoiceEngine(const char* path, doub
} }
#if _WIN32 #if _WIN32
std::unique_ptr<IAudioVoiceEngine> NewWAVAudioVoiceEngine(const wchar_t* path, double sampleRate, int numChans) std::unique_ptr<IAudioVoiceEngine> NewWAVAudioVoiceEngine(const wchar_t* path, double sampleRate, int numChans) {
{
std::unique_ptr<IAudioVoiceEngine> ret = std::make_unique<WAVOutVoiceEngine>(path, sampleRate, numChans); std::unique_ptr<IAudioVoiceEngine> ret = std::make_unique<WAVOutVoiceEngine>(path, sampleRate, numChans);
if (!static_cast<WAVOutVoiceEngine&>(*ret).m_fp) if (!static_cast<WAVOutVoiceEngine&>(*ret).m_fp)
return {}; return {};
@ -303,4 +245,4 @@ std::unique_ptr<IAudioVoiceEngine> NewWAVAudioVoiceEngine(const wchar_t* path, d
} }
#endif #endif
} } // namespace boo

View File

@ -1,18 +1,15 @@
#include "Common.hpp" #include "Common.hpp"
#include <cmath> #include <cmath>
namespace boo namespace boo {
{
void UpdateGammaLUT(ITextureD* tex, float gamma) void UpdateGammaLUT(ITextureD* tex, float gamma) {
{
void* data = tex->map(65536 * 2); void* data = tex->map(65536 * 2);
for (int i=0 ; i<65536 ; ++i) for (int i = 0; i < 65536; ++i) {
{
float level = std::pow(i / 65535.f, gamma); float level = std::pow(i / 65535.f, gamma);
reinterpret_cast<uint16_t*>(data)[i] = level * 65535.f; reinterpret_cast<uint16_t*>(data)[i] = level * 65535.f;
} }
tex->unmap(); tex->unmap();
} }
} } // namespace boo

View File

@ -10,8 +10,7 @@
#include "boo/graphicsdev/IGraphicsDataFactory.hpp" #include "boo/graphicsdev/IGraphicsDataFactory.hpp"
#include "../Common.hpp" #include "../Common.hpp"
namespace boo namespace boo {
{
struct BaseGraphicsData; struct BaseGraphicsData;
struct BaseGraphicsPool; struct BaseGraphicsPool;
@ -20,14 +19,12 @@ template<class NodeCls, class DataCls = BaseGraphicsData>
struct GraphicsDataNode; struct GraphicsDataNode;
/** Inherited by data factory implementations to track the head data and pool nodes */ /** Inherited by data factory implementations to track the head data and pool nodes */
struct GraphicsDataFactoryHead struct GraphicsDataFactoryHead {
{
std::recursive_mutex m_dataMutex; std::recursive_mutex m_dataMutex;
BaseGraphicsData* m_dataHead = nullptr; BaseGraphicsData* m_dataHead = nullptr;
BaseGraphicsPool* m_poolHead = nullptr; BaseGraphicsPool* m_poolHead = nullptr;
~GraphicsDataFactoryHead() ~GraphicsDataFactoryHead() {
{
assert(m_dataHead == nullptr && "Dangling graphics data pools detected"); assert(m_dataHead == nullptr && "Dangling graphics data pools detected");
assert(m_poolHead == nullptr && "Dangling graphics data pools detected"); assert(m_poolHead == nullptr && "Dangling graphics data pools detected");
} }
@ -36,11 +33,11 @@ struct GraphicsDataFactoryHead
/** Private generalized data container class. /** Private generalized data container class.
* Keeps head pointers to all graphics objects by type * Keeps head pointers to all graphics objects by type
*/ */
struct BaseGraphicsData : ListNode<BaseGraphicsData, GraphicsDataFactoryHead*> struct BaseGraphicsData : ListNode<BaseGraphicsData, GraphicsDataFactoryHead*> {
{
static BaseGraphicsData*& _getHeadPtr(GraphicsDataFactoryHead* head) { return head->m_dataHead; } static BaseGraphicsData*& _getHeadPtr(GraphicsDataFactoryHead* head) { return head->m_dataHead; }
static std::unique_lock<std::recursive_mutex> _getHeadLock(GraphicsDataFactoryHead* head) static std::unique_lock<std::recursive_mutex> _getHeadLock(GraphicsDataFactoryHead* head) {
{ return std::unique_lock<std::recursive_mutex>{head->m_dataMutex}; } return std::unique_lock<std::recursive_mutex>{head->m_dataMutex};
}
__BooTraceFields __BooTraceFields
@ -53,85 +50,114 @@ struct BaseGraphicsData : ListNode<BaseGraphicsData, GraphicsDataFactoryHead*>
GraphicsDataNode<ITextureSA, BaseGraphicsData>* m_SATexs = nullptr; GraphicsDataNode<ITextureSA, BaseGraphicsData>* m_SATexs = nullptr;
GraphicsDataNode<ITextureD, BaseGraphicsData>* m_DTexs = nullptr; GraphicsDataNode<ITextureD, BaseGraphicsData>* m_DTexs = nullptr;
GraphicsDataNode<ITextureR, BaseGraphicsData>* m_RTexs = nullptr; GraphicsDataNode<ITextureR, BaseGraphicsData>* m_RTexs = nullptr;
template<class T> GraphicsDataNode<T, BaseGraphicsData>*& getHead(); template <class T>
template<class T> size_t countForward() GraphicsDataNode<T, BaseGraphicsData>*& getHead();
{ auto* head = getHead<T>(); return head ? head->countForward() : 0; } template <class T>
std::unique_lock<std::recursive_mutex> destructorLock() override size_t countForward() {
{ return std::unique_lock<std::recursive_mutex>{m_head->m_dataMutex}; } auto* head = getHead<T>();
return head ? head->countForward() : 0;
}
std::unique_lock<std::recursive_mutex> destructorLock() override {
return std::unique_lock<std::recursive_mutex>{m_head->m_dataMutex};
}
explicit BaseGraphicsData(GraphicsDataFactoryHead& head __BooTraceArgs) explicit BaseGraphicsData(GraphicsDataFactoryHead& head __BooTraceArgs)
: ListNode<BaseGraphicsData, GraphicsDataFactoryHead*>(&head) __BooTraceInitializer : ListNode<BaseGraphicsData, GraphicsDataFactoryHead*>(&head) __BooTraceInitializer {}
{}
}; };
template <> inline GraphicsDataNode<IShaderStage, BaseGraphicsData>*& template <>
BaseGraphicsData::getHead<IShaderStage>() { return m_Ss; } inline GraphicsDataNode<IShaderStage, BaseGraphicsData>*& BaseGraphicsData::getHead<IShaderStage>() {
template <> inline GraphicsDataNode<IShaderPipeline, BaseGraphicsData>*& return m_Ss;
BaseGraphicsData::getHead<IShaderPipeline>() { return m_SPs; } }
template <> inline GraphicsDataNode<IShaderDataBinding, BaseGraphicsData>*& template <>
BaseGraphicsData::getHead<IShaderDataBinding>() { return m_SBinds; } inline GraphicsDataNode<IShaderPipeline, BaseGraphicsData>*& BaseGraphicsData::getHead<IShaderPipeline>() {
template <> inline GraphicsDataNode<IGraphicsBufferS, BaseGraphicsData>*& return m_SPs;
BaseGraphicsData::getHead<IGraphicsBufferS>() { return m_SBufs; } }
template <> inline GraphicsDataNode<IGraphicsBufferD, BaseGraphicsData>*& template <>
BaseGraphicsData::getHead<IGraphicsBufferD>() { return m_DBufs; } inline GraphicsDataNode<IShaderDataBinding, BaseGraphicsData>*& BaseGraphicsData::getHead<IShaderDataBinding>() {
template <> inline GraphicsDataNode<ITextureS, BaseGraphicsData>*& return m_SBinds;
BaseGraphicsData::getHead<ITextureS>() { return m_STexs; } }
template <> inline GraphicsDataNode<ITextureSA, BaseGraphicsData>*& template <>
BaseGraphicsData::getHead<ITextureSA>() { return m_SATexs; } inline GraphicsDataNode<IGraphicsBufferS, BaseGraphicsData>*& BaseGraphicsData::getHead<IGraphicsBufferS>() {
template <> inline GraphicsDataNode<ITextureD, BaseGraphicsData>*& return m_SBufs;
BaseGraphicsData::getHead<ITextureD>() { return m_DTexs; } }
template <> inline GraphicsDataNode<ITextureR, BaseGraphicsData>*& template <>
BaseGraphicsData::getHead<ITextureR>() { return m_RTexs; } inline GraphicsDataNode<IGraphicsBufferD, BaseGraphicsData>*& BaseGraphicsData::getHead<IGraphicsBufferD>() {
return m_DBufs;
}
template <>
inline GraphicsDataNode<ITextureS, BaseGraphicsData>*& BaseGraphicsData::getHead<ITextureS>() {
return m_STexs;
}
template <>
inline GraphicsDataNode<ITextureSA, BaseGraphicsData>*& BaseGraphicsData::getHead<ITextureSA>() {
return m_SATexs;
}
template <>
inline GraphicsDataNode<ITextureD, BaseGraphicsData>*& BaseGraphicsData::getHead<ITextureD>() {
return m_DTexs;
}
template <>
inline GraphicsDataNode<ITextureR, BaseGraphicsData>*& BaseGraphicsData::getHead<ITextureR>() {
return m_RTexs;
}
/** Private generalized pool container class. /** Private generalized pool container class.
* Keeps head pointer to exactly one dynamic buffer while otherwise conforming to BaseGraphicsData * Keeps head pointer to exactly one dynamic buffer while otherwise conforming to BaseGraphicsData
*/ */
struct BaseGraphicsPool : ListNode<BaseGraphicsPool, GraphicsDataFactoryHead*> struct BaseGraphicsPool : ListNode<BaseGraphicsPool, GraphicsDataFactoryHead*> {
{
static BaseGraphicsPool*& _getHeadPtr(GraphicsDataFactoryHead* head) { return head->m_poolHead; } static BaseGraphicsPool*& _getHeadPtr(GraphicsDataFactoryHead* head) { return head->m_poolHead; }
static std::unique_lock<std::recursive_mutex> _getHeadLock(GraphicsDataFactoryHead* head) static std::unique_lock<std::recursive_mutex> _getHeadLock(GraphicsDataFactoryHead* head) {
{ return std::unique_lock<std::recursive_mutex>{head->m_dataMutex}; } return std::unique_lock<std::recursive_mutex>{head->m_dataMutex};
}
__BooTraceFields __BooTraceFields
GraphicsDataNode<IGraphicsBufferD, BaseGraphicsPool>* m_DBufs = nullptr; GraphicsDataNode<IGraphicsBufferD, BaseGraphicsPool>* m_DBufs = nullptr;
template<class T> GraphicsDataNode<T, BaseGraphicsPool>*& getHead(); template <class T>
template<class T> size_t countForward() GraphicsDataNode<T, BaseGraphicsPool>*& getHead();
{ auto* head = getHead<T>(); return head ? head->countForward() : 0; } template <class T>
std::unique_lock<std::recursive_mutex> destructorLock() override size_t countForward() {
{ return std::unique_lock<std::recursive_mutex>{m_head->m_dataMutex}; } auto* head = getHead<T>();
return head ? head->countForward() : 0;
}
std::unique_lock<std::recursive_mutex> destructorLock() override {
return std::unique_lock<std::recursive_mutex>{m_head->m_dataMutex};
}
explicit BaseGraphicsPool(GraphicsDataFactoryHead& head __BooTraceArgs) explicit BaseGraphicsPool(GraphicsDataFactoryHead& head __BooTraceArgs)
: ListNode<BaseGraphicsPool, GraphicsDataFactoryHead*>(&head) __BooTraceInitializer : ListNode<BaseGraphicsPool, GraphicsDataFactoryHead*>(&head) __BooTraceInitializer {}
{}
}; };
template <> inline GraphicsDataNode<IGraphicsBufferD, BaseGraphicsPool>*& template <>
BaseGraphicsPool::getHead<IGraphicsBufferD>() { return m_DBufs; } inline GraphicsDataNode<IGraphicsBufferD, BaseGraphicsPool>*& BaseGraphicsPool::getHead<IGraphicsBufferD>() {
return m_DBufs;
}
/** Private generalised graphics object node. /** Private generalised graphics object node.
* Keeps a strong reference to the data pool that it's a member of; * Keeps a strong reference to the data pool that it's a member of;
* as well as doubly-linked pointers to same-type sibling objects * as well as doubly-linked pointers to same-type sibling objects
*/ */
template <class NodeCls, class DataCls> template <class NodeCls, class DataCls>
struct GraphicsDataNode : ListNode<GraphicsDataNode<NodeCls, DataCls>, ObjToken<DataCls>, NodeCls> struct GraphicsDataNode : ListNode<GraphicsDataNode<NodeCls, DataCls>, ObjToken<DataCls>, NodeCls> {
{
using base = ListNode<GraphicsDataNode<NodeCls, DataCls>, ObjToken<DataCls>, NodeCls>; using base = ListNode<GraphicsDataNode<NodeCls, DataCls>, ObjToken<DataCls>, NodeCls>;
static GraphicsDataNode<NodeCls, DataCls>*& _getHeadPtr(ObjToken<DataCls>& head) static GraphicsDataNode<NodeCls, DataCls>*& _getHeadPtr(ObjToken<DataCls>& head) {
{ return head->template getHead<NodeCls>(); } return head->template getHead<NodeCls>();
static std::unique_lock<std::recursive_mutex> _getHeadLock(ObjToken<DataCls>& head) }
{ return std::unique_lock<std::recursive_mutex>{head->m_head->m_dataMutex}; } static std::unique_lock<std::recursive_mutex> _getHeadLock(ObjToken<DataCls>& head) {
return std::unique_lock<std::recursive_mutex>{head->m_head->m_dataMutex};
}
std::unique_lock<std::recursive_mutex> destructorLock() override std::unique_lock<std::recursive_mutex> destructorLock() override {
{ return std::unique_lock<std::recursive_mutex>{base::m_head->m_head->m_dataMutex}; } return std::unique_lock<std::recursive_mutex>{base::m_head->m_head->m_dataMutex};
}
explicit GraphicsDataNode(const ObjToken<DataCls>& data) explicit GraphicsDataNode(const ObjToken<DataCls>& data)
: ListNode<GraphicsDataNode<NodeCls, DataCls>, ObjToken<DataCls>, NodeCls>(data) : ListNode<GraphicsDataNode<NodeCls, DataCls>, ObjToken<DataCls>, NodeCls>(data) {}
{}
class iterator class iterator {
{
GraphicsDataNode<NodeCls, DataCls>* m_node; GraphicsDataNode<NodeCls, DataCls>* m_node;
public: public:
using iterator_category = std::bidirectional_iterator_tag; using iterator_category = std::bidirectional_iterator_tag;
using value_type = NodeCls; using value_type = NodeCls;
@ -142,15 +168,20 @@ struct GraphicsDataNode : ListNode<GraphicsDataNode<NodeCls, DataCls>, ObjToken<
explicit iterator(GraphicsDataNode<NodeCls, DataCls>* node) : m_node(node) {} explicit iterator(GraphicsDataNode<NodeCls, DataCls>* node) : m_node(node) {}
NodeCls& operator*() const { return *m_node; } NodeCls& operator*() const { return *m_node; }
bool operator!=(const iterator& other) const { return m_node != other.m_node; } bool operator!=(const iterator& other) const { return m_node != other.m_node; }
iterator& operator++() { m_node = m_node->m_next; return *this; } iterator& operator++() {
iterator& operator--() { m_node = m_node->m_prev; return *this; } m_node = m_node->m_next;
return *this;
}
iterator& operator--() {
m_node = m_node->m_prev;
return *this;
}
}; };
iterator begin() { return iterator(this); } iterator begin() { return iterator(this); }
iterator end() { return iterator(nullptr); } iterator end() { return iterator(nullptr); }
size_t countForward() size_t countForward() {
{
size_t ret = 0; size_t ret = 0;
for (auto& n : *this) for (auto& n : *this)
++ret; ++ret;
@ -160,5 +191,4 @@ struct GraphicsDataNode : ListNode<GraphicsDataNode<NodeCls, DataCls>, ObjToken<
void UpdateGammaLUT(ITextureD* tex, float gamma); void UpdateGammaLUT(ITextureD* tex, float gamma);
} } // namespace boo

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,17 @@
#include "boo/graphicsdev/glxew.h" #include "boo/graphicsdev/glxew.h"
#include "logvisor/logvisor.hpp" #include "logvisor/logvisor.hpp"
namespace boo namespace boo {
{
static logvisor::Module Log("boo::GLX"); static logvisor::Module Log("boo::GLX");
void GLXExtensionCheck() void GLXExtensionCheck() {
{
if (!GLXEW_SGI_video_sync) if (!GLXEW_SGI_video_sync)
Log.report(logvisor::Fatal, "GLX_SGI_video_sync not available"); Log.report(logvisor::Fatal, "GLX_SGI_video_sync not available");
if (!GLXEW_EXT_swap_control && !GLXEW_MESA_swap_control && !GLXEW_SGI_swap_control) if (!GLXEW_EXT_swap_control && !GLXEW_MESA_swap_control && !GLXEW_SGI_swap_control)
Log.report(logvisor::Fatal, "swap_control not available"); Log.report(logvisor::Fatal, "swap_control not available");
} }
void GLXEnableVSync(Display* disp, GLXWindow drawable) void GLXEnableVSync(Display* disp, GLXWindow drawable) {
{
if (GLXEW_EXT_swap_control) if (GLXEW_EXT_swap_control)
glXSwapIntervalEXT(disp, drawable, 1); glXSwapIntervalEXT(disp, drawable, 1);
else if (GLXEW_MESA_swap_control) else if (GLXEW_MESA_swap_control)
@ -23,4 +20,4 @@ void GLXEnableVSync(Display* disp, GLXWindow drawable)
glXSwapIntervalSGI(1); glXSwapIntervalSGI(1);
} }
} } // namespace boo

File diff suppressed because it is too large Load Diff

View File

@ -184,78 +184,114 @@ PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT; PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
PFN_vkDebugReportMessageEXT DebugReportMessageEXT; PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
void init_dispatch_table_top(PFN_vkGetInstanceProcAddr get_instance_proc_addr) void init_dispatch_table_top(PFN_vkGetInstanceProcAddr get_instance_proc_addr) {
{
GetInstanceProcAddr = get_instance_proc_addr; GetInstanceProcAddr = get_instance_proc_addr;
CreateInstance = reinterpret_cast<PFN_vkCreateInstance>(GetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance")); CreateInstance = reinterpret_cast<PFN_vkCreateInstance>(GetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance"));
EnumerateInstanceExtensionProperties = reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(GetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties")); EnumerateInstanceExtensionProperties = reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
EnumerateInstanceLayerProperties = reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(GetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceLayerProperties")); GetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"));
EnumerateInstanceLayerProperties = reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
GetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceLayerProperties"));
} }
void init_dispatch_table_middle(VkInstance instance, bool include_bottom) void init_dispatch_table_middle(VkInstance instance, bool include_bottom) {
{ GetInstanceProcAddr =
GetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr(instance, "vkGetInstanceProcAddr")); reinterpret_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr(instance, "vkGetInstanceProcAddr"));
DestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(GetInstanceProcAddr(instance, "vkDestroyInstance")); DestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(GetInstanceProcAddr(instance, "vkDestroyInstance"));
EnumeratePhysicalDevices = reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(GetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices")); EnumeratePhysicalDevices =
GetPhysicalDeviceFeatures = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures")); reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(GetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices"));
GetPhysicalDeviceFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties")); GetPhysicalDeviceFeatures =
GetPhysicalDeviceImageFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties")); reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures"));
GetPhysicalDeviceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties")); GetPhysicalDeviceFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties>(
GetPhysicalDeviceQueueFamilyProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties")); GetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties"));
GetPhysicalDeviceMemoryProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties")); GetPhysicalDeviceImageFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceImageFormatProperties"));
GetPhysicalDeviceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties"));
GetPhysicalDeviceQueueFamilyProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties"));
GetPhysicalDeviceMemoryProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties"));
CreateDevice = reinterpret_cast<PFN_vkCreateDevice>(GetInstanceProcAddr(instance, "vkCreateDevice")); CreateDevice = reinterpret_cast<PFN_vkCreateDevice>(GetInstanceProcAddr(instance, "vkCreateDevice"));
EnumerateDeviceExtensionProperties = reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(GetInstanceProcAddr(instance, "vkEnumerateDeviceExtensionProperties")); EnumerateDeviceExtensionProperties = reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
GetPhysicalDeviceSparseImageFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties")); GetInstanceProcAddr(instance, "vkEnumerateDeviceExtensionProperties"));
GetPhysicalDeviceSparseImageFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties"));
DestroySurfaceKHR = reinterpret_cast<PFN_vkDestroySurfaceKHR>(GetInstanceProcAddr(instance, "vkDestroySurfaceKHR")); DestroySurfaceKHR = reinterpret_cast<PFN_vkDestroySurfaceKHR>(GetInstanceProcAddr(instance, "vkDestroySurfaceKHR"));
GetPhysicalDeviceSurfaceSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceSupportKHR")); GetPhysicalDeviceSurfaceSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>(
GetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR")); GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceSupportKHR"));
GetPhysicalDeviceSurfaceFormatsKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR")); GetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
GetPhysicalDeviceSurfacePresentModesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR")); GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
GetPhysicalDeviceDisplayPropertiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPropertiesKHR>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR")); GetPhysicalDeviceSurfaceFormatsKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
GetPhysicalDeviceDisplayPlanePropertiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR")); GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"));
GetDisplayPlaneSupportedDisplaysKHR = reinterpret_cast<PFN_vkGetDisplayPlaneSupportedDisplaysKHR>(GetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR")); GetPhysicalDeviceSurfacePresentModesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
GetDisplayModePropertiesKHR = reinterpret_cast<PFN_vkGetDisplayModePropertiesKHR>(GetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR")); GetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR"));
CreateDisplayModeKHR = reinterpret_cast<PFN_vkCreateDisplayModeKHR>(GetInstanceProcAddr(instance, "vkCreateDisplayModeKHR")); GetPhysicalDeviceDisplayPropertiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPropertiesKHR>(
GetDisplayPlaneCapabilitiesKHR = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilitiesKHR>(GetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR")); GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPropertiesKHR"));
CreateDisplayPlaneSurfaceKHR = reinterpret_cast<PFN_vkCreateDisplayPlaneSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateDisplayPlaneSurfaceKHR")); GetPhysicalDeviceDisplayPlanePropertiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"));
GetDisplayPlaneSupportedDisplaysKHR = reinterpret_cast<PFN_vkGetDisplayPlaneSupportedDisplaysKHR>(
GetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR"));
GetDisplayModePropertiesKHR = reinterpret_cast<PFN_vkGetDisplayModePropertiesKHR>(
GetInstanceProcAddr(instance, "vkGetDisplayModePropertiesKHR"));
CreateDisplayModeKHR =
reinterpret_cast<PFN_vkCreateDisplayModeKHR>(GetInstanceProcAddr(instance, "vkCreateDisplayModeKHR"));
GetDisplayPlaneCapabilitiesKHR = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilitiesKHR>(
GetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR"));
CreateDisplayPlaneSurfaceKHR = reinterpret_cast<PFN_vkCreateDisplayPlaneSurfaceKHR>(
GetInstanceProcAddr(instance, "vkCreateDisplayPlaneSurfaceKHR"));
#ifdef VK_USE_PLATFORM_XLIB_KHR #ifdef VK_USE_PLATFORM_XLIB_KHR
CreateXlibSurfaceKHR = reinterpret_cast<PFN_vkCreateXlibSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR")); CreateXlibSurfaceKHR =
reinterpret_cast<PFN_vkCreateXlibSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR"));
#endif #endif
#ifdef VK_USE_PLATFORM_XLIB_KHR #ifdef VK_USE_PLATFORM_XLIB_KHR
GetPhysicalDeviceXlibPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR")); GetPhysicalDeviceXlibPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"));
#endif #endif
#ifdef VK_USE_PLATFORM_XCB_KHR #ifdef VK_USE_PLATFORM_XCB_KHR
CreateXcbSurfaceKHR = reinterpret_cast<PFN_vkCreateXcbSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR")); CreateXcbSurfaceKHR =
reinterpret_cast<PFN_vkCreateXcbSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR"));
#endif #endif
#ifdef VK_USE_PLATFORM_XCB_KHR #ifdef VK_USE_PLATFORM_XCB_KHR
GetPhysicalDeviceXcbPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR")); GetPhysicalDeviceXcbPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR"));
#endif #endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR #ifdef VK_USE_PLATFORM_WAYLAND_KHR
CreateWaylandSurfaceKHR = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR")); CreateWaylandSurfaceKHR =
reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR"));
#endif #endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR #ifdef VK_USE_PLATFORM_WAYLAND_KHR
GetPhysicalDeviceWaylandPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR")); GetPhysicalDeviceWaylandPresentationSupportKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"));
#endif #endif
#ifdef VK_USE_PLATFORM_MIR_KHR #ifdef VK_USE_PLATFORM_MIR_KHR
CreateMirSurfaceKHR = reinterpret_cast<PFN_vkCreateMirSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateMirSurfaceKHR")); CreateMirSurfaceKHR =
reinterpret_cast<PFN_vkCreateMirSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateMirSurfaceKHR"));
#endif #endif
#ifdef VK_USE_PLATFORM_MIR_KHR #ifdef VK_USE_PLATFORM_MIR_KHR
GetPhysicalDeviceMirPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceMirPresentationSupportKHR>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR")); GetPhysicalDeviceMirPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceMirPresentationSupportKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR"));
#endif #endif
#ifdef VK_USE_PLATFORM_ANDROID_KHR #ifdef VK_USE_PLATFORM_ANDROID_KHR
CreateAndroidSurfaceKHR = reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateAndroidSurfaceKHR")); CreateAndroidSurfaceKHR =
reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateAndroidSurfaceKHR"));
#endif #endif
#ifdef VK_USE_PLATFORM_WIN32_KHR #ifdef VK_USE_PLATFORM_WIN32_KHR
CreateWin32SurfaceKHR = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR")); CreateWin32SurfaceKHR =
reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>(GetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"));
#endif #endif
#ifdef VK_USE_PLATFORM_WIN32_KHR #ifdef VK_USE_PLATFORM_WIN32_KHR
GetPhysicalDeviceWin32PresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR>(GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR")); GetPhysicalDeviceWin32PresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR>(
GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR"));
#endif #endif
CreateDebugReportCallbackEXT = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(GetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT")); CreateDebugReportCallbackEXT = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
DestroyDebugReportCallbackEXT = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT")); GetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
DebugReportMessageEXT = reinterpret_cast<PFN_vkDebugReportMessageEXT>(GetInstanceProcAddr(instance, "vkDebugReportMessageEXT")); DestroyDebugReportCallbackEXT = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"));
DebugReportMessageEXT =
reinterpret_cast<PFN_vkDebugReportMessageEXT>(GetInstanceProcAddr(instance, "vkDebugReportMessageEXT"));
if (!include_bottom) if (!include_bottom)
return; return;
@ -270,14 +306,20 @@ void init_dispatch_table_middle(VkInstance instance, bool include_bottom)
FreeMemory = reinterpret_cast<PFN_vkFreeMemory>(GetInstanceProcAddr(instance, "vkFreeMemory")); FreeMemory = reinterpret_cast<PFN_vkFreeMemory>(GetInstanceProcAddr(instance, "vkFreeMemory"));
MapMemory = reinterpret_cast<PFN_vkMapMemory>(GetInstanceProcAddr(instance, "vkMapMemory")); MapMemory = reinterpret_cast<PFN_vkMapMemory>(GetInstanceProcAddr(instance, "vkMapMemory"));
UnmapMemory = reinterpret_cast<PFN_vkUnmapMemory>(GetInstanceProcAddr(instance, "vkUnmapMemory")); UnmapMemory = reinterpret_cast<PFN_vkUnmapMemory>(GetInstanceProcAddr(instance, "vkUnmapMemory"));
FlushMappedMemoryRanges = reinterpret_cast<PFN_vkFlushMappedMemoryRanges>(GetInstanceProcAddr(instance, "vkFlushMappedMemoryRanges")); FlushMappedMemoryRanges =
InvalidateMappedMemoryRanges = reinterpret_cast<PFN_vkInvalidateMappedMemoryRanges>(GetInstanceProcAddr(instance, "vkInvalidateMappedMemoryRanges")); reinterpret_cast<PFN_vkFlushMappedMemoryRanges>(GetInstanceProcAddr(instance, "vkFlushMappedMemoryRanges"));
GetDeviceMemoryCommitment = reinterpret_cast<PFN_vkGetDeviceMemoryCommitment>(GetInstanceProcAddr(instance, "vkGetDeviceMemoryCommitment")); InvalidateMappedMemoryRanges = reinterpret_cast<PFN_vkInvalidateMappedMemoryRanges>(
GetInstanceProcAddr(instance, "vkInvalidateMappedMemoryRanges"));
GetDeviceMemoryCommitment =
reinterpret_cast<PFN_vkGetDeviceMemoryCommitment>(GetInstanceProcAddr(instance, "vkGetDeviceMemoryCommitment"));
BindBufferMemory = reinterpret_cast<PFN_vkBindBufferMemory>(GetInstanceProcAddr(instance, "vkBindBufferMemory")); BindBufferMemory = reinterpret_cast<PFN_vkBindBufferMemory>(GetInstanceProcAddr(instance, "vkBindBufferMemory"));
BindImageMemory = reinterpret_cast<PFN_vkBindImageMemory>(GetInstanceProcAddr(instance, "vkBindImageMemory")); BindImageMemory = reinterpret_cast<PFN_vkBindImageMemory>(GetInstanceProcAddr(instance, "vkBindImageMemory"));
GetBufferMemoryRequirements = reinterpret_cast<PFN_vkGetBufferMemoryRequirements>(GetInstanceProcAddr(instance, "vkGetBufferMemoryRequirements")); GetBufferMemoryRequirements = reinterpret_cast<PFN_vkGetBufferMemoryRequirements>(
GetImageMemoryRequirements = reinterpret_cast<PFN_vkGetImageMemoryRequirements>(GetInstanceProcAddr(instance, "vkGetImageMemoryRequirements")); GetInstanceProcAddr(instance, "vkGetBufferMemoryRequirements"));
GetImageSparseMemoryRequirements = reinterpret_cast<PFN_vkGetImageSparseMemoryRequirements>(GetInstanceProcAddr(instance, "vkGetImageSparseMemoryRequirements")); GetImageMemoryRequirements =
reinterpret_cast<PFN_vkGetImageMemoryRequirements>(GetInstanceProcAddr(instance, "vkGetImageMemoryRequirements"));
GetImageSparseMemoryRequirements = reinterpret_cast<PFN_vkGetImageSparseMemoryRequirements>(
GetInstanceProcAddr(instance, "vkGetImageSparseMemoryRequirements"));
QueueBindSparse = reinterpret_cast<PFN_vkQueueBindSparse>(GetInstanceProcAddr(instance, "vkQueueBindSparse")); QueueBindSparse = reinterpret_cast<PFN_vkQueueBindSparse>(GetInstanceProcAddr(instance, "vkQueueBindSparse"));
CreateFence = reinterpret_cast<PFN_vkCreateFence>(GetInstanceProcAddr(instance, "vkCreateFence")); CreateFence = reinterpret_cast<PFN_vkCreateFence>(GetInstanceProcAddr(instance, "vkCreateFence"));
DestroyFence = reinterpret_cast<PFN_vkDestroyFence>(GetInstanceProcAddr(instance, "vkDestroyFence")); DestroyFence = reinterpret_cast<PFN_vkDestroyFence>(GetInstanceProcAddr(instance, "vkDestroyFence"));
@ -293,104 +335,153 @@ void init_dispatch_table_middle(VkInstance instance, bool include_bottom)
ResetEvent = reinterpret_cast<PFN_vkResetEvent>(GetInstanceProcAddr(instance, "vkResetEvent")); ResetEvent = reinterpret_cast<PFN_vkResetEvent>(GetInstanceProcAddr(instance, "vkResetEvent"));
CreateQueryPool = reinterpret_cast<PFN_vkCreateQueryPool>(GetInstanceProcAddr(instance, "vkCreateQueryPool")); CreateQueryPool = reinterpret_cast<PFN_vkCreateQueryPool>(GetInstanceProcAddr(instance, "vkCreateQueryPool"));
DestroyQueryPool = reinterpret_cast<PFN_vkDestroyQueryPool>(GetInstanceProcAddr(instance, "vkDestroyQueryPool")); DestroyQueryPool = reinterpret_cast<PFN_vkDestroyQueryPool>(GetInstanceProcAddr(instance, "vkDestroyQueryPool"));
GetQueryPoolResults = reinterpret_cast<PFN_vkGetQueryPoolResults>(GetInstanceProcAddr(instance, "vkGetQueryPoolResults")); GetQueryPoolResults =
reinterpret_cast<PFN_vkGetQueryPoolResults>(GetInstanceProcAddr(instance, "vkGetQueryPoolResults"));
CreateBuffer = reinterpret_cast<PFN_vkCreateBuffer>(GetInstanceProcAddr(instance, "vkCreateBuffer")); CreateBuffer = reinterpret_cast<PFN_vkCreateBuffer>(GetInstanceProcAddr(instance, "vkCreateBuffer"));
DestroyBuffer = reinterpret_cast<PFN_vkDestroyBuffer>(GetInstanceProcAddr(instance, "vkDestroyBuffer")); DestroyBuffer = reinterpret_cast<PFN_vkDestroyBuffer>(GetInstanceProcAddr(instance, "vkDestroyBuffer"));
CreateBufferView = reinterpret_cast<PFN_vkCreateBufferView>(GetInstanceProcAddr(instance, "vkCreateBufferView")); CreateBufferView = reinterpret_cast<PFN_vkCreateBufferView>(GetInstanceProcAddr(instance, "vkCreateBufferView"));
DestroyBufferView = reinterpret_cast<PFN_vkDestroyBufferView>(GetInstanceProcAddr(instance, "vkDestroyBufferView")); DestroyBufferView = reinterpret_cast<PFN_vkDestroyBufferView>(GetInstanceProcAddr(instance, "vkDestroyBufferView"));
CreateImage = reinterpret_cast<PFN_vkCreateImage>(GetInstanceProcAddr(instance, "vkCreateImage")); CreateImage = reinterpret_cast<PFN_vkCreateImage>(GetInstanceProcAddr(instance, "vkCreateImage"));
DestroyImage = reinterpret_cast<PFN_vkDestroyImage>(GetInstanceProcAddr(instance, "vkDestroyImage")); DestroyImage = reinterpret_cast<PFN_vkDestroyImage>(GetInstanceProcAddr(instance, "vkDestroyImage"));
GetImageSubresourceLayout = reinterpret_cast<PFN_vkGetImageSubresourceLayout>(GetInstanceProcAddr(instance, "vkGetImageSubresourceLayout")); GetImageSubresourceLayout =
reinterpret_cast<PFN_vkGetImageSubresourceLayout>(GetInstanceProcAddr(instance, "vkGetImageSubresourceLayout"));
CreateImageView = reinterpret_cast<PFN_vkCreateImageView>(GetInstanceProcAddr(instance, "vkCreateImageView")); CreateImageView = reinterpret_cast<PFN_vkCreateImageView>(GetInstanceProcAddr(instance, "vkCreateImageView"));
DestroyImageView = reinterpret_cast<PFN_vkDestroyImageView>(GetInstanceProcAddr(instance, "vkDestroyImageView")); DestroyImageView = reinterpret_cast<PFN_vkDestroyImageView>(GetInstanceProcAddr(instance, "vkDestroyImageView"));
CreateShaderModule = reinterpret_cast<PFN_vkCreateShaderModule>(GetInstanceProcAddr(instance, "vkCreateShaderModule")); CreateShaderModule =
DestroyShaderModule = reinterpret_cast<PFN_vkDestroyShaderModule>(GetInstanceProcAddr(instance, "vkDestroyShaderModule")); reinterpret_cast<PFN_vkCreateShaderModule>(GetInstanceProcAddr(instance, "vkCreateShaderModule"));
CreatePipelineCache = reinterpret_cast<PFN_vkCreatePipelineCache>(GetInstanceProcAddr(instance, "vkCreatePipelineCache")); DestroyShaderModule =
DestroyPipelineCache = reinterpret_cast<PFN_vkDestroyPipelineCache>(GetInstanceProcAddr(instance, "vkDestroyPipelineCache")); reinterpret_cast<PFN_vkDestroyShaderModule>(GetInstanceProcAddr(instance, "vkDestroyShaderModule"));
GetPipelineCacheData = reinterpret_cast<PFN_vkGetPipelineCacheData>(GetInstanceProcAddr(instance, "vkGetPipelineCacheData")); CreatePipelineCache =
MergePipelineCaches = reinterpret_cast<PFN_vkMergePipelineCaches>(GetInstanceProcAddr(instance, "vkMergePipelineCaches")); reinterpret_cast<PFN_vkCreatePipelineCache>(GetInstanceProcAddr(instance, "vkCreatePipelineCache"));
CreateGraphicsPipelines = reinterpret_cast<PFN_vkCreateGraphicsPipelines>(GetInstanceProcAddr(instance, "vkCreateGraphicsPipelines")); DestroyPipelineCache =
CreateComputePipelines = reinterpret_cast<PFN_vkCreateComputePipelines>(GetInstanceProcAddr(instance, "vkCreateComputePipelines")); reinterpret_cast<PFN_vkDestroyPipelineCache>(GetInstanceProcAddr(instance, "vkDestroyPipelineCache"));
GetPipelineCacheData =
reinterpret_cast<PFN_vkGetPipelineCacheData>(GetInstanceProcAddr(instance, "vkGetPipelineCacheData"));
MergePipelineCaches =
reinterpret_cast<PFN_vkMergePipelineCaches>(GetInstanceProcAddr(instance, "vkMergePipelineCaches"));
CreateGraphicsPipelines =
reinterpret_cast<PFN_vkCreateGraphicsPipelines>(GetInstanceProcAddr(instance, "vkCreateGraphicsPipelines"));
CreateComputePipelines =
reinterpret_cast<PFN_vkCreateComputePipelines>(GetInstanceProcAddr(instance, "vkCreateComputePipelines"));
DestroyPipeline = reinterpret_cast<PFN_vkDestroyPipeline>(GetInstanceProcAddr(instance, "vkDestroyPipeline")); DestroyPipeline = reinterpret_cast<PFN_vkDestroyPipeline>(GetInstanceProcAddr(instance, "vkDestroyPipeline"));
CreatePipelineLayout = reinterpret_cast<PFN_vkCreatePipelineLayout>(GetInstanceProcAddr(instance, "vkCreatePipelineLayout")); CreatePipelineLayout =
DestroyPipelineLayout = reinterpret_cast<PFN_vkDestroyPipelineLayout>(GetInstanceProcAddr(instance, "vkDestroyPipelineLayout")); reinterpret_cast<PFN_vkCreatePipelineLayout>(GetInstanceProcAddr(instance, "vkCreatePipelineLayout"));
DestroyPipelineLayout =
reinterpret_cast<PFN_vkDestroyPipelineLayout>(GetInstanceProcAddr(instance, "vkDestroyPipelineLayout"));
CreateSampler = reinterpret_cast<PFN_vkCreateSampler>(GetInstanceProcAddr(instance, "vkCreateSampler")); CreateSampler = reinterpret_cast<PFN_vkCreateSampler>(GetInstanceProcAddr(instance, "vkCreateSampler"));
DestroySampler = reinterpret_cast<PFN_vkDestroySampler>(GetInstanceProcAddr(instance, "vkDestroySampler")); DestroySampler = reinterpret_cast<PFN_vkDestroySampler>(GetInstanceProcAddr(instance, "vkDestroySampler"));
CreateDescriptorSetLayout = reinterpret_cast<PFN_vkCreateDescriptorSetLayout>(GetInstanceProcAddr(instance, "vkCreateDescriptorSetLayout")); CreateDescriptorSetLayout =
DestroyDescriptorSetLayout = reinterpret_cast<PFN_vkDestroyDescriptorSetLayout>(GetInstanceProcAddr(instance, "vkDestroyDescriptorSetLayout")); reinterpret_cast<PFN_vkCreateDescriptorSetLayout>(GetInstanceProcAddr(instance, "vkCreateDescriptorSetLayout"));
CreateDescriptorPool = reinterpret_cast<PFN_vkCreateDescriptorPool>(GetInstanceProcAddr(instance, "vkCreateDescriptorPool")); DestroyDescriptorSetLayout =
DestroyDescriptorPool = reinterpret_cast<PFN_vkDestroyDescriptorPool>(GetInstanceProcAddr(instance, "vkDestroyDescriptorPool")); reinterpret_cast<PFN_vkDestroyDescriptorSetLayout>(GetInstanceProcAddr(instance, "vkDestroyDescriptorSetLayout"));
ResetDescriptorPool = reinterpret_cast<PFN_vkResetDescriptorPool>(GetInstanceProcAddr(instance, "vkResetDescriptorPool")); CreateDescriptorPool =
AllocateDescriptorSets = reinterpret_cast<PFN_vkAllocateDescriptorSets>(GetInstanceProcAddr(instance, "vkAllocateDescriptorSets")); reinterpret_cast<PFN_vkCreateDescriptorPool>(GetInstanceProcAddr(instance, "vkCreateDescriptorPool"));
FreeDescriptorSets = reinterpret_cast<PFN_vkFreeDescriptorSets>(GetInstanceProcAddr(instance, "vkFreeDescriptorSets")); DestroyDescriptorPool =
UpdateDescriptorSets = reinterpret_cast<PFN_vkUpdateDescriptorSets>(GetInstanceProcAddr(instance, "vkUpdateDescriptorSets")); reinterpret_cast<PFN_vkDestroyDescriptorPool>(GetInstanceProcAddr(instance, "vkDestroyDescriptorPool"));
ResetDescriptorPool =
reinterpret_cast<PFN_vkResetDescriptorPool>(GetInstanceProcAddr(instance, "vkResetDescriptorPool"));
AllocateDescriptorSets =
reinterpret_cast<PFN_vkAllocateDescriptorSets>(GetInstanceProcAddr(instance, "vkAllocateDescriptorSets"));
FreeDescriptorSets =
reinterpret_cast<PFN_vkFreeDescriptorSets>(GetInstanceProcAddr(instance, "vkFreeDescriptorSets"));
UpdateDescriptorSets =
reinterpret_cast<PFN_vkUpdateDescriptorSets>(GetInstanceProcAddr(instance, "vkUpdateDescriptorSets"));
CreateFramebuffer = reinterpret_cast<PFN_vkCreateFramebuffer>(GetInstanceProcAddr(instance, "vkCreateFramebuffer")); CreateFramebuffer = reinterpret_cast<PFN_vkCreateFramebuffer>(GetInstanceProcAddr(instance, "vkCreateFramebuffer"));
DestroyFramebuffer = reinterpret_cast<PFN_vkDestroyFramebuffer>(GetInstanceProcAddr(instance, "vkDestroyFramebuffer")); DestroyFramebuffer =
reinterpret_cast<PFN_vkDestroyFramebuffer>(GetInstanceProcAddr(instance, "vkDestroyFramebuffer"));
CreateRenderPass = reinterpret_cast<PFN_vkCreateRenderPass>(GetInstanceProcAddr(instance, "vkCreateRenderPass")); CreateRenderPass = reinterpret_cast<PFN_vkCreateRenderPass>(GetInstanceProcAddr(instance, "vkCreateRenderPass"));
DestroyRenderPass = reinterpret_cast<PFN_vkDestroyRenderPass>(GetInstanceProcAddr(instance, "vkDestroyRenderPass")); DestroyRenderPass = reinterpret_cast<PFN_vkDestroyRenderPass>(GetInstanceProcAddr(instance, "vkDestroyRenderPass"));
GetRenderAreaGranularity = reinterpret_cast<PFN_vkGetRenderAreaGranularity>(GetInstanceProcAddr(instance, "vkGetRenderAreaGranularity")); GetRenderAreaGranularity =
reinterpret_cast<PFN_vkGetRenderAreaGranularity>(GetInstanceProcAddr(instance, "vkGetRenderAreaGranularity"));
CreateCommandPool = reinterpret_cast<PFN_vkCreateCommandPool>(GetInstanceProcAddr(instance, "vkCreateCommandPool")); CreateCommandPool = reinterpret_cast<PFN_vkCreateCommandPool>(GetInstanceProcAddr(instance, "vkCreateCommandPool"));
DestroyCommandPool = reinterpret_cast<PFN_vkDestroyCommandPool>(GetInstanceProcAddr(instance, "vkDestroyCommandPool")); DestroyCommandPool =
reinterpret_cast<PFN_vkDestroyCommandPool>(GetInstanceProcAddr(instance, "vkDestroyCommandPool"));
ResetCommandPool = reinterpret_cast<PFN_vkResetCommandPool>(GetInstanceProcAddr(instance, "vkResetCommandPool")); ResetCommandPool = reinterpret_cast<PFN_vkResetCommandPool>(GetInstanceProcAddr(instance, "vkResetCommandPool"));
AllocateCommandBuffers = reinterpret_cast<PFN_vkAllocateCommandBuffers>(GetInstanceProcAddr(instance, "vkAllocateCommandBuffers")); AllocateCommandBuffers =
FreeCommandBuffers = reinterpret_cast<PFN_vkFreeCommandBuffers>(GetInstanceProcAddr(instance, "vkFreeCommandBuffers")); reinterpret_cast<PFN_vkAllocateCommandBuffers>(GetInstanceProcAddr(instance, "vkAllocateCommandBuffers"));
BeginCommandBuffer = reinterpret_cast<PFN_vkBeginCommandBuffer>(GetInstanceProcAddr(instance, "vkBeginCommandBuffer")); FreeCommandBuffers =
reinterpret_cast<PFN_vkFreeCommandBuffers>(GetInstanceProcAddr(instance, "vkFreeCommandBuffers"));
BeginCommandBuffer =
reinterpret_cast<PFN_vkBeginCommandBuffer>(GetInstanceProcAddr(instance, "vkBeginCommandBuffer"));
EndCommandBuffer = reinterpret_cast<PFN_vkEndCommandBuffer>(GetInstanceProcAddr(instance, "vkEndCommandBuffer")); EndCommandBuffer = reinterpret_cast<PFN_vkEndCommandBuffer>(GetInstanceProcAddr(instance, "vkEndCommandBuffer"));
ResetCommandBuffer = reinterpret_cast<PFN_vkResetCommandBuffer>(GetInstanceProcAddr(instance, "vkResetCommandBuffer")); ResetCommandBuffer =
reinterpret_cast<PFN_vkResetCommandBuffer>(GetInstanceProcAddr(instance, "vkResetCommandBuffer"));
CmdBindPipeline = reinterpret_cast<PFN_vkCmdBindPipeline>(GetInstanceProcAddr(instance, "vkCmdBindPipeline")); CmdBindPipeline = reinterpret_cast<PFN_vkCmdBindPipeline>(GetInstanceProcAddr(instance, "vkCmdBindPipeline"));
CmdSetViewport = reinterpret_cast<PFN_vkCmdSetViewport>(GetInstanceProcAddr(instance, "vkCmdSetViewport")); CmdSetViewport = reinterpret_cast<PFN_vkCmdSetViewport>(GetInstanceProcAddr(instance, "vkCmdSetViewport"));
CmdSetScissor = reinterpret_cast<PFN_vkCmdSetScissor>(GetInstanceProcAddr(instance, "vkCmdSetScissor")); CmdSetScissor = reinterpret_cast<PFN_vkCmdSetScissor>(GetInstanceProcAddr(instance, "vkCmdSetScissor"));
CmdSetLineWidth = reinterpret_cast<PFN_vkCmdSetLineWidth>(GetInstanceProcAddr(instance, "vkCmdSetLineWidth")); CmdSetLineWidth = reinterpret_cast<PFN_vkCmdSetLineWidth>(GetInstanceProcAddr(instance, "vkCmdSetLineWidth"));
CmdSetDepthBias = reinterpret_cast<PFN_vkCmdSetDepthBias>(GetInstanceProcAddr(instance, "vkCmdSetDepthBias")); CmdSetDepthBias = reinterpret_cast<PFN_vkCmdSetDepthBias>(GetInstanceProcAddr(instance, "vkCmdSetDepthBias"));
CmdSetBlendConstants = reinterpret_cast<PFN_vkCmdSetBlendConstants>(GetInstanceProcAddr(instance, "vkCmdSetBlendConstants")); CmdSetBlendConstants =
reinterpret_cast<PFN_vkCmdSetBlendConstants>(GetInstanceProcAddr(instance, "vkCmdSetBlendConstants"));
CmdSetDepthBounds = reinterpret_cast<PFN_vkCmdSetDepthBounds>(GetInstanceProcAddr(instance, "vkCmdSetDepthBounds")); CmdSetDepthBounds = reinterpret_cast<PFN_vkCmdSetDepthBounds>(GetInstanceProcAddr(instance, "vkCmdSetDepthBounds"));
CmdSetStencilCompareMask = reinterpret_cast<PFN_vkCmdSetStencilCompareMask>(GetInstanceProcAddr(instance, "vkCmdSetStencilCompareMask")); CmdSetStencilCompareMask =
CmdSetStencilWriteMask = reinterpret_cast<PFN_vkCmdSetStencilWriteMask>(GetInstanceProcAddr(instance, "vkCmdSetStencilWriteMask")); reinterpret_cast<PFN_vkCmdSetStencilCompareMask>(GetInstanceProcAddr(instance, "vkCmdSetStencilCompareMask"));
CmdSetStencilReference = reinterpret_cast<PFN_vkCmdSetStencilReference>(GetInstanceProcAddr(instance, "vkCmdSetStencilReference")); CmdSetStencilWriteMask =
CmdBindDescriptorSets = reinterpret_cast<PFN_vkCmdBindDescriptorSets>(GetInstanceProcAddr(instance, "vkCmdBindDescriptorSets")); reinterpret_cast<PFN_vkCmdSetStencilWriteMask>(GetInstanceProcAddr(instance, "vkCmdSetStencilWriteMask"));
CmdBindIndexBuffer = reinterpret_cast<PFN_vkCmdBindIndexBuffer>(GetInstanceProcAddr(instance, "vkCmdBindIndexBuffer")); CmdSetStencilReference =
CmdBindVertexBuffers = reinterpret_cast<PFN_vkCmdBindVertexBuffers>(GetInstanceProcAddr(instance, "vkCmdBindVertexBuffers")); reinterpret_cast<PFN_vkCmdSetStencilReference>(GetInstanceProcAddr(instance, "vkCmdSetStencilReference"));
CmdBindDescriptorSets =
reinterpret_cast<PFN_vkCmdBindDescriptorSets>(GetInstanceProcAddr(instance, "vkCmdBindDescriptorSets"));
CmdBindIndexBuffer =
reinterpret_cast<PFN_vkCmdBindIndexBuffer>(GetInstanceProcAddr(instance, "vkCmdBindIndexBuffer"));
CmdBindVertexBuffers =
reinterpret_cast<PFN_vkCmdBindVertexBuffers>(GetInstanceProcAddr(instance, "vkCmdBindVertexBuffers"));
CmdDraw = reinterpret_cast<PFN_vkCmdDraw>(GetInstanceProcAddr(instance, "vkCmdDraw")); CmdDraw = reinterpret_cast<PFN_vkCmdDraw>(GetInstanceProcAddr(instance, "vkCmdDraw"));
CmdDrawIndexed = reinterpret_cast<PFN_vkCmdDrawIndexed>(GetInstanceProcAddr(instance, "vkCmdDrawIndexed")); CmdDrawIndexed = reinterpret_cast<PFN_vkCmdDrawIndexed>(GetInstanceProcAddr(instance, "vkCmdDrawIndexed"));
CmdDrawIndirect = reinterpret_cast<PFN_vkCmdDrawIndirect>(GetInstanceProcAddr(instance, "vkCmdDrawIndirect")); CmdDrawIndirect = reinterpret_cast<PFN_vkCmdDrawIndirect>(GetInstanceProcAddr(instance, "vkCmdDrawIndirect"));
CmdDrawIndexedIndirect = reinterpret_cast<PFN_vkCmdDrawIndexedIndirect>(GetInstanceProcAddr(instance, "vkCmdDrawIndexedIndirect")); CmdDrawIndexedIndirect =
reinterpret_cast<PFN_vkCmdDrawIndexedIndirect>(GetInstanceProcAddr(instance, "vkCmdDrawIndexedIndirect"));
CmdDispatch = reinterpret_cast<PFN_vkCmdDispatch>(GetInstanceProcAddr(instance, "vkCmdDispatch")); CmdDispatch = reinterpret_cast<PFN_vkCmdDispatch>(GetInstanceProcAddr(instance, "vkCmdDispatch"));
CmdDispatchIndirect = reinterpret_cast<PFN_vkCmdDispatchIndirect>(GetInstanceProcAddr(instance, "vkCmdDispatchIndirect")); CmdDispatchIndirect =
reinterpret_cast<PFN_vkCmdDispatchIndirect>(GetInstanceProcAddr(instance, "vkCmdDispatchIndirect"));
CmdCopyBuffer = reinterpret_cast<PFN_vkCmdCopyBuffer>(GetInstanceProcAddr(instance, "vkCmdCopyBuffer")); CmdCopyBuffer = reinterpret_cast<PFN_vkCmdCopyBuffer>(GetInstanceProcAddr(instance, "vkCmdCopyBuffer"));
CmdCopyImage = reinterpret_cast<PFN_vkCmdCopyImage>(GetInstanceProcAddr(instance, "vkCmdCopyImage")); CmdCopyImage = reinterpret_cast<PFN_vkCmdCopyImage>(GetInstanceProcAddr(instance, "vkCmdCopyImage"));
CmdBlitImage = reinterpret_cast<PFN_vkCmdBlitImage>(GetInstanceProcAddr(instance, "vkCmdBlitImage")); CmdBlitImage = reinterpret_cast<PFN_vkCmdBlitImage>(GetInstanceProcAddr(instance, "vkCmdBlitImage"));
CmdCopyBufferToImage = reinterpret_cast<PFN_vkCmdCopyBufferToImage>(GetInstanceProcAddr(instance, "vkCmdCopyBufferToImage")); CmdCopyBufferToImage =
CmdCopyImageToBuffer = reinterpret_cast<PFN_vkCmdCopyImageToBuffer>(GetInstanceProcAddr(instance, "vkCmdCopyImageToBuffer")); reinterpret_cast<PFN_vkCmdCopyBufferToImage>(GetInstanceProcAddr(instance, "vkCmdCopyBufferToImage"));
CmdCopyImageToBuffer =
reinterpret_cast<PFN_vkCmdCopyImageToBuffer>(GetInstanceProcAddr(instance, "vkCmdCopyImageToBuffer"));
CmdUpdateBuffer = reinterpret_cast<PFN_vkCmdUpdateBuffer>(GetInstanceProcAddr(instance, "vkCmdUpdateBuffer")); CmdUpdateBuffer = reinterpret_cast<PFN_vkCmdUpdateBuffer>(GetInstanceProcAddr(instance, "vkCmdUpdateBuffer"));
CmdFillBuffer = reinterpret_cast<PFN_vkCmdFillBuffer>(GetInstanceProcAddr(instance, "vkCmdFillBuffer")); CmdFillBuffer = reinterpret_cast<PFN_vkCmdFillBuffer>(GetInstanceProcAddr(instance, "vkCmdFillBuffer"));
CmdClearColorImage = reinterpret_cast<PFN_vkCmdClearColorImage>(GetInstanceProcAddr(instance, "vkCmdClearColorImage")); CmdClearColorImage =
CmdClearDepthStencilImage = reinterpret_cast<PFN_vkCmdClearDepthStencilImage>(GetInstanceProcAddr(instance, "vkCmdClearDepthStencilImage")); reinterpret_cast<PFN_vkCmdClearColorImage>(GetInstanceProcAddr(instance, "vkCmdClearColorImage"));
CmdClearAttachments = reinterpret_cast<PFN_vkCmdClearAttachments>(GetInstanceProcAddr(instance, "vkCmdClearAttachments")); CmdClearDepthStencilImage =
reinterpret_cast<PFN_vkCmdClearDepthStencilImage>(GetInstanceProcAddr(instance, "vkCmdClearDepthStencilImage"));
CmdClearAttachments =
reinterpret_cast<PFN_vkCmdClearAttachments>(GetInstanceProcAddr(instance, "vkCmdClearAttachments"));
CmdResolveImage = reinterpret_cast<PFN_vkCmdResolveImage>(GetInstanceProcAddr(instance, "vkCmdResolveImage")); CmdResolveImage = reinterpret_cast<PFN_vkCmdResolveImage>(GetInstanceProcAddr(instance, "vkCmdResolveImage"));
CmdSetEvent = reinterpret_cast<PFN_vkCmdSetEvent>(GetInstanceProcAddr(instance, "vkCmdSetEvent")); CmdSetEvent = reinterpret_cast<PFN_vkCmdSetEvent>(GetInstanceProcAddr(instance, "vkCmdSetEvent"));
CmdResetEvent = reinterpret_cast<PFN_vkCmdResetEvent>(GetInstanceProcAddr(instance, "vkCmdResetEvent")); CmdResetEvent = reinterpret_cast<PFN_vkCmdResetEvent>(GetInstanceProcAddr(instance, "vkCmdResetEvent"));
CmdWaitEvents = reinterpret_cast<PFN_vkCmdWaitEvents>(GetInstanceProcAddr(instance, "vkCmdWaitEvents")); CmdWaitEvents = reinterpret_cast<PFN_vkCmdWaitEvents>(GetInstanceProcAddr(instance, "vkCmdWaitEvents"));
CmdPipelineBarrier = reinterpret_cast<PFN_vkCmdPipelineBarrier>(GetInstanceProcAddr(instance, "vkCmdPipelineBarrier")); CmdPipelineBarrier =
reinterpret_cast<PFN_vkCmdPipelineBarrier>(GetInstanceProcAddr(instance, "vkCmdPipelineBarrier"));
CmdBeginQuery = reinterpret_cast<PFN_vkCmdBeginQuery>(GetInstanceProcAddr(instance, "vkCmdBeginQuery")); CmdBeginQuery = reinterpret_cast<PFN_vkCmdBeginQuery>(GetInstanceProcAddr(instance, "vkCmdBeginQuery"));
CmdEndQuery = reinterpret_cast<PFN_vkCmdEndQuery>(GetInstanceProcAddr(instance, "vkCmdEndQuery")); CmdEndQuery = reinterpret_cast<PFN_vkCmdEndQuery>(GetInstanceProcAddr(instance, "vkCmdEndQuery"));
CmdResetQueryPool = reinterpret_cast<PFN_vkCmdResetQueryPool>(GetInstanceProcAddr(instance, "vkCmdResetQueryPool")); CmdResetQueryPool = reinterpret_cast<PFN_vkCmdResetQueryPool>(GetInstanceProcAddr(instance, "vkCmdResetQueryPool"));
CmdWriteTimestamp = reinterpret_cast<PFN_vkCmdWriteTimestamp>(GetInstanceProcAddr(instance, "vkCmdWriteTimestamp")); CmdWriteTimestamp = reinterpret_cast<PFN_vkCmdWriteTimestamp>(GetInstanceProcAddr(instance, "vkCmdWriteTimestamp"));
CmdCopyQueryPoolResults = reinterpret_cast<PFN_vkCmdCopyQueryPoolResults>(GetInstanceProcAddr(instance, "vkCmdCopyQueryPoolResults")); CmdCopyQueryPoolResults =
reinterpret_cast<PFN_vkCmdCopyQueryPoolResults>(GetInstanceProcAddr(instance, "vkCmdCopyQueryPoolResults"));
CmdPushConstants = reinterpret_cast<PFN_vkCmdPushConstants>(GetInstanceProcAddr(instance, "vkCmdPushConstants")); CmdPushConstants = reinterpret_cast<PFN_vkCmdPushConstants>(GetInstanceProcAddr(instance, "vkCmdPushConstants"));
CmdBeginRenderPass = reinterpret_cast<PFN_vkCmdBeginRenderPass>(GetInstanceProcAddr(instance, "vkCmdBeginRenderPass")); CmdBeginRenderPass =
reinterpret_cast<PFN_vkCmdBeginRenderPass>(GetInstanceProcAddr(instance, "vkCmdBeginRenderPass"));
CmdNextSubpass = reinterpret_cast<PFN_vkCmdNextSubpass>(GetInstanceProcAddr(instance, "vkCmdNextSubpass")); CmdNextSubpass = reinterpret_cast<PFN_vkCmdNextSubpass>(GetInstanceProcAddr(instance, "vkCmdNextSubpass"));
CmdEndRenderPass = reinterpret_cast<PFN_vkCmdEndRenderPass>(GetInstanceProcAddr(instance, "vkCmdEndRenderPass")); CmdEndRenderPass = reinterpret_cast<PFN_vkCmdEndRenderPass>(GetInstanceProcAddr(instance, "vkCmdEndRenderPass"));
CmdExecuteCommands = reinterpret_cast<PFN_vkCmdExecuteCommands>(GetInstanceProcAddr(instance, "vkCmdExecuteCommands")); CmdExecuteCommands =
CreateSwapchainKHR = reinterpret_cast<PFN_vkCreateSwapchainKHR>(GetInstanceProcAddr(instance, "vkCreateSwapchainKHR")); reinterpret_cast<PFN_vkCmdExecuteCommands>(GetInstanceProcAddr(instance, "vkCmdExecuteCommands"));
DestroySwapchainKHR = reinterpret_cast<PFN_vkDestroySwapchainKHR>(GetInstanceProcAddr(instance, "vkDestroySwapchainKHR")); CreateSwapchainKHR =
GetSwapchainImagesKHR = reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(GetInstanceProcAddr(instance, "vkGetSwapchainImagesKHR")); reinterpret_cast<PFN_vkCreateSwapchainKHR>(GetInstanceProcAddr(instance, "vkCreateSwapchainKHR"));
AcquireNextImageKHR = reinterpret_cast<PFN_vkAcquireNextImageKHR>(GetInstanceProcAddr(instance, "vkAcquireNextImageKHR")); DestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(GetInstanceProcAddr(instance, "vkDestroySwapchainKHR"));
GetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(GetInstanceProcAddr(instance, "vkGetSwapchainImagesKHR"));
AcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(GetInstanceProcAddr(instance, "vkAcquireNextImageKHR"));
QueuePresentKHR = reinterpret_cast<PFN_vkQueuePresentKHR>(GetInstanceProcAddr(instance, "vkQueuePresentKHR")); QueuePresentKHR = reinterpret_cast<PFN_vkQueuePresentKHR>(GetInstanceProcAddr(instance, "vkQueuePresentKHR"));
CreateSharedSwapchainsKHR = reinterpret_cast<PFN_vkCreateSharedSwapchainsKHR>(GetInstanceProcAddr(instance, "vkCreateSharedSwapchainsKHR")); CreateSharedSwapchainsKHR =
reinterpret_cast<PFN_vkCreateSharedSwapchainsKHR>(GetInstanceProcAddr(instance, "vkCreateSharedSwapchainsKHR"));
} }
void init_dispatch_table_bottom(VkInstance instance, VkDevice dev) void init_dispatch_table_bottom(VkInstance instance, VkDevice dev) {
{
GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(GetInstanceProcAddr(instance, "vkGetDeviceProcAddr")); GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(GetInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(GetDeviceProcAddr(dev, "vkGetDeviceProcAddr")); GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(GetDeviceProcAddr(dev, "vkGetDeviceProcAddr"));
@ -403,14 +494,20 @@ void init_dispatch_table_bottom(VkInstance instance, VkDevice dev)
FreeMemory = reinterpret_cast<PFN_vkFreeMemory>(GetDeviceProcAddr(dev, "vkFreeMemory")); FreeMemory = reinterpret_cast<PFN_vkFreeMemory>(GetDeviceProcAddr(dev, "vkFreeMemory"));
MapMemory = reinterpret_cast<PFN_vkMapMemory>(GetDeviceProcAddr(dev, "vkMapMemory")); MapMemory = reinterpret_cast<PFN_vkMapMemory>(GetDeviceProcAddr(dev, "vkMapMemory"));
UnmapMemory = reinterpret_cast<PFN_vkUnmapMemory>(GetDeviceProcAddr(dev, "vkUnmapMemory")); UnmapMemory = reinterpret_cast<PFN_vkUnmapMemory>(GetDeviceProcAddr(dev, "vkUnmapMemory"));
FlushMappedMemoryRanges = reinterpret_cast<PFN_vkFlushMappedMemoryRanges>(GetDeviceProcAddr(dev, "vkFlushMappedMemoryRanges")); FlushMappedMemoryRanges =
InvalidateMappedMemoryRanges = reinterpret_cast<PFN_vkInvalidateMappedMemoryRanges>(GetDeviceProcAddr(dev, "vkInvalidateMappedMemoryRanges")); reinterpret_cast<PFN_vkFlushMappedMemoryRanges>(GetDeviceProcAddr(dev, "vkFlushMappedMemoryRanges"));
GetDeviceMemoryCommitment = reinterpret_cast<PFN_vkGetDeviceMemoryCommitment>(GetDeviceProcAddr(dev, "vkGetDeviceMemoryCommitment")); InvalidateMappedMemoryRanges =
reinterpret_cast<PFN_vkInvalidateMappedMemoryRanges>(GetDeviceProcAddr(dev, "vkInvalidateMappedMemoryRanges"));
GetDeviceMemoryCommitment =
reinterpret_cast<PFN_vkGetDeviceMemoryCommitment>(GetDeviceProcAddr(dev, "vkGetDeviceMemoryCommitment"));
BindBufferMemory = reinterpret_cast<PFN_vkBindBufferMemory>(GetDeviceProcAddr(dev, "vkBindBufferMemory")); BindBufferMemory = reinterpret_cast<PFN_vkBindBufferMemory>(GetDeviceProcAddr(dev, "vkBindBufferMemory"));
BindImageMemory = reinterpret_cast<PFN_vkBindImageMemory>(GetDeviceProcAddr(dev, "vkBindImageMemory")); BindImageMemory = reinterpret_cast<PFN_vkBindImageMemory>(GetDeviceProcAddr(dev, "vkBindImageMemory"));
GetBufferMemoryRequirements = reinterpret_cast<PFN_vkGetBufferMemoryRequirements>(GetDeviceProcAddr(dev, "vkGetBufferMemoryRequirements")); GetBufferMemoryRequirements =
GetImageMemoryRequirements = reinterpret_cast<PFN_vkGetImageMemoryRequirements>(GetDeviceProcAddr(dev, "vkGetImageMemoryRequirements")); reinterpret_cast<PFN_vkGetBufferMemoryRequirements>(GetDeviceProcAddr(dev, "vkGetBufferMemoryRequirements"));
GetImageSparseMemoryRequirements = reinterpret_cast<PFN_vkGetImageSparseMemoryRequirements>(GetDeviceProcAddr(dev, "vkGetImageSparseMemoryRequirements")); GetImageMemoryRequirements =
reinterpret_cast<PFN_vkGetImageMemoryRequirements>(GetDeviceProcAddr(dev, "vkGetImageMemoryRequirements"));
GetImageSparseMemoryRequirements = reinterpret_cast<PFN_vkGetImageSparseMemoryRequirements>(
GetDeviceProcAddr(dev, "vkGetImageSparseMemoryRequirements"));
QueueBindSparse = reinterpret_cast<PFN_vkQueueBindSparse>(GetDeviceProcAddr(dev, "vkQueueBindSparse")); QueueBindSparse = reinterpret_cast<PFN_vkQueueBindSparse>(GetDeviceProcAddr(dev, "vkQueueBindSparse"));
CreateFence = reinterpret_cast<PFN_vkCreateFence>(GetDeviceProcAddr(dev, "vkCreateFence")); CreateFence = reinterpret_cast<PFN_vkCreateFence>(GetDeviceProcAddr(dev, "vkCreateFence"));
DestroyFence = reinterpret_cast<PFN_vkDestroyFence>(GetDeviceProcAddr(dev, "vkDestroyFence")); DestroyFence = reinterpret_cast<PFN_vkDestroyFence>(GetDeviceProcAddr(dev, "vkDestroyFence"));
@ -433,7 +530,8 @@ void init_dispatch_table_bottom(VkInstance instance, VkDevice dev)
DestroyBufferView = reinterpret_cast<PFN_vkDestroyBufferView>(GetDeviceProcAddr(dev, "vkDestroyBufferView")); DestroyBufferView = reinterpret_cast<PFN_vkDestroyBufferView>(GetDeviceProcAddr(dev, "vkDestroyBufferView"));
CreateImage = reinterpret_cast<PFN_vkCreateImage>(GetDeviceProcAddr(dev, "vkCreateImage")); CreateImage = reinterpret_cast<PFN_vkCreateImage>(GetDeviceProcAddr(dev, "vkCreateImage"));
DestroyImage = reinterpret_cast<PFN_vkDestroyImage>(GetDeviceProcAddr(dev, "vkDestroyImage")); DestroyImage = reinterpret_cast<PFN_vkDestroyImage>(GetDeviceProcAddr(dev, "vkDestroyImage"));
GetImageSubresourceLayout = reinterpret_cast<PFN_vkGetImageSubresourceLayout>(GetDeviceProcAddr(dev, "vkGetImageSubresourceLayout")); GetImageSubresourceLayout =
reinterpret_cast<PFN_vkGetImageSubresourceLayout>(GetDeviceProcAddr(dev, "vkGetImageSubresourceLayout"));
CreateImageView = reinterpret_cast<PFN_vkCreateImageView>(GetDeviceProcAddr(dev, "vkCreateImageView")); CreateImageView = reinterpret_cast<PFN_vkCreateImageView>(GetDeviceProcAddr(dev, "vkCreateImageView"));
DestroyImageView = reinterpret_cast<PFN_vkDestroyImageView>(GetDeviceProcAddr(dev, "vkDestroyImageView")); DestroyImageView = reinterpret_cast<PFN_vkDestroyImageView>(GetDeviceProcAddr(dev, "vkDestroyImageView"));
CreateShaderModule = reinterpret_cast<PFN_vkCreateShaderModule>(GetDeviceProcAddr(dev, "vkCreateShaderModule")); CreateShaderModule = reinterpret_cast<PFN_vkCreateShaderModule>(GetDeviceProcAddr(dev, "vkCreateShaderModule"));
@ -442,30 +540,39 @@ void init_dispatch_table_bottom(VkInstance instance, VkDevice dev)
DestroyPipelineCache = reinterpret_cast<PFN_vkDestroyPipelineCache>(GetDeviceProcAddr(dev, "vkDestroyPipelineCache")); DestroyPipelineCache = reinterpret_cast<PFN_vkDestroyPipelineCache>(GetDeviceProcAddr(dev, "vkDestroyPipelineCache"));
GetPipelineCacheData = reinterpret_cast<PFN_vkGetPipelineCacheData>(GetDeviceProcAddr(dev, "vkGetPipelineCacheData")); GetPipelineCacheData = reinterpret_cast<PFN_vkGetPipelineCacheData>(GetDeviceProcAddr(dev, "vkGetPipelineCacheData"));
MergePipelineCaches = reinterpret_cast<PFN_vkMergePipelineCaches>(GetDeviceProcAddr(dev, "vkMergePipelineCaches")); MergePipelineCaches = reinterpret_cast<PFN_vkMergePipelineCaches>(GetDeviceProcAddr(dev, "vkMergePipelineCaches"));
CreateGraphicsPipelines = reinterpret_cast<PFN_vkCreateGraphicsPipelines>(GetDeviceProcAddr(dev, "vkCreateGraphicsPipelines")); CreateGraphicsPipelines =
CreateComputePipelines = reinterpret_cast<PFN_vkCreateComputePipelines>(GetDeviceProcAddr(dev, "vkCreateComputePipelines")); reinterpret_cast<PFN_vkCreateGraphicsPipelines>(GetDeviceProcAddr(dev, "vkCreateGraphicsPipelines"));
CreateComputePipelines =
reinterpret_cast<PFN_vkCreateComputePipelines>(GetDeviceProcAddr(dev, "vkCreateComputePipelines"));
DestroyPipeline = reinterpret_cast<PFN_vkDestroyPipeline>(GetDeviceProcAddr(dev, "vkDestroyPipeline")); DestroyPipeline = reinterpret_cast<PFN_vkDestroyPipeline>(GetDeviceProcAddr(dev, "vkDestroyPipeline"));
CreatePipelineLayout = reinterpret_cast<PFN_vkCreatePipelineLayout>(GetDeviceProcAddr(dev, "vkCreatePipelineLayout")); CreatePipelineLayout = reinterpret_cast<PFN_vkCreatePipelineLayout>(GetDeviceProcAddr(dev, "vkCreatePipelineLayout"));
DestroyPipelineLayout = reinterpret_cast<PFN_vkDestroyPipelineLayout>(GetDeviceProcAddr(dev, "vkDestroyPipelineLayout")); DestroyPipelineLayout =
reinterpret_cast<PFN_vkDestroyPipelineLayout>(GetDeviceProcAddr(dev, "vkDestroyPipelineLayout"));
CreateSampler = reinterpret_cast<PFN_vkCreateSampler>(GetDeviceProcAddr(dev, "vkCreateSampler")); CreateSampler = reinterpret_cast<PFN_vkCreateSampler>(GetDeviceProcAddr(dev, "vkCreateSampler"));
DestroySampler = reinterpret_cast<PFN_vkDestroySampler>(GetDeviceProcAddr(dev, "vkDestroySampler")); DestroySampler = reinterpret_cast<PFN_vkDestroySampler>(GetDeviceProcAddr(dev, "vkDestroySampler"));
CreateDescriptorSetLayout = reinterpret_cast<PFN_vkCreateDescriptorSetLayout>(GetDeviceProcAddr(dev, "vkCreateDescriptorSetLayout")); CreateDescriptorSetLayout =
DestroyDescriptorSetLayout = reinterpret_cast<PFN_vkDestroyDescriptorSetLayout>(GetDeviceProcAddr(dev, "vkDestroyDescriptorSetLayout")); reinterpret_cast<PFN_vkCreateDescriptorSetLayout>(GetDeviceProcAddr(dev, "vkCreateDescriptorSetLayout"));
DestroyDescriptorSetLayout =
reinterpret_cast<PFN_vkDestroyDescriptorSetLayout>(GetDeviceProcAddr(dev, "vkDestroyDescriptorSetLayout"));
CreateDescriptorPool = reinterpret_cast<PFN_vkCreateDescriptorPool>(GetDeviceProcAddr(dev, "vkCreateDescriptorPool")); CreateDescriptorPool = reinterpret_cast<PFN_vkCreateDescriptorPool>(GetDeviceProcAddr(dev, "vkCreateDescriptorPool"));
DestroyDescriptorPool = reinterpret_cast<PFN_vkDestroyDescriptorPool>(GetDeviceProcAddr(dev, "vkDestroyDescriptorPool")); DestroyDescriptorPool =
reinterpret_cast<PFN_vkDestroyDescriptorPool>(GetDeviceProcAddr(dev, "vkDestroyDescriptorPool"));
ResetDescriptorPool = reinterpret_cast<PFN_vkResetDescriptorPool>(GetDeviceProcAddr(dev, "vkResetDescriptorPool")); ResetDescriptorPool = reinterpret_cast<PFN_vkResetDescriptorPool>(GetDeviceProcAddr(dev, "vkResetDescriptorPool"));
AllocateDescriptorSets = reinterpret_cast<PFN_vkAllocateDescriptorSets>(GetDeviceProcAddr(dev, "vkAllocateDescriptorSets")); AllocateDescriptorSets =
reinterpret_cast<PFN_vkAllocateDescriptorSets>(GetDeviceProcAddr(dev, "vkAllocateDescriptorSets"));
FreeDescriptorSets = reinterpret_cast<PFN_vkFreeDescriptorSets>(GetDeviceProcAddr(dev, "vkFreeDescriptorSets")); FreeDescriptorSets = reinterpret_cast<PFN_vkFreeDescriptorSets>(GetDeviceProcAddr(dev, "vkFreeDescriptorSets"));
UpdateDescriptorSets = reinterpret_cast<PFN_vkUpdateDescriptorSets>(GetDeviceProcAddr(dev, "vkUpdateDescriptorSets")); UpdateDescriptorSets = reinterpret_cast<PFN_vkUpdateDescriptorSets>(GetDeviceProcAddr(dev, "vkUpdateDescriptorSets"));
CreateFramebuffer = reinterpret_cast<PFN_vkCreateFramebuffer>(GetDeviceProcAddr(dev, "vkCreateFramebuffer")); CreateFramebuffer = reinterpret_cast<PFN_vkCreateFramebuffer>(GetDeviceProcAddr(dev, "vkCreateFramebuffer"));
DestroyFramebuffer = reinterpret_cast<PFN_vkDestroyFramebuffer>(GetDeviceProcAddr(dev, "vkDestroyFramebuffer")); DestroyFramebuffer = reinterpret_cast<PFN_vkDestroyFramebuffer>(GetDeviceProcAddr(dev, "vkDestroyFramebuffer"));
CreateRenderPass = reinterpret_cast<PFN_vkCreateRenderPass>(GetDeviceProcAddr(dev, "vkCreateRenderPass")); CreateRenderPass = reinterpret_cast<PFN_vkCreateRenderPass>(GetDeviceProcAddr(dev, "vkCreateRenderPass"));
DestroyRenderPass = reinterpret_cast<PFN_vkDestroyRenderPass>(GetDeviceProcAddr(dev, "vkDestroyRenderPass")); DestroyRenderPass = reinterpret_cast<PFN_vkDestroyRenderPass>(GetDeviceProcAddr(dev, "vkDestroyRenderPass"));
GetRenderAreaGranularity = reinterpret_cast<PFN_vkGetRenderAreaGranularity>(GetDeviceProcAddr(dev, "vkGetRenderAreaGranularity")); GetRenderAreaGranularity =
reinterpret_cast<PFN_vkGetRenderAreaGranularity>(GetDeviceProcAddr(dev, "vkGetRenderAreaGranularity"));
CreateCommandPool = reinterpret_cast<PFN_vkCreateCommandPool>(GetDeviceProcAddr(dev, "vkCreateCommandPool")); CreateCommandPool = reinterpret_cast<PFN_vkCreateCommandPool>(GetDeviceProcAddr(dev, "vkCreateCommandPool"));
DestroyCommandPool = reinterpret_cast<PFN_vkDestroyCommandPool>(GetDeviceProcAddr(dev, "vkDestroyCommandPool")); DestroyCommandPool = reinterpret_cast<PFN_vkDestroyCommandPool>(GetDeviceProcAddr(dev, "vkDestroyCommandPool"));
ResetCommandPool = reinterpret_cast<PFN_vkResetCommandPool>(GetDeviceProcAddr(dev, "vkResetCommandPool")); ResetCommandPool = reinterpret_cast<PFN_vkResetCommandPool>(GetDeviceProcAddr(dev, "vkResetCommandPool"));
AllocateCommandBuffers = reinterpret_cast<PFN_vkAllocateCommandBuffers>(GetDeviceProcAddr(dev, "vkAllocateCommandBuffers")); AllocateCommandBuffers =
reinterpret_cast<PFN_vkAllocateCommandBuffers>(GetDeviceProcAddr(dev, "vkAllocateCommandBuffers"));
FreeCommandBuffers = reinterpret_cast<PFN_vkFreeCommandBuffers>(GetDeviceProcAddr(dev, "vkFreeCommandBuffers")); FreeCommandBuffers = reinterpret_cast<PFN_vkFreeCommandBuffers>(GetDeviceProcAddr(dev, "vkFreeCommandBuffers"));
BeginCommandBuffer = reinterpret_cast<PFN_vkBeginCommandBuffer>(GetDeviceProcAddr(dev, "vkBeginCommandBuffer")); BeginCommandBuffer = reinterpret_cast<PFN_vkBeginCommandBuffer>(GetDeviceProcAddr(dev, "vkBeginCommandBuffer"));
EndCommandBuffer = reinterpret_cast<PFN_vkEndCommandBuffer>(GetDeviceProcAddr(dev, "vkEndCommandBuffer")); EndCommandBuffer = reinterpret_cast<PFN_vkEndCommandBuffer>(GetDeviceProcAddr(dev, "vkEndCommandBuffer"));
@ -477,16 +584,21 @@ void init_dispatch_table_bottom(VkInstance instance, VkDevice dev)
CmdSetDepthBias = reinterpret_cast<PFN_vkCmdSetDepthBias>(GetDeviceProcAddr(dev, "vkCmdSetDepthBias")); CmdSetDepthBias = reinterpret_cast<PFN_vkCmdSetDepthBias>(GetDeviceProcAddr(dev, "vkCmdSetDepthBias"));
CmdSetBlendConstants = reinterpret_cast<PFN_vkCmdSetBlendConstants>(GetDeviceProcAddr(dev, "vkCmdSetBlendConstants")); CmdSetBlendConstants = reinterpret_cast<PFN_vkCmdSetBlendConstants>(GetDeviceProcAddr(dev, "vkCmdSetBlendConstants"));
CmdSetDepthBounds = reinterpret_cast<PFN_vkCmdSetDepthBounds>(GetDeviceProcAddr(dev, "vkCmdSetDepthBounds")); CmdSetDepthBounds = reinterpret_cast<PFN_vkCmdSetDepthBounds>(GetDeviceProcAddr(dev, "vkCmdSetDepthBounds"));
CmdSetStencilCompareMask = reinterpret_cast<PFN_vkCmdSetStencilCompareMask>(GetDeviceProcAddr(dev, "vkCmdSetStencilCompareMask")); CmdSetStencilCompareMask =
CmdSetStencilWriteMask = reinterpret_cast<PFN_vkCmdSetStencilWriteMask>(GetDeviceProcAddr(dev, "vkCmdSetStencilWriteMask")); reinterpret_cast<PFN_vkCmdSetStencilCompareMask>(GetDeviceProcAddr(dev, "vkCmdSetStencilCompareMask"));
CmdSetStencilReference = reinterpret_cast<PFN_vkCmdSetStencilReference>(GetDeviceProcAddr(dev, "vkCmdSetStencilReference")); CmdSetStencilWriteMask =
CmdBindDescriptorSets = reinterpret_cast<PFN_vkCmdBindDescriptorSets>(GetDeviceProcAddr(dev, "vkCmdBindDescriptorSets")); reinterpret_cast<PFN_vkCmdSetStencilWriteMask>(GetDeviceProcAddr(dev, "vkCmdSetStencilWriteMask"));
CmdSetStencilReference =
reinterpret_cast<PFN_vkCmdSetStencilReference>(GetDeviceProcAddr(dev, "vkCmdSetStencilReference"));
CmdBindDescriptorSets =
reinterpret_cast<PFN_vkCmdBindDescriptorSets>(GetDeviceProcAddr(dev, "vkCmdBindDescriptorSets"));
CmdBindIndexBuffer = reinterpret_cast<PFN_vkCmdBindIndexBuffer>(GetDeviceProcAddr(dev, "vkCmdBindIndexBuffer")); CmdBindIndexBuffer = reinterpret_cast<PFN_vkCmdBindIndexBuffer>(GetDeviceProcAddr(dev, "vkCmdBindIndexBuffer"));
CmdBindVertexBuffers = reinterpret_cast<PFN_vkCmdBindVertexBuffers>(GetDeviceProcAddr(dev, "vkCmdBindVertexBuffers")); CmdBindVertexBuffers = reinterpret_cast<PFN_vkCmdBindVertexBuffers>(GetDeviceProcAddr(dev, "vkCmdBindVertexBuffers"));
CmdDraw = reinterpret_cast<PFN_vkCmdDraw>(GetDeviceProcAddr(dev, "vkCmdDraw")); CmdDraw = reinterpret_cast<PFN_vkCmdDraw>(GetDeviceProcAddr(dev, "vkCmdDraw"));
CmdDrawIndexed = reinterpret_cast<PFN_vkCmdDrawIndexed>(GetDeviceProcAddr(dev, "vkCmdDrawIndexed")); CmdDrawIndexed = reinterpret_cast<PFN_vkCmdDrawIndexed>(GetDeviceProcAddr(dev, "vkCmdDrawIndexed"));
CmdDrawIndirect = reinterpret_cast<PFN_vkCmdDrawIndirect>(GetDeviceProcAddr(dev, "vkCmdDrawIndirect")); CmdDrawIndirect = reinterpret_cast<PFN_vkCmdDrawIndirect>(GetDeviceProcAddr(dev, "vkCmdDrawIndirect"));
CmdDrawIndexedIndirect = reinterpret_cast<PFN_vkCmdDrawIndexedIndirect>(GetDeviceProcAddr(dev, "vkCmdDrawIndexedIndirect")); CmdDrawIndexedIndirect =
reinterpret_cast<PFN_vkCmdDrawIndexedIndirect>(GetDeviceProcAddr(dev, "vkCmdDrawIndexedIndirect"));
CmdDispatch = reinterpret_cast<PFN_vkCmdDispatch>(GetDeviceProcAddr(dev, "vkCmdDispatch")); CmdDispatch = reinterpret_cast<PFN_vkCmdDispatch>(GetDeviceProcAddr(dev, "vkCmdDispatch"));
CmdDispatchIndirect = reinterpret_cast<PFN_vkCmdDispatchIndirect>(GetDeviceProcAddr(dev, "vkCmdDispatchIndirect")); CmdDispatchIndirect = reinterpret_cast<PFN_vkCmdDispatchIndirect>(GetDeviceProcAddr(dev, "vkCmdDispatchIndirect"));
CmdCopyBuffer = reinterpret_cast<PFN_vkCmdCopyBuffer>(GetDeviceProcAddr(dev, "vkCmdCopyBuffer")); CmdCopyBuffer = reinterpret_cast<PFN_vkCmdCopyBuffer>(GetDeviceProcAddr(dev, "vkCmdCopyBuffer"));
@ -497,7 +609,8 @@ void init_dispatch_table_bottom(VkInstance instance, VkDevice dev)
CmdUpdateBuffer = reinterpret_cast<PFN_vkCmdUpdateBuffer>(GetDeviceProcAddr(dev, "vkCmdUpdateBuffer")); CmdUpdateBuffer = reinterpret_cast<PFN_vkCmdUpdateBuffer>(GetDeviceProcAddr(dev, "vkCmdUpdateBuffer"));
CmdFillBuffer = reinterpret_cast<PFN_vkCmdFillBuffer>(GetDeviceProcAddr(dev, "vkCmdFillBuffer")); CmdFillBuffer = reinterpret_cast<PFN_vkCmdFillBuffer>(GetDeviceProcAddr(dev, "vkCmdFillBuffer"));
CmdClearColorImage = reinterpret_cast<PFN_vkCmdClearColorImage>(GetDeviceProcAddr(dev, "vkCmdClearColorImage")); CmdClearColorImage = reinterpret_cast<PFN_vkCmdClearColorImage>(GetDeviceProcAddr(dev, "vkCmdClearColorImage"));
CmdClearDepthStencilImage = reinterpret_cast<PFN_vkCmdClearDepthStencilImage>(GetDeviceProcAddr(dev, "vkCmdClearDepthStencilImage")); CmdClearDepthStencilImage =
reinterpret_cast<PFN_vkCmdClearDepthStencilImage>(GetDeviceProcAddr(dev, "vkCmdClearDepthStencilImage"));
CmdClearAttachments = reinterpret_cast<PFN_vkCmdClearAttachments>(GetDeviceProcAddr(dev, "vkCmdClearAttachments")); CmdClearAttachments = reinterpret_cast<PFN_vkCmdClearAttachments>(GetDeviceProcAddr(dev, "vkCmdClearAttachments"));
CmdResolveImage = reinterpret_cast<PFN_vkCmdResolveImage>(GetDeviceProcAddr(dev, "vkCmdResolveImage")); CmdResolveImage = reinterpret_cast<PFN_vkCmdResolveImage>(GetDeviceProcAddr(dev, "vkCmdResolveImage"));
CmdSetEvent = reinterpret_cast<PFN_vkCmdSetEvent>(GetDeviceProcAddr(dev, "vkCmdSetEvent")); CmdSetEvent = reinterpret_cast<PFN_vkCmdSetEvent>(GetDeviceProcAddr(dev, "vkCmdSetEvent"));
@ -508,7 +621,8 @@ void init_dispatch_table_bottom(VkInstance instance, VkDevice dev)
CmdEndQuery = reinterpret_cast<PFN_vkCmdEndQuery>(GetDeviceProcAddr(dev, "vkCmdEndQuery")); CmdEndQuery = reinterpret_cast<PFN_vkCmdEndQuery>(GetDeviceProcAddr(dev, "vkCmdEndQuery"));
CmdResetQueryPool = reinterpret_cast<PFN_vkCmdResetQueryPool>(GetDeviceProcAddr(dev, "vkCmdResetQueryPool")); CmdResetQueryPool = reinterpret_cast<PFN_vkCmdResetQueryPool>(GetDeviceProcAddr(dev, "vkCmdResetQueryPool"));
CmdWriteTimestamp = reinterpret_cast<PFN_vkCmdWriteTimestamp>(GetDeviceProcAddr(dev, "vkCmdWriteTimestamp")); CmdWriteTimestamp = reinterpret_cast<PFN_vkCmdWriteTimestamp>(GetDeviceProcAddr(dev, "vkCmdWriteTimestamp"));
CmdCopyQueryPoolResults = reinterpret_cast<PFN_vkCmdCopyQueryPoolResults>(GetDeviceProcAddr(dev, "vkCmdCopyQueryPoolResults")); CmdCopyQueryPoolResults =
reinterpret_cast<PFN_vkCmdCopyQueryPoolResults>(GetDeviceProcAddr(dev, "vkCmdCopyQueryPoolResults"));
CmdPushConstants = reinterpret_cast<PFN_vkCmdPushConstants>(GetDeviceProcAddr(dev, "vkCmdPushConstants")); CmdPushConstants = reinterpret_cast<PFN_vkCmdPushConstants>(GetDeviceProcAddr(dev, "vkCmdPushConstants"));
CmdBeginRenderPass = reinterpret_cast<PFN_vkCmdBeginRenderPass>(GetDeviceProcAddr(dev, "vkCmdBeginRenderPass")); CmdBeginRenderPass = reinterpret_cast<PFN_vkCmdBeginRenderPass>(GetDeviceProcAddr(dev, "vkCmdBeginRenderPass"));
CmdNextSubpass = reinterpret_cast<PFN_vkCmdNextSubpass>(GetDeviceProcAddr(dev, "vkCmdNextSubpass")); CmdNextSubpass = reinterpret_cast<PFN_vkCmdNextSubpass>(GetDeviceProcAddr(dev, "vkCmdNextSubpass"));
@ -516,10 +630,12 @@ void init_dispatch_table_bottom(VkInstance instance, VkDevice dev)
CmdExecuteCommands = reinterpret_cast<PFN_vkCmdExecuteCommands>(GetDeviceProcAddr(dev, "vkCmdExecuteCommands")); CmdExecuteCommands = reinterpret_cast<PFN_vkCmdExecuteCommands>(GetDeviceProcAddr(dev, "vkCmdExecuteCommands"));
CreateSwapchainKHR = reinterpret_cast<PFN_vkCreateSwapchainKHR>(GetDeviceProcAddr(dev, "vkCreateSwapchainKHR")); CreateSwapchainKHR = reinterpret_cast<PFN_vkCreateSwapchainKHR>(GetDeviceProcAddr(dev, "vkCreateSwapchainKHR"));
DestroySwapchainKHR = reinterpret_cast<PFN_vkDestroySwapchainKHR>(GetDeviceProcAddr(dev, "vkDestroySwapchainKHR")); DestroySwapchainKHR = reinterpret_cast<PFN_vkDestroySwapchainKHR>(GetDeviceProcAddr(dev, "vkDestroySwapchainKHR"));
GetSwapchainImagesKHR = reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(GetDeviceProcAddr(dev, "vkGetSwapchainImagesKHR")); GetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(GetDeviceProcAddr(dev, "vkGetSwapchainImagesKHR"));
AcquireNextImageKHR = reinterpret_cast<PFN_vkAcquireNextImageKHR>(GetDeviceProcAddr(dev, "vkAcquireNextImageKHR")); AcquireNextImageKHR = reinterpret_cast<PFN_vkAcquireNextImageKHR>(GetDeviceProcAddr(dev, "vkAcquireNextImageKHR"));
QueuePresentKHR = reinterpret_cast<PFN_vkQueuePresentKHR>(GetDeviceProcAddr(dev, "vkQueuePresentKHR")); QueuePresentKHR = reinterpret_cast<PFN_vkQueuePresentKHR>(GetDeviceProcAddr(dev, "vkQueuePresentKHR"));
CreateSharedSwapchainsKHR = reinterpret_cast<PFN_vkCreateSharedSwapchainsKHR>(GetDeviceProcAddr(dev, "vkCreateSharedSwapchainsKHR")); CreateSharedSwapchainsKHR =
reinterpret_cast<PFN_vkCreateSharedSwapchainsKHR>(GetDeviceProcAddr(dev, "vkCreateSharedSwapchainsKHR"));
} }
} // namespace vk } // namespace vk

File diff suppressed because it is too large Load Diff

View File

@ -55,50 +55,23 @@ extern "C" {
_GLAPI_EXPORT __thread void* _glapi_tls_Context; _GLAPI_EXPORT __thread void* _glapi_tls_Context;
_GLAPI_EXPORT __thread struct _glapi_table* _glapi_tls_Dispatch; _GLAPI_EXPORT __thread struct _glapi_table* _glapi_tls_Dispatch;
int int _glapi_add_dispatch(const char* const* function_names, const char* parameter_signature) { return 0; }
_glapi_add_dispatch( const char * const * function_names,
const char * parameter_signature )
{
return 0;
}
void void _glapi_destroy_multithread(void) {}
_glapi_destroy_multithread(void)
{
}
void void _glapi_check_multithread(void) {}
_glapi_check_multithread(void)
{
}
void void _glapi_set_context(void* context) { _glapi_tls_Context = context; }
_glapi_set_context(void *context)
{
_glapi_tls_Context = context;
}
void * void* _glapi_get_context() { return _glapi_tls_Context; }
_glapi_get_context()
{
return _glapi_tls_Context;
}
void void _glapi_set_dispatch(struct _glapi_table* dispatch) { _glapi_tls_Dispatch = dispatch; }
_glapi_set_dispatch(struct _glapi_table *dispatch)
{
_glapi_tls_Dispatch = dispatch;
}
struct _glapi_table * struct _glapi_table* _glapi_get_dispatch() {
_glapi_get_dispatch()
{
return _glapi_tls_Dispatch; return _glapi_tls_Dispatch;
} }
GLuint GLuint _glapi_get_dispatch_table_size(void) {
_glapi_get_dispatch_table_size(void)
{
/* /*
* The dispatch table size (number of entries) is the size of the * The dispatch table size (number of entries) is the size of the
* _glapi_table struct plus the number of dynamic entries we can add. * _glapi_table struct plus the number of dynamic entries we can add.
@ -110,20 +83,11 @@ _glapi_get_dispatch_table_size(void)
class dead_variable_visitor : public ir_hierarchical_visitor { class dead_variable_visitor : public ir_hierarchical_visitor {
public: public:
dead_variable_visitor() dead_variable_visitor() { variables = _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal); }
{
variables = _mesa_set_create(NULL,
_mesa_hash_pointer,
_mesa_key_pointer_equal);
}
virtual ~dead_variable_visitor() virtual ~dead_variable_visitor() { _mesa_set_destroy(variables, NULL); }
{
_mesa_set_destroy(variables, NULL);
}
virtual ir_visitor_status visit(ir_variable *ir) virtual ir_visitor_status visit(ir_variable* ir) {
{
/* If the variable is auto or temp, add it to the set of variables that /* If the variable is auto or temp, add it to the set of variables that
* are candidates for removal. * are candidates for removal.
*/ */
@ -135,8 +99,7 @@ public:
return visit_continue; return visit_continue;
} }
virtual ir_visitor_status visit(ir_dereference_variable *ir) virtual ir_visitor_status visit(ir_dereference_variable* ir) {
{
struct set_entry* entry = _mesa_set_search(variables, ir->var); struct set_entry* entry = _mesa_set_search(variables, ir->var);
/* If a variable is dereferenced at all, remove it from the set of /* If a variable is dereferenced at all, remove it from the set of
@ -148,8 +111,7 @@ public:
return visit_continue; return visit_continue;
} }
void remove_dead_variables() void remove_dead_variables() {
{
struct set_entry* entry; struct set_entry* entry;
set_foreach(variables, entry) { set_foreach(variables, entry) {
@ -164,13 +126,10 @@ private:
set* variables; set* variables;
}; };
void nx_compiler::compile_shader(struct gl_context *ctx, struct gl_shader *shader) void nx_compiler::compile_shader(struct gl_context* ctx, struct gl_shader* shader) {
{ struct _mesa_glsl_parse_state* state = new (shader) _mesa_glsl_parse_state(ctx, shader->Stage, shader);
struct _mesa_glsl_parse_state *state =
new(shader) _mesa_glsl_parse_state(ctx, shader->Stage, shader);
_mesa_glsl_compile_shader(ctx, shader, m_options.dump_ast, _mesa_glsl_compile_shader(ctx, shader, m_options.dump_ast, m_options.dump_hir, true);
m_options.dump_hir, true);
/* Print out the resulting IR */ /* Print out the resulting IR */
if (!state->error && m_options.dump_lir) { if (!state->error && m_options.dump_lir) {
@ -178,16 +137,13 @@ void nx_compiler::compile_shader(struct gl_context *ctx, struct gl_shader *shade
} }
} }
nx_compiler::nx_compiler() nx_compiler::nx_compiler() {
{
m_options.glsl_version = 330; m_options.glsl_version = 330;
m_options.do_link = true; m_options.do_link = true;
} }
nx_compiler::~nx_compiler() nx_compiler::~nx_compiler() {
{ if (m_ownsCtx) {
if (m_ownsCtx)
{
_mesa_glsl_release_types(); _mesa_glsl_release_types();
_mesa_glsl_release_builtin_functions(); _mesa_glsl_release_builtin_functions();
if (m_st) if (m_st)
@ -197,9 +153,7 @@ nx_compiler::~nx_compiler()
} }
} }
bool nx_compiler::initialize(struct pipe_screen *screen, struct st_context *st, bool nx_compiler::initialize(struct pipe_screen* screen, struct st_context* st, const struct standalone_options* o) {
const struct standalone_options *o)
{
m_screen = screen; m_screen = screen;
m_st = st; m_st = st;
if (o) if (o)
@ -207,8 +161,7 @@ bool nx_compiler::initialize(struct pipe_screen *screen, struct st_context *st,
return true; return true;
} }
bool nx_compiler::initialize(const struct standalone_options* o) bool nx_compiler::initialize(const struct standalone_options* o) {
{
m_ownsCtx = true; m_ownsCtx = true;
bool glsl_es; bool glsl_es;
@ -289,16 +242,14 @@ bool nx_compiler::initialize(const struct standalone_options* o)
return false; return false;
screen->refcount = 1; screen->refcount = 1;
struct pipe_context* p_ctx = screen->base.context_create(&screen->base, nullptr, 0); struct pipe_context* p_ctx = screen->base.context_create(&screen->base, nullptr, 0);
if (!p_ctx) if (!p_ctx) {
{
screen->base.destroy(&screen->base); screen->base.destroy(&screen->base);
return false; return false;
} }
st_config_options opts = {}; st_config_options opts = {};
struct st_context* st = st_create_context(use_api, p_ctx, nullptr, nullptr, &opts, false); struct st_context* st = st_create_context(use_api, p_ctx, nullptr, nullptr, &opts, false);
if (!st) if (!st) {
{
screen->base.destroy(&screen->base); screen->base.destroy(&screen->base);
return false; return false;
} }
@ -306,17 +257,14 @@ bool nx_compiler::initialize(const struct standalone_options* o)
return initialize(&screen->base, st); return initialize(&screen->base, st);
} }
nx_shader_stage_object::nx_shader_stage_object(const nx_shader_stage_object& other) nx_shader_stage_object::nx_shader_stage_object(const nx_shader_stage_object& other) : m_parent(other.m_parent) {
: m_parent(other.m_parent)
{
if (!other.m_shader || !m_parent) if (!other.m_shader || !m_parent)
return; return;
struct gl_context* ctx = m_parent->m_st->ctx; struct gl_context* ctx = m_parent->m_st->ctx;
_mesa_reference_shader(ctx, &m_shader, other.m_shader); _mesa_reference_shader(ctx, &m_shader, other.m_shader);
} }
nx_shader_stage_object& nx_shader_stage_object::operator=(const nx_shader_stage_object& other) nx_shader_stage_object& nx_shader_stage_object::operator=(const nx_shader_stage_object& other) {
{
m_parent = other.m_parent; m_parent = other.m_parent;
if (!other.m_shader || !m_parent) if (!other.m_shader || !m_parent)
return *this; return *this;
@ -325,44 +273,35 @@ nx_shader_stage_object& nx_shader_stage_object::operator=(const nx_shader_stage_
return *this; return *this;
} }
void nx_shader_stage_object::reset() void nx_shader_stage_object::reset() {
{
if (!m_shader || !m_parent) if (!m_shader || !m_parent)
return; return;
struct gl_context* ctx = m_parent->m_st->ctx; struct gl_context* ctx = m_parent->m_st->ctx;
_mesa_reference_shader(ctx, &m_shader, nullptr); _mesa_reference_shader(ctx, &m_shader, nullptr);
} }
nx_shader_stage_object::operator bool() const nx_shader_stage_object::operator bool() const {
{
if (!m_shader) if (!m_shader)
return false; return false;
return m_shader->CompileStatus; return m_shader->CompileStatus;
} }
nx_shader_stage nx_shader_stage_object::stage() const nx_shader_stage nx_shader_stage_object::stage() const { return nx_shader_stage(m_shader->Stage); }
{
return nx_shader_stage(m_shader->Stage);
}
const char* nx_shader_stage_object::info_log() const const char* nx_shader_stage_object::info_log() const {
{
if (!m_shader) if (!m_shader)
return nullptr; return nullptr;
return m_shader->InfoLog; return m_shader->InfoLog;
} }
nx_linked_shader::nx_linked_shader(const nx_linked_shader& other) nx_linked_shader::nx_linked_shader(const nx_linked_shader& other) : m_parent(other.m_parent) {
: m_parent(other.m_parent)
{
if (!other.m_program || !m_parent) if (!other.m_program || !m_parent)
return; return;
struct gl_context* ctx = m_parent->m_st->ctx; struct gl_context* ctx = m_parent->m_st->ctx;
_mesa_reference_shader_program(ctx, &m_program, other.m_program); _mesa_reference_shader_program(ctx, &m_program, other.m_program);
} }
nx_linked_shader& nx_linked_shader::operator=(const nx_linked_shader& other) nx_linked_shader& nx_linked_shader::operator=(const nx_linked_shader& other) {
{
m_parent = other.m_parent; m_parent = other.m_parent;
if (!other.m_program || !m_parent) if (!other.m_program || !m_parent)
return *this; return *this;
@ -371,16 +310,14 @@ nx_linked_shader& nx_linked_shader::operator=(const nx_linked_shader& other)
return *this; return *this;
} }
void nx_linked_shader::reset() void nx_linked_shader::reset() {
{
if (!m_program || !m_parent) if (!m_program || !m_parent)
return; return;
struct gl_context* ctx = m_parent->m_st->ctx; struct gl_context* ctx = m_parent->m_st->ctx;
_mesa_reference_shader_program(ctx, &m_program, nullptr); _mesa_reference_shader_program(ctx, &m_program, nullptr);
} }
nx_shader_stage_object nx_compiler::compile(nx_shader_stage type, const char *source) nx_shader_stage_object nx_compiler::compile(nx_shader_stage type, const char* source) {
{
struct gl_context* ctx = m_st->ctx; struct gl_context* ctx = m_st->ctx;
nx_shader_stage_object ret(*this); nx_shader_stage_object ret(*this);
@ -399,8 +336,7 @@ nx_shader_stage_object nx_compiler::compile(nx_shader_stage type, const char *so
return ret; return ret;
} }
nx_linked_shader nx_compiler::link(unsigned num_stages, const nx_shader_stage_object **stages, std::string* infoLog) nx_linked_shader nx_compiler::link(unsigned num_stages, const nx_shader_stage_object** stages, std::string* infoLog) {
{
nx_linked_shader ret(*this); nx_linked_shader ret(*this);
int status = EXIT_SUCCESS; int status = EXIT_SUCCESS;
struct gl_context* ctx = m_st->ctx; struct gl_context* ctx = m_st->ctx;
@ -444,12 +380,7 @@ nx_linked_shader nx_compiler::link(unsigned num_stages, const nx_shader_stage_ob
whole_program->data->LinkStatus = LINKING_SUCCESS; whole_program->data->LinkStatus = LINKING_SUCCESS;
whole_program->_LinkedShaders[stage] = whole_program->_LinkedShaders[stage] =
link_intrastage_shaders(whole_program /* mem_ctx */, link_intrastage_shaders(whole_program /* mem_ctx */, ctx, whole_program, whole_program->Shaders, 1, true);
ctx,
whole_program,
whole_program->Shaders,
1,
true);
whole_program->_LinkedShaders[stage]->Program->Target = _mesa_shader_stage_to_program(stage); whole_program->_LinkedShaders[stage]->Program->Target = _mesa_shader_stage_to_program(stage);
/* Par-linking can fail, for example, if there are undefined external /* Par-linking can fail, for example, if there are undefined external
@ -458,22 +389,15 @@ nx_linked_shader nx_compiler::link(unsigned num_stages, const nx_shader_stage_ob
if (whole_program->_LinkedShaders[stage] != NULL) { if (whole_program->_LinkedShaders[stage] != NULL) {
assert(whole_program->data->LinkStatus); assert(whole_program->data->LinkStatus);
struct gl_shader_compiler_options *const compiler_options = struct gl_shader_compiler_options* const compiler_options = &ctx->Const.ShaderCompilerOptions[stage];
&ctx->Const.ShaderCompilerOptions[stage];
exec_list *const ir = exec_list* const ir = whole_program->_LinkedShaders[stage]->ir;
whole_program->_LinkedShaders[stage]->ir;
bool progress; bool progress;
do { do {
progress = do_function_inlining(ir); progress = do_function_inlining(ir);
progress = do_common_optimization(ir, progress = do_common_optimization(ir, false, false, compiler_options, true) && progress;
false,
false,
compiler_options,
true)
&& progress;
} while (progress); } while (progress);
} }
} }
@ -519,23 +443,18 @@ nx_linked_shader nx_compiler::link(unsigned num_stages, const nx_shader_stage_ob
return nx_linked_shader(*this); return nx_linked_shader(*this);
} }
static void static void SizeProgramBuffer(const nvc0_program* prog, size_t& sz) {
SizeProgramBuffer(const nvc0_program *prog, size_t &sz)
{
sz += 140; sz += 140;
sz += prog->code_size; sz += prog->code_size;
} }
template<class T> static void template <class T>
OutputField(T f, uint8_t *&ptr) static void OutputField(T f, uint8_t*& ptr) {
{
memcpy(ptr, &f, sizeof(f)); memcpy(ptr, &f, sizeof(f));
ptr += sizeof(f); ptr += sizeof(f);
} }
static void static void BuildProgramBuffer(const nvc0_program* prog, uint8_t*& ptr) {
BuildProgramBuffer(const nvc0_program *prog, uint8_t *&ptr)
{
OutputField(prog->type, ptr); OutputField(prog->type, ptr);
OutputField(prog->translated, ptr); OutputField(prog->translated, ptr);
OutputField(prog->need_tls, ptr); OutputField(prog->need_tls, ptr);
@ -572,9 +491,9 @@ BuildProgramBuffer(const nvc0_program *prog, uint8_t *&ptr)
ptr += prog->code_size; ptr += prog->code_size;
} }
std::pair<std::shared_ptr<uint8_t[]>, size_t> std::pair<std::shared_ptr<uint8_t[]>, size_t> nx_compiler::offline_link(unsigned num_stages,
nx_compiler::offline_link(unsigned num_stages, const nx_shader_stage_object **stages, std::string *infoLog) const nx_shader_stage_object** stages,
{ std::string* infoLog) {
std::pair<std::shared_ptr<uint8_t[]>, size_t> ret = {}; std::pair<std::shared_ptr<uint8_t[]>, size_t> ret = {};
auto whole_program = link(num_stages, stages, infoLog); auto whole_program = link(num_stages, stages, infoLog);
if (!whole_program) if (!whole_program)

View File

@ -1,13 +1,10 @@
#include "boo/graphicsdev/nx_compiler.hpp" #include "boo/graphicsdev/nx_compiler.hpp"
int main(int argc, char** argv) int main(int argc, char** argv) {
{
nx_compiler c; nx_compiler c;
c.initialize(); c.initialize();
nx_shader_stage_object objs[] = nx_shader_stage_object objs[] = {c.compile(nx_shader_stage::VERTEX,
{
c.compile(nx_shader_stage::VERTEX,
"#version 330\n" "#version 330\n"
"#extension GL_ARB_separate_shader_objects: enable\n" "#extension GL_ARB_separate_shader_objects: enable\n"
"#extension GL_ARB_shading_language_420pack: enable\n" "#extension GL_ARB_shading_language_420pack: enable\n"
@ -30,8 +27,7 @@ int main(int argc, char** argv)
"void main()\n" "void main()\n"
"{\n" "{\n"
" out_frag = texture(texs[0], out_uv) + texture(texs[1], out_uv);\n" " out_frag = texture(texs[0], out_uv) + texture(texs[1], out_uv);\n"
"}") "}")};
};
std::string log; std::string log;
auto linkData = c.link(2, objs, &log); auto linkData = c.link(2, objs, &log);

View File

@ -3,76 +3,62 @@
#include "IHIDDevice.hpp" #include "IHIDDevice.hpp"
#include <cstdarg> #include <cstdarg>
namespace boo namespace boo {
{
DeviceBase::DeviceBase(uint64_t typeHash, DeviceToken* token) DeviceBase::DeviceBase(uint64_t typeHash, DeviceToken* token) : m_typeHash(typeHash), m_token(token) {}
: m_typeHash(typeHash), m_token(token)
{
}
void DeviceBase::_deviceDisconnected() void DeviceBase::_deviceDisconnected() {
{
deviceDisconnected(); deviceDisconnected();
m_token = nullptr; m_token = nullptr;
if (m_hidDev) if (m_hidDev) {
{
m_hidDev->_deviceDisconnected(); m_hidDev->_deviceDisconnected();
m_hidDev.reset(); m_hidDev.reset();
} }
} }
void DeviceBase::closeDevice() void DeviceBase::closeDevice() {
{
if (m_token) if (m_token)
m_token->_deviceClose(); m_token->_deviceClose();
} }
void DeviceBase::deviceError(const char* error, ...) void DeviceBase::deviceError(const char* error, ...) {
{
va_list vl; va_list vl;
va_start(vl, error); va_start(vl, error);
vfprintf(stderr, error, vl); vfprintf(stderr, error, vl);
va_end(vl); va_end(vl);
} }
bool DeviceBase::sendUSBInterruptTransfer(const uint8_t* data, size_t length) bool DeviceBase::sendUSBInterruptTransfer(const uint8_t* data, size_t length) {
{
if (m_hidDev) if (m_hidDev)
return m_hidDev->_sendUSBInterruptTransfer(data, length); return m_hidDev->_sendUSBInterruptTransfer(data, length);
return false; return false;
} }
size_t DeviceBase::receiveUSBInterruptTransfer(uint8_t* data, size_t length) size_t DeviceBase::receiveUSBInterruptTransfer(uint8_t* data, size_t length) {
{
if (m_hidDev) if (m_hidDev)
return m_hidDev->_receiveUSBInterruptTransfer(data, length); return m_hidDev->_receiveUSBInterruptTransfer(data, length);
return false; return false;
} }
unsigned DeviceBase::getVendorId() unsigned DeviceBase::getVendorId() {
{
if (m_token) if (m_token)
return m_token->getVendorId(); return m_token->getVendorId();
return -1; return -1;
} }
unsigned DeviceBase::getProductId() unsigned DeviceBase::getProductId() {
{
if (m_token) if (m_token)
return m_token->getProductId(); return m_token->getProductId();
return -1; return -1;
} }
std::string_view DeviceBase::getVendorName() std::string_view DeviceBase::getVendorName() {
{
if (m_token) if (m_token)
return m_token->getVendorName(); return m_token->getVendorName();
return {}; return {};
} }
std::string_view DeviceBase::getProductName() std::string_view DeviceBase::getProductName() {
{
if (m_token) if (m_token)
return m_token->getProductName(); return m_token->getProductName();
return {}; return {};
@ -80,34 +66,30 @@ std::string_view DeviceBase::getProductName()
#if _WIN32 #if _WIN32
#if !WINDOWS_STORE #if !WINDOWS_STORE
const PHIDP_PREPARSED_DATA DeviceBase::getReportDescriptor() const PHIDP_PREPARSED_DATA DeviceBase::getReportDescriptor() {
{
if (m_hidDev) if (m_hidDev)
return m_hidDev->_getReportDescriptor(); return m_hidDev->_getReportDescriptor();
return {}; return {};
} }
#endif #endif
#else #else
std::vector<uint8_t> DeviceBase::getReportDescriptor() std::vector<uint8_t> DeviceBase::getReportDescriptor() {
{
if (m_hidDev) if (m_hidDev)
return m_hidDev->_getReportDescriptor(); return m_hidDev->_getReportDescriptor();
return {}; return {};
} }
#endif #endif
bool DeviceBase::sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) bool DeviceBase::sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
{
if (m_hidDev) if (m_hidDev)
return m_hidDev->_sendHIDReport(data, length, tp, message); return m_hidDev->_sendHIDReport(data, length, tp, message);
return false; return false;
} }
size_t DeviceBase::receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) size_t DeviceBase::receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
{
if (m_hidDev) if (m_hidDev)
return m_hidDev->_receiveHIDReport(data, length, tp, message); return m_hidDev->_receiveHIDReport(data, length, tp, message);
return 0; return 0;
} }
} } // namespace boo

View File

@ -6,33 +6,28 @@
#include <usbiodef.h> #include <usbiodef.h>
#endif #endif
namespace boo namespace boo {
{
DeviceFinder* DeviceFinder::skDevFinder = nullptr; DeviceFinder* DeviceFinder::skDevFinder = nullptr;
#if _WIN32 && !WINDOWS_STORE #if _WIN32 && !WINDOWS_STORE
/* Windows-specific WM_DEVICECHANGED handler */ /* Windows-specific WM_DEVICECHANGED handler */
LRESULT DeviceFinder::winDevChangedHandler(WPARAM wParam, LPARAM lParam) LRESULT DeviceFinder::winDevChangedHandler(WPARAM wParam, LPARAM lParam) {
{
PDEV_BROADCAST_HDR dbh = (PDEV_BROADCAST_HDR)lParam; PDEV_BROADCAST_HDR dbh = (PDEV_BROADCAST_HDR)lParam;
PDEV_BROADCAST_DEVICEINTERFACE dbhi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam; PDEV_BROADCAST_DEVICEINTERFACE dbhi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
DeviceFinder* finder = instance(); DeviceFinder* finder = instance();
if (!finder) if (!finder)
return 0; return 0;
if (wParam == DBT_DEVICEARRIVAL) if (wParam == DBT_DEVICEARRIVAL) {
{ if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
DeviceType type = DeviceType::None; DeviceType type = DeviceType::None;
if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_USB_DEVICE) if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_USB_DEVICE)
type = DeviceType::USB; type = DeviceType::USB;
else if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_HID) else if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_HID)
type = DeviceType::HID; type = DeviceType::HID;
if (type != DeviceType::None) if (type != DeviceType::None) {
{
#ifdef UNICODE #ifdef UNICODE
char devPath[1024]; char devPath[1024];
wcstombs(devPath, dbhi->dbcc_name, 1024); wcstombs(devPath, dbhi->dbcc_name, 1024);
@ -42,19 +37,15 @@ LRESULT DeviceFinder::winDevChangedHandler(WPARAM wParam, LPARAM lParam)
#endif #endif
} }
} }
} } else if (wParam == DBT_DEVICEREMOVECOMPLETE) {
else if (wParam == DBT_DEVICEREMOVECOMPLETE) if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
{
if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
DeviceType type = DeviceType::None; DeviceType type = DeviceType::None;
if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_USB_DEVICE) if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_USB_DEVICE)
type = DeviceType::USB; type = DeviceType::USB;
else if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_HID) else if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_HID)
type = DeviceType::HID; type = DeviceType::HID;
if (type != DeviceType::None) if (type != DeviceType::None) {
{
#ifdef UNICODE #ifdef UNICODE
char devPath[1024]; char devPath[1024];
wcstombs(devPath, dbhi->dbcc_name, 1024); wcstombs(devPath, dbhi->dbcc_name, 1024);
@ -70,4 +61,4 @@ LRESULT DeviceFinder::winDevChangedHandler(WPARAM wParam, LPARAM lParam)
} }
#endif #endif
} } // namespace boo

View File

@ -3,30 +3,23 @@
#include "boo/inputdev/GenericPad.hpp" #include "boo/inputdev/GenericPad.hpp"
#include "IHIDDevice.hpp" #include "IHIDDevice.hpp"
namespace boo namespace boo {
{
extern const DeviceSignature BOO_DEVICE_SIGS[]; extern const DeviceSignature BOO_DEVICE_SIGS[];
bool DeviceSignature::DeviceMatchToken(const DeviceToken& token, const TDeviceSignatureSet& sigSet) {
bool DeviceSignature::DeviceMatchToken(const DeviceToken& token, const TDeviceSignatureSet& sigSet) if (token.getDeviceType() == DeviceType::HID) {
{
if (token.getDeviceType() == DeviceType::HID)
{
uint64_t genPadHash = dev_typeid(GenericPad); uint64_t genPadHash = dev_typeid(GenericPad);
bool hasGenericPad = false; bool hasGenericPad = false;
for (const DeviceSignature* sig : sigSet) for (const DeviceSignature* sig : sigSet) {
{ if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId() && sig->m_type != DeviceType::HID)
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId() &&
sig->m_type != DeviceType::HID)
return false; return false;
if (sig->m_typeHash == genPadHash) if (sig->m_typeHash == genPadHash)
hasGenericPad = true; hasGenericPad = true;
} }
return hasGenericPad; return hasGenericPad;
} }
for (const DeviceSignature* sig : sigSet) for (const DeviceSignature* sig : sigSet) {
{
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId()) if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId())
return true; return true;
} }
@ -34,8 +27,7 @@ bool DeviceSignature::DeviceMatchToken(const DeviceToken& token, const TDeviceSi
} }
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp); std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp);
std::shared_ptr<DeviceBase> DeviceSignature::DeviceNew(DeviceToken& token) std::shared_ptr<DeviceBase> DeviceSignature::DeviceNew(DeviceToken& token) {
{
std::shared_ptr<DeviceBase> retval; std::shared_ptr<DeviceBase> retval;
/* Perform signature-matching to find the appropriate device-factory */ /* Perform signature-matching to find the appropriate device-factory */
@ -43,20 +35,16 @@ std::shared_ptr<DeviceBase> DeviceSignature::DeviceNew(DeviceToken& token)
const DeviceSignature* sigIter = BOO_DEVICE_SIGS; const DeviceSignature* sigIter = BOO_DEVICE_SIGS;
unsigned targetVid = token.getVendorId(); unsigned targetVid = token.getVendorId();
unsigned targetPid = token.getProductId(); unsigned targetPid = token.getProductId();
while (sigIter->m_name) while (sigIter->m_name) {
{ if (sigIter->m_vid == targetVid && sigIter->m_pid == targetPid) {
if (sigIter->m_vid == targetVid && sigIter->m_pid == targetPid)
{
foundSig = sigIter; foundSig = sigIter;
break; break;
} }
++sigIter; ++sigIter;
} }
if (!foundSig) if (!foundSig) {
{
/* Try Generic HID devices */ /* Try Generic HID devices */
if (token.getDeviceType() == DeviceType::HID) if (token.getDeviceType() == DeviceType::HID) {
{
retval = std::make_shared<GenericPad>(&token); retval = std::make_shared<GenericPad>(&token);
if (!retval) if (!retval)
return nullptr; return nullptr;
@ -86,4 +74,4 @@ std::shared_ptr<DeviceBase> DeviceSignature::DeviceNew(DeviceToken& token)
return retval; return retval;
} }
} } // namespace boo

View File

@ -3,8 +3,7 @@
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
namespace boo namespace boo {
{
/* /*
* Reference: https://github.com/ToadKing/wii-u-gc-adapter/blob/master/wii-u-gc-adapter.c * Reference: https://github.com/ToadKing/wii-u-gc-adapter/blob/master/wii-u-gc-adapter.c
*/ */
@ -14,12 +13,10 @@ DolphinSmashAdapter::DolphinSmashAdapter(DeviceToken* token)
DolphinSmashAdapter::~DolphinSmashAdapter() {} DolphinSmashAdapter::~DolphinSmashAdapter() {}
static inline EDolphinControllerType parseType(unsigned char status) static inline EDolphinControllerType parseType(unsigned char status) {
{
EDolphinControllerType type = EDolphinControllerType type =
EDolphinControllerType(status) & (EDolphinControllerType::Normal | EDolphinControllerType::Wavebird); EDolphinControllerType(status) & (EDolphinControllerType::Normal | EDolphinControllerType::Wavebird);
switch (type) switch (type) {
{
case EDolphinControllerType::Normal: case EDolphinControllerType::Normal:
case EDolphinControllerType::Wavebird: case EDolphinControllerType::Wavebird:
return type; return type;
@ -28,8 +25,7 @@ static inline EDolphinControllerType parseType(unsigned char status)
} }
} }
static inline EDolphinControllerType parseState(DolphinControllerState* stateOut, uint8_t* payload, bool& rumble) static inline EDolphinControllerType parseState(DolphinControllerState* stateOut, uint8_t* payload, bool& rumble) {
{
memset(stateOut, 0, sizeof(DolphinControllerState)); memset(stateOut, 0, sizeof(DolphinControllerState));
unsigned char status = payload[0]; unsigned char status = payload[0];
EDolphinControllerType type = parseType(status); EDolphinControllerType type = parseType(status);
@ -48,14 +44,12 @@ static inline EDolphinControllerType parseState(DolphinControllerState* stateOut
return type; return type;
} }
void DolphinSmashAdapter::initialCycle() void DolphinSmashAdapter::initialCycle() {
{
uint8_t handshakePayload[] = {0x13}; uint8_t handshakePayload[] = {0x13};
sendUSBInterruptTransfer(handshakePayload, sizeof(handshakePayload)); sendUSBInterruptTransfer(handshakePayload, sizeof(handshakePayload));
} }
void DolphinSmashAdapter::transferCycle() void DolphinSmashAdapter::transferCycle() {
{
uint8_t payload[37]; uint8_t payload[37];
size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload)); size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload));
if (recvSz != 37 || payload[0] != 0x21) if (recvSz != 37 || payload[0] != 0x21)
@ -70,13 +64,11 @@ void DolphinSmashAdapter::transferCycle()
/* Parse controller states */ /* Parse controller states */
uint8_t* controller = &payload[1]; uint8_t* controller = &payload[1];
uint8_t rumbleMask = 0; uint8_t rumbleMask = 0;
for (uint32_t i = 0; i < 4; i++, controller += 9) for (uint32_t i = 0; i < 4; i++, controller += 9) {
{
DolphinControllerState state; DolphinControllerState state;
bool rumble = false; bool rumble = false;
EDolphinControllerType type = parseState(&state, controller, rumble); EDolphinControllerType type = parseState(&state, controller, rumble);
if (type != EDolphinControllerType::None && !(m_knownControllers & 1 << i)) if (type != EDolphinControllerType::None && !(m_knownControllers & 1 << i)) {
{
m_leftStickCal[0] = state.m_leftStick[0]; m_leftStickCal[0] = state.m_leftStick[0];
m_leftStickCal[1] = state.m_leftStick[1]; m_leftStickCal[1] = state.m_leftStick[1];
m_rightStickCal[0] = state.m_rightStick[0]; m_rightStickCal[0] = state.m_rightStick[0];
@ -85,14 +77,11 @@ void DolphinSmashAdapter::transferCycle()
m_triggersCal[1] = state.m_analogTriggers[1]; m_triggersCal[1] = state.m_analogTriggers[1];
m_knownControllers |= 1 << i; m_knownControllers |= 1 << i;
m_callback->controllerConnected(i, type); m_callback->controllerConnected(i, type);
} } else if (type == EDolphinControllerType::None && (m_knownControllers & 1 << i)) {
else if (type == EDolphinControllerType::None && (m_knownControllers & 1 << i))
{
m_knownControllers &= ~(1 << i); m_knownControllers &= ~(1 << i);
m_callback->controllerDisconnected(i); m_callback->controllerDisconnected(i);
} }
if (m_knownControllers & 1 << i) if (m_knownControllers & 1 << i) {
{
state.m_leftStick[0] = state.m_leftStick[0] - m_leftStickCal[0]; state.m_leftStick[0] = state.m_leftStick[0] - m_leftStickCal[0];
state.m_leftStick[1] = state.m_leftStick[1] - m_leftStickCal[1]; state.m_leftStick[1] = state.m_leftStick[1] - m_leftStickCal[1];
state.m_rightStick[0] = state.m_rightStick[0] - m_rightStickCal[0]; state.m_rightStick[0] = state.m_rightStick[0] - m_rightStickCal[0];
@ -106,11 +95,9 @@ void DolphinSmashAdapter::transferCycle()
/* Send rumble message (if needed) */ /* Send rumble message (if needed) */
uint8_t rumbleReq = m_rumbleRequest & rumbleMask; uint8_t rumbleReq = m_rumbleRequest & rumbleMask;
if (rumbleReq != m_rumbleState) if (rumbleReq != m_rumbleState) {
{
uint8_t rumbleMessage[5] = {0x11}; uint8_t rumbleMessage[5] = {0x11};
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i) {
{
if (rumbleReq & 1 << i) if (rumbleReq & 1 << i)
rumbleMessage[i + 1] = 1; rumbleMessage[i + 1] = 1;
else if (m_hardStop[i]) else if (m_hardStop[i])
@ -124,18 +111,14 @@ void DolphinSmashAdapter::transferCycle()
} }
} }
void DolphinSmashAdapter::finalCycle() void DolphinSmashAdapter::finalCycle() {
{
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0}; uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage)); sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage));
} }
void DolphinSmashAdapter::deviceDisconnected() void DolphinSmashAdapter::deviceDisconnected() {
{ for (uint32_t i = 0; i < 4; i++) {
for (uint32_t i = 0; i < 4; i++) if (m_knownControllers & 1 << i) {
{
if (m_knownControllers & 1 << i)
{
m_knownControllers &= ~(1 << i); m_knownControllers &= ~(1 << i);
std::lock_guard<std::mutex> lk(m_callbackLock); std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback) if (m_callback)
@ -170,30 +153,23 @@ void DolphinSmashAdapter::deviceDisconnected()
static int16_t pad_clampregion[8] = {30, 180, 15, 72, 40, 15, 59, 31}; static int16_t pad_clampregion[8] = {30, 180, 15, 72, 40, 15, 59, 31};
static void pad_clampstick(int16_t& px, int16_t& py, int16_t max, int16_t xy, int16_t min) static void pad_clampstick(int16_t& px, int16_t& py, int16_t max, int16_t xy, int16_t min) {
{
int x = px; int x = px;
int y = py; int y = py;
int signX; int signX;
int signY; int signY;
int d; int d;
if (x > 0) if (x > 0) {
{
signX = 1; signX = 1;
} } else {
else
{
signX = -1; signX = -1;
x = -x; x = -x;
} }
if (y > 0) if (y > 0) {
{
signY = 1; signY = 1;
} } else {
else
{
signY = -1; signY = -1;
y = -y; y = -y;
} }
@ -203,35 +179,26 @@ static void pad_clampstick(int16_t& px, int16_t& py, int16_t max, int16_t xy, in
else else
x -= min; x -= min;
if (y <= min) if (y <= min) {
{
y = 0; y = 0;
} } else {
else
{
y -= min; y -= min;
} }
if (x == 0 && y == 0) if (x == 0 && y == 0) {
{
px = py = 0; px = py = 0;
return; return;
} }
if (xy * y <= xy * x) if (xy * y <= xy * x) {
{
d = xy * x + (max - xy) * y; d = xy * x + (max - xy) * y;
if (xy * max < d) if (xy * max < d) {
{
x = int16_t(xy * max * x / d); x = int16_t(xy * max * x / d);
y = int16_t(xy * max * y / d); y = int16_t(xy * max * y / d);
} }
} } else {
else
{
d = xy * y + (max - xy) * x; d = xy * y + (max - xy) * x;
if (xy * max < d) if (xy * max < d) {
{
x = int16_t(xy * max * x / d); x = int16_t(xy * max * x / d);
y = int16_t(xy * max * y / d); y = int16_t(xy * max * y / d);
} }
@ -241,27 +208,24 @@ static void pad_clampstick(int16_t& px, int16_t& py, int16_t max, int16_t xy, in
py = int16_t(signY * y); py = int16_t(signY * y);
} }
static void pad_clamptrigger(int16_t& trigger) static void pad_clamptrigger(int16_t& trigger) {
{
int16_t min, max; int16_t min, max;
min = pad_clampregion[0]; min = pad_clampregion[0];
max = pad_clampregion[1]; max = pad_clampregion[1];
if (min > trigger) if (min > trigger)
trigger = 0; trigger = 0;
else else {
{
if (max < trigger) if (max < trigger)
trigger = max; trigger = max;
trigger -= min; trigger -= min;
} }
} }
void DolphinControllerState::clamp() void DolphinControllerState::clamp() {
{
pad_clampstick(m_leftStick[0], m_leftStick[1], pad_clampregion[3], pad_clampregion[4], pad_clampregion[2]); pad_clampstick(m_leftStick[0], m_leftStick[1], pad_clampregion[3], pad_clampregion[4], pad_clampregion[2]);
pad_clampstick(m_rightStick[0], m_rightStick[1], pad_clampregion[6], pad_clampregion[7], pad_clampregion[5]); pad_clampstick(m_rightStick[0], m_rightStick[1], pad_clampregion[6], pad_clampregion[7], pad_clampregion[5]);
pad_clamptrigger(m_analogTriggers[0]); pad_clamptrigger(m_analogTriggers[0]);
pad_clamptrigger(m_analogTriggers[1]); pad_clamptrigger(m_analogTriggers[1]);
} }
} } // namespace boo

View File

@ -20,41 +20,27 @@ static inline uint16_t bswap16(uint16_t val) {return __builtin_byteswap(val);}
#define RAD_TO_DEG (180.f / M_PIF) #define RAD_TO_DEG (180.f / M_PIF)
namespace boo namespace boo {
{ static const uint8_t defaultReport[49] = {0x01, 0x01, 0xff, 0x00, 0xff, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff,
static const uint8_t defaultReport[49] = { 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10,
0x01, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00};
0x01, 0xff, 0x00, 0xff, 0x00,
0xff, 0x80, 0x00, 0x00, 0x00,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0x00, 0x00, 0x00, 0x00, 0x00
};
DualshockPad::DualshockPad(DeviceToken* token) DualshockPad::DualshockPad(DeviceToken* token)
: TDeviceBase<IDualshockPadCallback>(dev_typeid(DualshockPad), token), : TDeviceBase<IDualshockPadCallback>(dev_typeid(DualshockPad), token)
m_rumbleRequest(EDualshockMotor::None), , m_rumbleRequest(EDualshockMotor::None)
m_rumbleState(EDualshockMotor::None) , m_rumbleState(EDualshockMotor::None) {
{
memcpy(m_report.buf, defaultReport, 49); memcpy(m_report.buf, defaultReport, 49);
} }
DualshockPad::~DualshockPad() DualshockPad::~DualshockPad() {}
{
} void DualshockPad::deviceDisconnected() {
void DualshockPad::deviceDisconnected()
{
std::lock_guard<std::mutex> lk(m_callbackLock); std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback) if (m_callback)
m_callback->controllerDisconnected(); m_callback->controllerDisconnected();
} }
void DualshockPad::initialCycle() void DualshockPad::initialCycle() {
{
#if 0 #if 0
uint8_t setupCommand[5] = {0xF4, 0x42, 0x0c, 0x00, 0x00}; //Tells controller to start sending changes on in pipe uint8_t setupCommand[5] = {0xF4, 0x42, 0x0c, 0x00, 0x00}; //Tells controller to start sending changes on in pipe
if (!sendHIDReport(setupCommand, 5, HIDReportType::Feature, 0xF4)) if (!sendHIDReport(setupCommand, 5, HIDReportType::Feature, 0xF4))
@ -69,12 +55,9 @@ void DualshockPad::initialCycle()
#endif #endif
} }
void DualshockPad::transferCycle() void DualshockPad::transferCycle() {}
{
}
void DualshockPad::finalCycle() void DualshockPad::finalCycle() {
{
m_report.rumble.leftDuration = 0; m_report.rumble.leftDuration = 0;
m_report.rumble.leftForce = 0; m_report.rumble.leftForce = 0;
m_report.rumble.rightDuration = 0; m_report.rumble.rightDuration = 0;
@ -82,8 +65,7 @@ void DualshockPad::finalCycle()
sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01); sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01);
} }
void DualshockPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) void DualshockPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
{
if (message != 1 || length != 49 || tp != HIDReportType::Input) if (message != 1 || length != 49 || tp != HIDReportType::Input)
return; return;
DualshockPadState state = *reinterpret_cast<const DualshockPadState*>(data); DualshockPadState state = *reinterpret_cast<const DualshockPadState*>(data);
@ -106,34 +88,25 @@ void DualshockPad::receivedHIDReport(const uint8_t* data, size_t length, HIDRepo
m_callback->controllerUpdate(*this, state); m_callback->controllerUpdate(*this, state);
} }
if (m_rumbleRequest != m_rumbleState) if (m_rumbleRequest != m_rumbleState) {
{ if ((m_rumbleRequest & EDualshockMotor::Left) != EDualshockMotor::None) {
if ((m_rumbleRequest & EDualshockMotor::Left) != EDualshockMotor::None)
{
m_report.rumble.leftDuration = m_rumbleDuration[0]; m_report.rumble.leftDuration = m_rumbleDuration[0];
m_report.rumble.leftForce = m_rumbleIntensity[0]; m_report.rumble.leftForce = m_rumbleIntensity[0];
} } else {
else
{
m_report.rumble.leftDuration = 0; m_report.rumble.leftDuration = 0;
m_report.rumble.leftForce = 0; m_report.rumble.leftForce = 0;
} }
if ((m_rumbleRequest & EDualshockMotor::Right) != EDualshockMotor::None) if ((m_rumbleRequest & EDualshockMotor::Right) != EDualshockMotor::None) {
{
m_report.rumble.rightDuration = m_rumbleDuration[1]; m_report.rumble.rightDuration = m_rumbleDuration[1];
m_report.rumble.rightOn = m_rumbleIntensity[1] > 0; m_report.rumble.rightOn = m_rumbleIntensity[1] > 0;
} } else {
else
{
m_report.rumble.rightDuration = 0; m_report.rumble.rightDuration = 0;
m_report.rumble.rightOn = false; m_report.rumble.rightOn = false;
} }
sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01); sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01);
m_rumbleState = m_rumbleRequest; m_rumbleState = m_rumbleRequest;
} } else {
else
{
if (state.m_reserved5[8] & 0x80) if (state.m_reserved5[8] & 0x80)
m_rumbleRequest &= ~EDualshockMotor::Right; m_rumbleRequest &= ~EDualshockMotor::Right;
if (state.m_reserved5[7] & 0x01) if (state.m_reserved5[7] & 0x01)
@ -142,4 +115,4 @@ void DualshockPad::receivedHIDReport(const uint8_t* data, size_t length, HIDRepo
} }
} }
} // boo } // namespace boo

View File

@ -1,26 +1,19 @@
#include "boo/inputdev/GenericPad.hpp" #include "boo/inputdev/GenericPad.hpp"
#include "boo/inputdev/DeviceToken.hpp" #include "boo/inputdev/DeviceToken.hpp"
namespace boo namespace boo {
{
GenericPad::GenericPad(DeviceToken* token) GenericPad::GenericPad(DeviceToken* token) : TDeviceBase<IGenericPadCallback>(dev_typeid(GenericPad), token) {}
: TDeviceBase<IGenericPadCallback>(dev_typeid(GenericPad), token)
{
}
GenericPad::~GenericPad() {} GenericPad::~GenericPad() {}
void GenericPad::deviceDisconnected() void GenericPad::deviceDisconnected() {
{
std::lock_guard<std::mutex> lk(m_callbackLock); std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback) if (m_callback)
m_callback->controllerDisconnected(); m_callback->controllerDisconnected();
} }
void GenericPad::initialCycle() void GenericPad::initialCycle() {
{
#if _WIN32 #if _WIN32
#if !WINDOWS_STORE #if !WINDOWS_STORE
const PHIDP_PREPARSED_DATA reportDesc = getReportDescriptor(); const PHIDP_PREPARSED_DATA reportDesc = getReportDescriptor();
@ -35,23 +28,19 @@ void GenericPad::initialCycle()
m_callback->controllerConnected(); m_callback->controllerConnected();
} }
void GenericPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) void GenericPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
{
std::lock_guard<std::mutex> lk(m_callbackLock); std::lock_guard<std::mutex> lk(m_callbackLock);
if (length == 0 || tp != HIDReportType::Input || !m_callback) if (length == 0 || tp != HIDReportType::Input || !m_callback)
return; return;
std::function<bool(const HIDMainItem&, int32_t)> func = std::function<bool(const HIDMainItem&, int32_t)> func = [this](const HIDMainItem& item, int32_t value) {
[this](const HIDMainItem& item, int32_t value)
{
m_callback->valueUpdate(item, value); m_callback->valueUpdate(item, value);
return true; return true;
}; };
m_parser.ScanValues(func, data, length); m_parser.ScanValues(func, data, length);
} }
void GenericPad::enumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const void GenericPad::enumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const {
{
m_parser.EnumerateValues(valueCB); m_parser.EnumerateValues(valueCB);
} }
} } // namespace boo

View File

@ -1,22 +1,15 @@
#include "boo/inputdev/IHIDListener.hpp" #include "boo/inputdev/IHIDListener.hpp"
#include "boo/inputdev/DeviceFinder.hpp" #include "boo/inputdev/DeviceFinder.hpp"
namespace boo {
namespace boo class HIDListenerBSD final : public IHIDListener {
{
class HIDListenerBSD final : public IHIDListener
{
DeviceFinder& m_finder; DeviceFinder& m_finder;
public:
HIDListenerBSD(DeviceFinder& finder)
: m_finder(finder)
{
}
~HIDListenerBSD() public:
{ HIDListenerBSD(DeviceFinder& finder) : m_finder(finder) {}
}
~HIDListenerBSD() {}
bool startScanning() { return false; } bool startScanning() { return false; }
bool stopScanning() { return false; } bool stopScanning() { return false; }
@ -24,8 +17,5 @@ public:
bool scanNow() { return false; } bool scanNow() { return false; }
}; };
IHIDListener* IHIDListenerNew(DeviceFinder &finder) IHIDListener* IHIDListenerNew(DeviceFinder& finder) { return new HIDListenerBSD(finder); }
{ } // namespace boo
return new HIDListenerBSD(finder);
}
}

View File

@ -5,11 +5,9 @@
#include "IOKitPointer.hpp" #include "IOKitPointer.hpp"
#include <thread> #include <thread>
namespace boo namespace boo {
{
class HIDDeviceIOKit : public IHIDDevice class HIDDeviceIOKit : public IHIDDevice {
{
DeviceToken& m_token; DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp; std::shared_ptr<DeviceBase> m_devImp;
@ -25,20 +23,16 @@ class HIDDeviceIOKit : public IHIDDevice
std::condition_variable m_initCond; std::condition_variable m_initCond;
std::thread m_thread; std::thread m_thread;
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) {
{ if (m_usbIntf) {
if (m_usbIntf)
{
IOReturn res = m_usbIntf->WritePipe(m_usbIntf.storage(), m_usbIntfOutPipe, (void*)data, length); IOReturn res = m_usbIntf->WritePipe(m_usbIntf.storage(), m_usbIntfOutPipe, (void*)data, length);
return res == kIOReturnSuccess; return res == kIOReturnSuccess;
} }
return false; return false;
} }
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) {
{ if (m_usbIntf) {
if (m_usbIntf)
{
UInt32 readSize = length; UInt32 readSize = length;
IOReturn res = m_usbIntf->ReadPipe(m_usbIntf.storage(), m_usbIntfInPipe, data, &readSize); IOReturn res = m_usbIntf->ReadPipe(m_usbIntf.storage(), m_usbIntfInPipe, data, &readSize);
if (res != kIOReturnSuccess) if (res != kIOReturnSuccess)
@ -48,12 +42,9 @@ class HIDDeviceIOKit : public IHIDDevice
return 0; return 0;
} }
std::vector<uint8_t> _getReportDescriptor() std::vector<uint8_t> _getReportDescriptor() {
{ if (m_hidIntf) {
if (m_hidIntf) if (CFTypeRef desc = IOHIDDeviceGetProperty(m_hidIntf.get(), CFSTR(kIOHIDReportDescriptorKey))) {
{
if (CFTypeRef desc = IOHIDDeviceGetProperty(m_hidIntf.get(), CFSTR(kIOHIDReportDescriptorKey)))
{
CFIndex len = CFDataGetLength(CFDataRef(desc)); CFIndex len = CFDataGetLength(CFDataRef(desc));
std::vector<uint8_t> ret(len, '\0'); std::vector<uint8_t> ret(len, '\0');
CFDataGetBytes(CFDataRef(desc), CFRangeMake(0, len), &ret[0]); CFDataGetBytes(CFDataRef(desc), CFRangeMake(0, len), &ret[0]);
@ -63,22 +54,18 @@ class HIDDeviceIOKit : public IHIDDevice
return {}; return {};
} }
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
{
/* HACK: A bug in IOBluetoothGamepadHIDDriver prevents raw output report transmission /* HACK: A bug in IOBluetoothGamepadHIDDriver prevents raw output report transmission
* USB driver appears to work correctly */ * USB driver appears to work correctly */
if (m_hidIntf && !m_isBt) if (m_hidIntf && !m_isBt) {
{
IOReturn res = IOHIDDeviceSetReport(m_hidIntf.get(), IOHIDReportType(tp), message, data, length); IOReturn res = IOHIDDeviceSetReport(m_hidIntf.get(), IOHIDReportType(tp), message, data, length);
return res == kIOReturnSuccess; return res == kIOReturnSuccess;
} }
return false; return false;
} }
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
{ if (m_hidIntf) {
if (m_hidIntf)
{
CFIndex readSize = length; CFIndex readSize = length;
IOReturn res = IOHIDDeviceGetReport(m_hidIntf.get(), IOHIDReportType(tp), message, data, &readSize); IOReturn res = IOHIDDeviceGetReport(m_hidIntf.get(), IOHIDReportType(tp), message, data, &readSize);
if (res != kIOReturnSuccess) if (res != kIOReturnSuccess)
@ -88,8 +75,7 @@ class HIDDeviceIOKit : public IHIDDevice
return 0; return 0;
} }
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceIOKit> device) static void _threadProcUSBLL(std::shared_ptr<HIDDeviceIOKit> device) {
{
char thrName[128]; char thrName[128];
snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().data()); snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().data());
pthread_setname_np(thrName); pthread_setname_np(thrName);
@ -98,22 +84,18 @@ class HIDDeviceIOKit : public IHIDDevice
/* Get the HID element's parent (USB interrupt transfer-interface) */ /* Get the HID element's parent (USB interrupt transfer-interface) */
IOObjectPointer<io_iterator_t> devIter; IOObjectPointer<io_iterator_t> devIter;
IOObjectPointer<io_registry_entry_t> devEntry = IORegistryEntryFromPath(kIOMasterPortDefault, IOObjectPointer<io_registry_entry_t> devEntry =
device->m_devPath.data()); IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.data());
IOObjectPointer<io_object_t> interfaceEntry; IOObjectPointer<io_object_t> interfaceEntry;
IORegistryEntryGetChildIterator(devEntry.get(), kIOServicePlane, &devIter); IORegistryEntryGetChildIterator(devEntry.get(), kIOServicePlane, &devIter);
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(devIter.get())) while (IOObjectPointer<io_service_t> obj = IOIteratorNext(devIter.get())) {
{ if (IOObjectConformsTo(obj.get(), kIOUSBInterfaceClassName)) {
if (IOObjectConformsTo(obj.get(), kIOUSBInterfaceClassName))
{
interfaceEntry = obj; interfaceEntry = obj;
break; break;
} }
} }
if (!interfaceEntry) if (!interfaceEntry) {
{ snprintf(errStr, 256, "Unable to find interface for %s@%s\n", device->m_token.getProductName().data(),
snprintf(errStr, 256, "Unable to find interface for %s@%s\n",
device->m_token.getProductName().data(),
device->m_devPath.data()); device->m_devPath.data());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
lk.unlock(); lk.unlock();
@ -125,15 +107,11 @@ class HIDDeviceIOKit : public IHIDDevice
IOCFPluginPointer iodev; IOCFPluginPointer iodev;
SInt32 score; SInt32 score;
IOReturn err; IOReturn err;
err = IOCreatePlugInInterfaceForService(interfaceEntry.get(), err = IOCreatePlugInInterfaceForService(interfaceEntry.get(), kIOUSBInterfaceUserClientTypeID,
kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
kIOCFPlugInInterfaceID, if (err) {
&iodev, snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(),
&score); device->m_devPath.data());
if (err)
{
snprintf(errStr, 256, "Unable to open %s@%s\n",
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
lk.unlock(); lk.unlock();
device->m_initCond.notify_one(); device->m_initCond.notify_one();
@ -143,10 +121,9 @@ class HIDDeviceIOKit : public IHIDDevice
/* USB interface function-pointer table */ /* USB interface function-pointer table */
IUnknownPointer<IOUSBInterfaceInterface> intf; IUnknownPointer<IOUSBInterfaceInterface> intf;
err = iodev.As(&intf, kIOUSBInterfaceInterfaceID); err = iodev.As(&intf, kIOUSBInterfaceInterfaceID);
if (err) if (err) {
{ snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(),
snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_devPath.data());
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
lk.unlock(); lk.unlock();
device->m_initCond.notify_one(); device->m_initCond.notify_one();
@ -156,18 +133,14 @@ class HIDDeviceIOKit : public IHIDDevice
/* Obtain exclusive lock on device */ /* Obtain exclusive lock on device */
device->m_usbIntf = intf; device->m_usbIntf = intf;
err = intf->USBInterfaceOpen(intf.storage()); err = intf->USBInterfaceOpen(intf.storage());
if (err != kIOReturnSuccess) if (err != kIOReturnSuccess) {
{ if (err == kIOReturnExclusiveAccess) {
if (err == kIOReturnExclusiveAccess) snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n", device->m_token.getProductName().data(),
{ device->m_devPath.data());
snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n",
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
} } else {
else snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(),
{ device->m_devPath.data());
snprintf(errStr, 256, "Unable to open %s@%s\n",
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
} }
lk.unlock(); lk.unlock();
@ -178,13 +151,11 @@ class HIDDeviceIOKit : public IHIDDevice
/* Determine pipe indices for interrupt I/O */ /* Determine pipe indices for interrupt I/O */
UInt8 numEndpoints = 0; UInt8 numEndpoints = 0;
err = intf->GetNumEndpoints(intf.storage(), &numEndpoints); err = intf->GetNumEndpoints(intf.storage(), &numEndpoints);
for (int i=1 ; i<numEndpoints+1 ; ++i) for (int i = 1; i < numEndpoints + 1; ++i) {
{
UInt8 dir, num, tType, interval; UInt8 dir, num, tType, interval;
UInt16 mPacketSz; UInt16 mPacketSz;
err = intf->GetPipeProperties(intf.storage(), i, &dir, &num, &tType, &mPacketSz, &interval); err = intf->GetPipeProperties(intf.storage(), i, &dir, &num, &tType, &mPacketSz, &interval);
if (tType == kUSBInterrupt) if (tType == kUSBInterrupt) {
{
if (dir == kUSBIn) if (dir == kUSBIn)
device->m_usbIntfInPipe = num; device->m_usbIntfInPipe = num;
else if (dir == kUSBOut) else if (dir == kUSBOut)
@ -208,8 +179,7 @@ class HIDDeviceIOKit : public IHIDDevice
device->m_usbIntf = nullptr; device->m_usbIntf = nullptr;
} }
static void _threadProcBTLL(std::shared_ptr<HIDDeviceIOKit> device) static void _threadProcBTLL(std::shared_ptr<HIDDeviceIOKit> device) {
{
std::unique_lock<std::mutex> lk(device->m_initMutex); std::unique_lock<std::mutex> lk(device->m_initMutex);
/* Return control to main thread */ /* Return control to main thread */
@ -224,26 +194,16 @@ class HIDDeviceIOKit : public IHIDDevice
device->m_devImp->finalCycle(); device->m_devImp->finalCycle();
} }
static void _hidRemoveCb(void * _Nullable context, static void _hidRemoveCb(void* _Nullable context, IOReturn result, void* _Nullable sender) {
IOReturn result,
void * _Nullable sender)
{
reinterpret_cast<HIDDeviceIOKit*>(context)->m_runningTransferLoop = false; reinterpret_cast<HIDDeviceIOKit*>(context)->m_runningTransferLoop = false;
} }
static void _hidReportCb(void * _Nullable context, static void _hidReportCb(void* _Nullable context, IOReturn, void* _Nullable, IOHIDReportType type, uint32_t reportID,
IOReturn, uint8_t* report, CFIndex reportLength) {
void * _Nullable,
IOHIDReportType type,
uint32_t reportID,
uint8_t * report,
CFIndex reportLength)
{
reinterpret_cast<DeviceBase*>(context)->receivedHIDReport(report, reportLength, HIDReportType(type), reportID); reinterpret_cast<DeviceBase*>(context)->receivedHIDReport(report, reportLength, HIDReportType(type), reportID);
} }
static void _threadProcHID(std::shared_ptr<HIDDeviceIOKit> device) static void _threadProcHID(std::shared_ptr<HIDDeviceIOKit> device) {
{
char thrName[128]; char thrName[128];
snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().data()); snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().data());
pthread_setname_np(thrName); pthread_setname_np(thrName);
@ -253,10 +213,8 @@ class HIDDeviceIOKit : public IHIDDevice
/* Get the HID element's object (HID device interface) */ /* Get the HID element's object (HID device interface) */
IOObjectPointer<io_service_t> interfaceEntry = IOObjectPointer<io_service_t> interfaceEntry =
IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.data()); IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.data());
if (!IOObjectConformsTo(interfaceEntry.get(), "IOHIDDevice")) if (!IOObjectConformsTo(interfaceEntry.get(), "IOHIDDevice")) {
{ snprintf(errStr, 256, "Unable to find interface for %s@%s\n", device->m_token.getProductName().data(),
snprintf(errStr, 256, "Unable to find interface for %s@%s\n",
device->m_token.getProductName().data(),
device->m_devPath.data()); device->m_devPath.data());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
lk.unlock(); lk.unlock();
@ -265,10 +223,9 @@ class HIDDeviceIOKit : public IHIDDevice
} }
device->m_hidIntf = IOHIDDeviceCreate(nullptr, interfaceEntry.get()); device->m_hidIntf = IOHIDDeviceCreate(nullptr, interfaceEntry.get());
if (!device->m_hidIntf) if (!device->m_hidIntf) {
{ snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(),
snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_devPath.data());
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
lk.unlock(); lk.unlock();
device->m_initCond.notify_one(); device->m_initCond.notify_one();
@ -277,18 +234,14 @@ class HIDDeviceIOKit : public IHIDDevice
/* Open device */ /* Open device */
IOReturn err = IOHIDDeviceOpen(device->m_hidIntf.get(), kIOHIDOptionsTypeNone); IOReturn err = IOHIDDeviceOpen(device->m_hidIntf.get(), kIOHIDOptionsTypeNone);
if (err != kIOReturnSuccess) if (err != kIOReturnSuccess) {
{ if (err == kIOReturnExclusiveAccess) {
if (err == kIOReturnExclusiveAccess) snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n", device->m_token.getProductName().data(),
{ device->m_devPath.data());
snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n",
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
} } else {
else snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(),
{ device->m_devPath.data());
snprintf(errStr, 256, "Unable to open %s@%s\n",
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
} }
lk.unlock(); lk.unlock();
@ -301,18 +254,18 @@ class HIDDeviceIOKit : public IHIDDevice
/* Make note if device uses bluetooth driver */ /* Make note if device uses bluetooth driver */
if (CFTypeRef transport = IOHIDDeviceGetProperty(device->m_hidIntf.get(), CFSTR(kIOHIDTransportKey))) if (CFTypeRef transport = IOHIDDeviceGetProperty(device->m_hidIntf.get(), CFSTR(kIOHIDTransportKey)))
device->m_isBt = CFStringCompare(CFStringRef(transport), CFSTR(kIOHIDTransportBluetoothValue), 0) == kCFCompareEqualTo; device->m_isBt =
CFStringCompare(CFStringRef(transport), CFSTR(kIOHIDTransportBluetoothValue), 0) == kCFCompareEqualTo;
/* Register input buffer */ /* Register input buffer */
std::unique_ptr<uint8_t[]> buffer; std::unique_ptr<uint8_t[]> buffer;
int bufSize = 0; int bufSize = 0;
if (CFTypeRef maxSize = IOHIDDeviceGetProperty(device->m_hidIntf.get(), CFSTR(kIOHIDMaxInputReportSizeKey))) if (CFTypeRef maxSize = IOHIDDeviceGetProperty(device->m_hidIntf.get(), CFSTR(kIOHIDMaxInputReportSizeKey)))
CFNumberGetValue(CFNumberRef(maxSize), kCFNumberIntType, &bufSize); CFNumberGetValue(CFNumberRef(maxSize), kCFNumberIntType, &bufSize);
if (bufSize) if (bufSize) {
{
buffer = std::unique_ptr<uint8_t[]>(new uint8_t[bufSize]); buffer = std::unique_ptr<uint8_t[]>(new uint8_t[bufSize]);
IOHIDDeviceRegisterInputReportCallback(device->m_hidIntf.get(), buffer.get(), bufSize, IOHIDDeviceRegisterInputReportCallback(device->m_hidIntf.get(), buffer.get(), bufSize, _hidReportCb,
_hidReportCb, device->m_devImp.get()); device->m_devImp.get());
IOHIDDeviceScheduleWithRunLoop(device->m_hidIntf.get(), CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); IOHIDDeviceScheduleWithRunLoop(device->m_hidIntf.get(), CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
} }
@ -323,8 +276,7 @@ class HIDDeviceIOKit : public IHIDDevice
/* Start transfer loop */ /* Start transfer loop */
device->m_devImp->initialCycle(); device->m_devImp->initialCycle();
while (device->m_runningTransferLoop) while (device->m_runningTransferLoop) {
{
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.010, true); CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.010, true);
if (device->m_runningTransferLoop) if (device->m_runningTransferLoop)
device->m_devImp->transferCycle(); device->m_devImp->transferCycle();
@ -336,22 +288,13 @@ class HIDDeviceIOKit : public IHIDDevice
device->m_hidIntf.reset(); device->m_hidIntf.reset();
} }
void _deviceDisconnected() void _deviceDisconnected() { m_runningTransferLoop = false; }
{
m_runningTransferLoop = false;
}
public: public:
HIDDeviceIOKit(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) HIDDeviceIOKit(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token), : m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {}
m_devImp(devImp),
m_devPath(token.getDevicePath())
{
}
void _startThread() void _startThread() {
{
std::unique_lock<std::mutex> lk(m_initMutex); std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType(); DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB) if (dType == DeviceType::USB)
@ -360,25 +303,22 @@ public:
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this())); m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this()));
else if (dType == DeviceType::HID) else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this())); m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this()));
else else {
{
fprintf(stderr, "invalid token supplied to device constructor\n"); fprintf(stderr, "invalid token supplied to device constructor\n");
return; return;
} }
m_initCond.wait(lk); m_initCond.wait(lk);
} }
~HIDDeviceIOKit() ~HIDDeviceIOKit() {
{
m_runningTransferLoop = false; m_runningTransferLoop = false;
if (m_thread.joinable()) if (m_thread.joinable())
m_thread.detach(); m_thread.detach();
} }
}; };
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
{
return std::make_shared<HIDDeviceIOKit>(token, devImp); return std::make_shared<HIDDeviceIOKit>(token, devImp);
} }
} } // namespace boo

View File

@ -1,21 +1,15 @@
#include "IHIDDevice.hpp" #include "IHIDDevice.hpp"
namespace boo namespace boo {
{
class HIDDeviceNX : public IHIDDevice class HIDDeviceNX : public IHIDDevice {
{
DeviceToken& m_token; DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp; std::shared_ptr<DeviceBase> m_devImp;
std::string_view m_devPath; std::string_view m_devPath;
public: public:
HIDDeviceNX(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) HIDDeviceNX(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token), : m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {}
m_devImp(devImp),
m_devPath(token.getDevicePath())
{
}
void _deviceDisconnected() {} void _deviceDisconnected() {}
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; } bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; }
@ -26,9 +20,8 @@ public:
void _startThread() {} void _startThread() {}
}; };
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
{
return std::make_shared<HIDDeviceNX>(token, devImp); return std::make_shared<HIDDeviceNX>(token, devImp);
} }
} } // namespace boo

View File

@ -3,16 +3,11 @@
#include "boo/inputdev/DeviceToken.hpp" #include "boo/inputdev/DeviceToken.hpp"
#include "boo/inputdev/DeviceBase.hpp" #include "boo/inputdev/DeviceBase.hpp"
namespace boo namespace boo {
{
class HIDDeviceUWP : public IHIDDevice class HIDDeviceUWP : public IHIDDevice {
{
public: public:
HIDDeviceUWP(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) HIDDeviceUWP(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {}
{
}
void _deviceDisconnected() {} void _deviceDisconnected() {}
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; } bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; }
@ -22,9 +17,8 @@ public:
void _startThread() {} void _startThread() {}
}; };
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
{
return std::make_shared<HIDDeviceUWP>(token, devImp); return std::make_shared<HIDDeviceUWP>(token, devImp);
} }
} } // namespace boo

View File

@ -18,8 +18,7 @@
#include <cstring> #include <cstring>
#include "boo/inputdev/HIDParser.hpp" #include "boo/inputdev/HIDParser.hpp"
namespace boo namespace boo {
{
udev* GetUdev(); udev* GetUdev();
@ -27,8 +26,7 @@ udev* GetUdev();
* Reference: http://tali.admingilde.org/linux-docbook/usb/ch07s06.html * Reference: http://tali.admingilde.org/linux-docbook/usb/ch07s06.html
*/ */
class HIDDeviceUdev final : public IHIDDevice class HIDDeviceUdev final : public IHIDDevice {
{
DeviceToken& m_token; DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp; std::shared_ptr<DeviceBase> m_devImp;
@ -42,17 +40,9 @@ class HIDDeviceUdev final : public IHIDDevice
std::condition_variable m_initCond; std::condition_variable m_initCond;
std::thread m_thread; std::thread m_thread;
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) {
{ if (m_devFd) {
if (m_devFd) usbdevfs_bulktransfer xfer = {m_usbIntfOutPipe | USB_DIR_OUT, (unsigned)length, 30, (void*)data};
{
usbdevfs_bulktransfer xfer =
{
m_usbIntfOutPipe | USB_DIR_OUT,
(unsigned)length,
30,
(void*)data
};
int ret = ioctl(m_devFd, USBDEVFS_BULK, &xfer); int ret = ioctl(m_devFd, USBDEVFS_BULK, &xfer);
if (ret != (int)length) if (ret != (int)length)
return false; return false;
@ -61,24 +51,15 @@ class HIDDeviceUdev final : public IHIDDevice
return false; return false;
} }
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) {
{ if (m_devFd) {
if (m_devFd) usbdevfs_bulktransfer xfer = {m_usbIntfInPipe | USB_DIR_IN, (unsigned)length, 30, data};
{
usbdevfs_bulktransfer xfer =
{
m_usbIntfInPipe | USB_DIR_IN,
(unsigned)length,
30,
data
};
return ioctl(m_devFd, USBDEVFS_BULK, &xfer); return ioctl(m_devFd, USBDEVFS_BULK, &xfer);
} }
return 0; return 0;
} }
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceUdev> device) static void _threadProcUSBLL(std::shared_ptr<HIDDeviceUdev> device) {
{
int i; int i;
char errStr[256]; char errStr[256];
std::unique_lock<std::mutex> lk(device->m_initMutex); std::unique_lock<std::mutex> lk(device->m_initMutex);
@ -87,10 +68,8 @@ class HIDDeviceUdev final : public IHIDDevice
/* Get device file */ /* Get device file */
const char* dp = udev_device_get_devnode(udevDev); const char* dp = udev_device_get_devnode(udevDev);
int fd = open(dp, O_RDWR); int fd = open(dp, O_RDWR);
if (fd < 0) if (fd < 0) {
{ snprintf(errStr, 256, "Unable to open %s@%s: %s\n", device->m_token.getProductName().data(), dp, strerror(errno));
snprintf(errStr, 256, "Unable to open %s@%s: %s\n",
device->m_token.getProductName().data(), dp, strerror(errno));
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
lk.unlock(); lk.unlock();
device->m_initCond.notify_one(); device->m_initCond.notify_one();
@ -101,23 +80,19 @@ class HIDDeviceUdev final : public IHIDDevice
usb_device_descriptor devDesc = {}; usb_device_descriptor devDesc = {};
read(fd, &devDesc, 1); read(fd, &devDesc, 1);
read(fd, &devDesc.bDescriptorType, devDesc.bLength - 1); read(fd, &devDesc.bDescriptorType, devDesc.bLength - 1);
if (devDesc.bNumConfigurations) if (devDesc.bNumConfigurations) {
{
usb_config_descriptor confDesc = {}; usb_config_descriptor confDesc = {};
read(fd, &confDesc, 1); read(fd, &confDesc, 1);
read(fd, &confDesc.bDescriptorType, confDesc.bLength - 1); read(fd, &confDesc.bDescriptorType, confDesc.bLength - 1);
if (confDesc.bNumInterfaces) if (confDesc.bNumInterfaces) {
{
usb_interface_descriptor intfDesc = {}; usb_interface_descriptor intfDesc = {};
read(fd, &intfDesc, 1); read(fd, &intfDesc, 1);
read(fd, &intfDesc.bDescriptorType, intfDesc.bLength - 1); read(fd, &intfDesc.bDescriptorType, intfDesc.bLength - 1);
for (i=0 ; i<intfDesc.bNumEndpoints+1 ; ++i) for (i = 0; i < intfDesc.bNumEndpoints + 1; ++i) {
{
usb_endpoint_descriptor endpDesc = {}; usb_endpoint_descriptor endpDesc = {};
read(fd, &endpDesc, 1); read(fd, &endpDesc, 1);
read(fd, &endpDesc.bDescriptorType, endpDesc.bLength - 1); read(fd, &endpDesc.bDescriptorType, endpDesc.bLength - 1);
if ((endpDesc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) if ((endpDesc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
{
if ((endpDesc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) if ((endpDesc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
device->m_usbIntfInPipe = endpDesc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; device->m_usbIntfInPipe = endpDesc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
else if ((endpDesc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) else if ((endpDesc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
@ -128,11 +103,7 @@ class HIDDeviceUdev final : public IHIDDevice
} }
/* Request that kernel disconnects existing driver */ /* Request that kernel disconnects existing driver */
usbdevfs_ioctl disconnectReq = { usbdevfs_ioctl disconnectReq = {0, USBDEVFS_DISCONNECT, NULL};
0,
USBDEVFS_DISCONNECT,
NULL
};
ioctl(fd, USBDEVFS_IOCTL, &disconnectReq); ioctl(fd, USBDEVFS_IOCTL, &disconnectReq);
/* Return control to main thread */ /* Return control to main thread */
@ -152,8 +123,7 @@ class HIDDeviceUdev final : public IHIDDevice
udev_device_unref(udevDev); udev_device_unref(udevDev);
} }
static void _threadProcBTLL(std::shared_ptr<HIDDeviceUdev> device) static void _threadProcBTLL(std::shared_ptr<HIDDeviceUdev> device) {
{
std::unique_lock<std::mutex> lk(device->m_initMutex); std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.data()); udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.data());
@ -171,8 +141,7 @@ class HIDDeviceUdev final : public IHIDDevice
udev_device_unref(udevDev); udev_device_unref(udevDev);
} }
static void _threadProcHID(std::shared_ptr<HIDDeviceUdev> device) static void _threadProcHID(std::shared_ptr<HIDDeviceUdev> device) {
{
char errStr[256]; char errStr[256];
std::unique_lock<std::mutex> lk(device->m_initMutex); std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.data()); udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.data());
@ -180,10 +149,8 @@ class HIDDeviceUdev final : public IHIDDevice
/* Get device file */ /* Get device file */
const char* dp = udev_device_get_devnode(udevDev); const char* dp = udev_device_get_devnode(udevDev);
int fd = open(dp, O_RDWR | O_NONBLOCK); int fd = open(dp, O_RDWR | O_NONBLOCK);
if (fd < 0) if (fd < 0) {
{ snprintf(errStr, 256, "Unable to open %s@%s: %s\n", device->m_token.getProductName().data(), dp, strerror(errno));
snprintf(errStr, 256, "Unable to open %s@%s: %s\n",
device->m_token.getProductName().data(), dp, strerror(errno));
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
lk.unlock(); lk.unlock();
device->m_initCond.notify_one(); device->m_initCond.notify_one();
@ -199,10 +166,9 @@ class HIDDeviceUdev final : public IHIDDevice
/* Report descriptor size */ /* Report descriptor size */
int reportDescSize; int reportDescSize;
if (ioctl(fd, HIDIOCGRDESCSIZE, &reportDescSize) == -1) if (ioctl(fd, HIDIOCGRDESCSIZE, &reportDescSize) == -1) {
{ snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESCSIZE) %s@%s: %s\n", device->m_token.getProductName().data(),
snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESCSIZE) %s@%s: %s\n", dp, strerror(errno));
device->m_token.getProductName().data(), dp, strerror(errno));
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
close(fd); close(fd);
return; return;
@ -211,10 +177,9 @@ class HIDDeviceUdev final : public IHIDDevice
/* Get report descriptor */ /* Get report descriptor */
hidraw_report_descriptor reportDesc; hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize; reportDesc.size = reportDescSize;
if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1) if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1) {
{ snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESC) %s@%s: %s\n", device->m_token.getProductName().data(), dp,
snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESC) %s@%s: %s\n", strerror(errno));
device->m_token.getProductName().data(), dp, strerror(errno));
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
close(fd); close(fd);
return; return;
@ -224,21 +189,17 @@ class HIDDeviceUdev final : public IHIDDevice
/* Start transfer loop */ /* Start transfer loop */
device->m_devImp->initialCycle(); device->m_devImp->initialCycle();
while (device->m_runningTransferLoop) while (device->m_runningTransferLoop) {
{
fd_set readset; fd_set readset;
FD_ZERO(&readset); FD_ZERO(&readset);
FD_SET(fd, &readset); FD_SET(fd, &readset);
struct timeval timeout = {0, 10000}; struct timeval timeout = {0, 10000};
if (select(fd + 1, &readset, nullptr, nullptr, &timeout) > 0) if (select(fd + 1, &readset, nullptr, nullptr, &timeout) > 0) {
{ while (true) {
while (true)
{
ssize_t sz = read(fd, readBuf.get(), readSz); ssize_t sz = read(fd, readBuf.get(), readSz);
if (sz < 0) if (sz < 0)
break; break;
device->m_devImp->receivedHIDReport(readBuf.get(), sz, device->m_devImp->receivedHIDReport(readBuf.get(), sz, HIDReportType::Input, readBuf[0]);
HIDReportType::Input, readBuf[0]);
} }
} }
if (device->m_runningTransferLoop) if (device->m_runningTransferLoop)
@ -252,13 +213,9 @@ class HIDDeviceUdev final : public IHIDDevice
udev_device_unref(udevDev); udev_device_unref(udevDev);
} }
void _deviceDisconnected() void _deviceDisconnected() { m_runningTransferLoop = false; }
{
m_runningTransferLoop = false;
}
std::vector<uint8_t> _getReportDescriptor() std::vector<uint8_t> _getReportDescriptor() {
{
/* Report descriptor size */ /* Report descriptor size */
int reportDescSize; int reportDescSize;
if (ioctl(m_devFd, HIDIOCGRDESCSIZE, &reportDescSize) == -1) if (ioctl(m_devFd, HIDIOCGRDESCSIZE, &reportDescSize) == -1)
@ -274,19 +231,14 @@ class HIDDeviceUdev final : public IHIDDevice
return ret; return ret;
} }
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
{ if (m_devFd) {
if (m_devFd) if (tp == HIDReportType::Feature) {
{
if (tp == HIDReportType::Feature)
{
int ret = ioctl(m_devFd, HIDIOCSFEATURE(length), data); int ret = ioctl(m_devFd, HIDIOCSFEATURE(length), data);
if (ret < 0) if (ret < 0)
return false; return false;
return true; return true;
} } else if (tp == HIDReportType::Output) {
else if (tp == HIDReportType::Output)
{
ssize_t ret = write(m_devFd, data, length); ssize_t ret = write(m_devFd, data, length);
if (ret < 0) if (ret < 0)
return false; return false;
@ -296,12 +248,9 @@ class HIDDeviceUdev final : public IHIDDevice
return false; return false;
} }
size_t _receiveHIDReport(uint8_t *data, size_t length, HIDReportType tp, uint32_t message) size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
{ if (m_devFd) {
if (m_devFd) if (tp == HIDReportType::Feature) {
{
if (tp == HIDReportType::Feature)
{
data[0] = message; data[0] = message;
int ret = ioctl(m_devFd, HIDIOCGFEATURE(length), data); int ret = ioctl(m_devFd, HIDIOCGFEATURE(length), data);
if (ret < 0) if (ret < 0)
@ -313,16 +262,10 @@ class HIDDeviceUdev final : public IHIDDevice
} }
public: public:
HIDDeviceUdev(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) HIDDeviceUdev(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token), : m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {}
m_devImp(devImp),
m_devPath(token.getDevicePath())
{
}
void _startThread() void _startThread() {
{
std::unique_lock<std::mutex> lk(m_initMutex); std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType(); DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB) if (dType == DeviceType::USB)
@ -331,27 +274,22 @@ public:
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this())); m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else if (dType == DeviceType::HID) else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this())); m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else else {
{
fprintf(stderr, "invalid token supplied to device constructor"); fprintf(stderr, "invalid token supplied to device constructor");
abort(); abort();
} }
m_initCond.wait(lk); m_initCond.wait(lk);
} }
~HIDDeviceUdev() ~HIDDeviceUdev() {
{
m_runningTransferLoop = false; m_runningTransferLoop = false;
if (m_thread.joinable()) if (m_thread.joinable())
m_thread.detach(); m_thread.detach();
} }
}; };
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
{
return std::make_shared<HIDDeviceUdev>(token, devImp); return std::make_shared<HIDDeviceUdev>(token, devImp);
} }
} } // namespace boo

View File

@ -21,11 +21,9 @@
#undef min #undef min
#undef max #undef max
namespace boo namespace boo {
{
class HIDDeviceWinUSB final : public IHIDDevice class HIDDeviceWinUSB final : public IHIDDevice {
{
DeviceToken& m_token; DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp; std::shared_ptr<DeviceBase> m_devImp;
@ -41,13 +39,10 @@ class HIDDeviceWinUSB final : public IHIDDevice
std::condition_variable m_initCond; std::condition_variable m_initCond;
std::thread m_thread; std::thread m_thread;
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) {
{ if (m_usbHandle) {
if (m_usbHandle)
{
ULONG lengthTransferred = 0; ULONG lengthTransferred = 0;
if (!WinUsb_WritePipe(m_usbHandle, m_usbIntfOutPipe, (PUCHAR)data, if (!WinUsb_WritePipe(m_usbHandle, m_usbIntfOutPipe, (PUCHAR)data, (ULONG)length, &lengthTransferred, NULL) ||
(ULONG)length, &lengthTransferred, NULL) ||
lengthTransferred != length) lengthTransferred != length)
return false; return false;
return true; return true;
@ -55,37 +50,27 @@ class HIDDeviceWinUSB final : public IHIDDevice
return false; return false;
} }
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) {
{ if (m_usbHandle) {
if (m_usbHandle)
{
ULONG lengthTransferred = 0; ULONG lengthTransferred = 0;
if (!WinUsb_ReadPipe(m_usbHandle, m_usbIntfInPipe, (PUCHAR)data, if (!WinUsb_ReadPipe(m_usbHandle, m_usbIntfInPipe, (PUCHAR)data, (ULONG)length, &lengthTransferred, NULL))
(ULONG)length, &lengthTransferred, NULL))
return 0; return 0;
return lengthTransferred; return lengthTransferred;
} }
return 0; return 0;
} }
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceWinUSB> device) static void _threadProcUSBLL(std::shared_ptr<HIDDeviceWinUSB> device) {
{
unsigned i; unsigned i;
char errStr[256]; char errStr[256];
std::unique_lock<std::mutex> lk(device->m_initMutex); std::unique_lock<std::mutex> lk(device->m_initMutex);
/* POSIX.. who needs it?? -MS */ /* POSIX.. who needs it?? -MS */
device->m_devHandle = CreateFileA(device->m_devPath.data(), device->m_devHandle =
GENERIC_WRITE | GENERIC_READ, CreateFileA(device->m_devPath.data(), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
FILE_SHARE_WRITE | FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
NULL, if (INVALID_HANDLE_VALUE == device->m_devHandle) {
OPEN_EXISTING, _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().data(),
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == device->m_devHandle)
{
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
device->m_token.getProductName().data(),
device->m_devPath.data(), GetLastError()); device->m_devPath.data(), GetLastError());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
lk.unlock(); lk.unlock();
@ -93,10 +78,8 @@ class HIDDeviceWinUSB final : public IHIDDevice
return; return;
} }
if (!WinUsb_Initialize(device->m_devHandle, &device->m_usbHandle)) if (!WinUsb_Initialize(device->m_devHandle, &device->m_usbHandle)) {
{ _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().data(),
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
device->m_token.getProductName().data(),
device->m_devPath.data(), GetLastError()); device->m_devPath.data(), GetLastError());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
lk.unlock(); lk.unlock();
@ -107,10 +90,8 @@ class HIDDeviceWinUSB final : public IHIDDevice
/* Enumerate device pipes */ /* Enumerate device pipes */
USB_INTERFACE_DESCRIPTOR ifDesc = {0}; USB_INTERFACE_DESCRIPTOR ifDesc = {0};
if (!WinUsb_QueryInterfaceSettings(device->m_usbHandle, 0, &ifDesc)) if (!WinUsb_QueryInterfaceSettings(device->m_usbHandle, 0, &ifDesc)) {
{ _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().data(),
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
device->m_token.getProductName().data(),
device->m_devPath.data(), GetLastError()); device->m_devPath.data(), GetLastError());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
lk.unlock(); lk.unlock();
@ -118,12 +99,10 @@ class HIDDeviceWinUSB final : public IHIDDevice
CloseHandle(device->m_devHandle); CloseHandle(device->m_devHandle);
return; return;
} }
for (i=0 ; i<ifDesc.bNumEndpoints ; ++i) for (i = 0; i < ifDesc.bNumEndpoints; ++i) {
{
WINUSB_PIPE_INFORMATION pipeDesc; WINUSB_PIPE_INFORMATION pipeDesc;
WinUsb_QueryPipe(device->m_usbHandle, 0, i, &pipeDesc); WinUsb_QueryPipe(device->m_usbHandle, 0, i, &pipeDesc);
if (pipeDesc.PipeType == UsbdPipeTypeInterrupt) if (pipeDesc.PipeType == UsbdPipeTypeInterrupt) {
{
if (USB_ENDPOINT_DIRECTION_IN(pipeDesc.PipeId)) if (USB_ENDPOINT_DIRECTION_IN(pipeDesc.PipeId))
device->m_usbIntfInPipe = pipeDesc.PipeId; device->m_usbIntfInPipe = pipeDesc.PipeId;
else else
@ -148,8 +127,7 @@ class HIDDeviceWinUSB final : public IHIDDevice
device->m_devHandle = 0; device->m_devHandle = 0;
} }
static void _threadProcBTLL(std::shared_ptr<HIDDeviceWinUSB> device) static void _threadProcBTLL(std::shared_ptr<HIDDeviceWinUSB> device) {
{
std::unique_lock<std::mutex> lk(device->m_initMutex); std::unique_lock<std::mutex> lk(device->m_initMutex);
/* Return control to main thread */ /* Return control to main thread */
@ -170,24 +148,17 @@ class HIDDeviceWinUSB final : public IHIDDevice
PHIDP_PREPARSED_DATA m_preparsedData = nullptr; PHIDP_PREPARSED_DATA m_preparsedData = nullptr;
static void _threadProcHID(std::shared_ptr<HIDDeviceWinUSB> device) static void _threadProcHID(std::shared_ptr<HIDDeviceWinUSB> device) {
{
char errStr[256]; char errStr[256];
std::unique_lock<std::mutex> lk(device->m_initMutex); std::unique_lock<std::mutex> lk(device->m_initMutex);
/* POSIX.. who needs it?? -MS */ /* POSIX.. who needs it?? -MS */
device->m_overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); device->m_overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
device->m_hidHandle = CreateFileA(device->m_devPath.data(), device->m_hidHandle =
GENERIC_WRITE | GENERIC_READ, CreateFileA(device->m_devPath.data(), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
FILE_SHARE_WRITE | FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
NULL, if (INVALID_HANDLE_VALUE == device->m_hidHandle) {
OPEN_EXISTING, _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().data(),
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == device->m_hidHandle)
{
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
device->m_token.getProductName().data(),
device->m_devPath.data(), GetLastError()); device->m_devPath.data(), GetLastError());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
lk.unlock(); lk.unlock();
@ -195,10 +166,8 @@ class HIDDeviceWinUSB final : public IHIDDevice
return; return;
} }
if (!HidD_GetPreparsedData(device->m_hidHandle, &device->m_preparsedData)) if (!HidD_GetPreparsedData(device->m_hidHandle, &device->m_preparsedData)) {
{ _snprintf(errStr, 256, "Unable get preparsed data of %s@%s: %d\n", device->m_token.getProductName().data(),
_snprintf(errStr, 256, "Unable get preparsed data of %s@%s: %d\n",
device->m_token.getProductName().data(),
device->m_devPath.data(), GetLastError()); device->m_devPath.data(), GetLastError());
device->m_devImp->deviceError(errStr); device->m_devImp->deviceError(errStr);
lk.unlock(); lk.unlock();
@ -223,8 +192,7 @@ class HIDDeviceWinUSB final : public IHIDDevice
/* Start transfer loop */ /* Start transfer loop */
device->m_devImp->initialCycle(); device->m_devImp->initialCycle();
while (device->m_runningTransferLoop) while (device->m_runningTransferLoop) {
{
device->ReadCycle(readBuf.get(), inBufferSz); device->ReadCycle(readBuf.get(), inBufferSz);
if (device->m_runningTransferLoop) if (device->m_runningTransferLoop)
device->m_devImp->transferCycle(); device->m_devImp->transferCycle();
@ -238,21 +206,14 @@ class HIDDeviceWinUSB final : public IHIDDevice
device->m_hidHandle = nullptr; device->m_hidHandle = nullptr;
} }
void _deviceDisconnected() void _deviceDisconnected() { m_runningTransferLoop = false; }
{
m_runningTransferLoop = false;
}
std::vector<uint8_t> m_sendBuf; std::vector<uint8_t> m_sendBuf;
std::vector<uint8_t> m_recvBuf; std::vector<uint8_t> m_recvBuf;
const PHIDP_PREPARSED_DATA _getReportDescriptor() const PHIDP_PREPARSED_DATA _getReportDescriptor() { return m_preparsedData; }
{
return m_preparsedData;
}
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
{
size_t maxOut = std::max(m_minFeatureSz, std::max(m_minOutputSz, length)); size_t maxOut = std::max(m_minFeatureSz, std::max(m_minOutputSz, length));
if (m_sendBuf.size() < maxOut) if (m_sendBuf.size() < maxOut)
m_sendBuf.resize(maxOut); m_sendBuf.resize(maxOut);
@ -260,43 +221,35 @@ class HIDDeviceWinUSB final : public IHIDDevice
memset(m_sendBuf.data() + length, 0, maxOut - length); memset(m_sendBuf.data() + length, 0, maxOut - length);
memmove(m_sendBuf.data(), data, length); memmove(m_sendBuf.data(), data, length);
if (tp == HIDReportType::Output) if (tp == HIDReportType::Output) {
{
DWORD useLength = DWORD(std::max(length, m_minOutputSz)); DWORD useLength = DWORD(std::max(length, m_minOutputSz));
DWORD BytesWritten; DWORD BytesWritten;
OVERLAPPED Overlapped; OVERLAPPED Overlapped;
ZeroMemory(&Overlapped, sizeof(Overlapped)); ZeroMemory(&Overlapped, sizeof(Overlapped));
BOOL Result = WriteFile(m_hidHandle, m_sendBuf.data(), useLength, &BytesWritten, &Overlapped); BOOL Result = WriteFile(m_hidHandle, m_sendBuf.data(), useLength, &BytesWritten, &Overlapped);
if (!Result) if (!Result) {
{
DWORD Error = GetLastError(); DWORD Error = GetLastError();
if (Error == ERROR_INVALID_USER_BUFFER) if (Error == ERROR_INVALID_USER_BUFFER) {
{
// std::cout << "Falling back to SetOutputReport" << std::endl; // std::cout << "Falling back to SetOutputReport" << std::endl;
if (!HidD_SetOutputReport(m_hidHandle, (PVOID)m_sendBuf.data(), useLength)) if (!HidD_SetOutputReport(m_hidHandle, (PVOID)m_sendBuf.data(), useLength))
return false; return false;
} }
if (Error != ERROR_IO_PENDING) if (Error != ERROR_IO_PENDING) {
{
fprintf(stderr, "Write Failed %08X\n", int(Error)); fprintf(stderr, "Write Failed %08X\n", int(Error));
return false; return false;
} }
} }
if (!GetOverlappedResult(m_hidHandle, &Overlapped, &BytesWritten, TRUE)) if (!GetOverlappedResult(m_hidHandle, &Overlapped, &BytesWritten, TRUE)) {
{
DWORD Error = GetLastError(); DWORD Error = GetLastError();
fprintf(stderr, "Write Failed %08X\n", int(Error)); fprintf(stderr, "Write Failed %08X\n", int(Error));
return false; return false;
} }
} } else if (tp == HIDReportType::Feature) {
else if (tp == HIDReportType::Feature)
{
DWORD useLength = DWORD(std::max(length, m_minFeatureSz)); DWORD useLength = DWORD(std::max(length, m_minFeatureSz));
if (!HidD_SetFeature(m_hidHandle, (PVOID)m_sendBuf.data(), useLength)) if (!HidD_SetFeature(m_hidHandle, (PVOID)m_sendBuf.data(), useLength)) {
{
// int error = GetLastError(); // int error = GetLastError();
return false; return false;
} }
@ -304,22 +257,17 @@ class HIDDeviceWinUSB final : public IHIDDevice
return true; return true;
} }
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
{
size_t maxIn = std::max(m_minFeatureSz, std::max(m_minInputSz, length)); size_t maxIn = std::max(m_minFeatureSz, std::max(m_minInputSz, length));
if (m_recvBuf.size() < maxIn) if (m_recvBuf.size() < maxIn)
m_recvBuf.resize(maxIn); m_recvBuf.resize(maxIn);
memset(m_recvBuf.data(), 0, length); memset(m_recvBuf.data(), 0, length);
m_recvBuf[0] = message; m_recvBuf[0] = message;
if (tp == HIDReportType::Input) if (tp == HIDReportType::Input) {
{
if (!HidD_GetInputReport(m_hidHandle, m_recvBuf.data(), ULONG(std::max(m_minInputSz, length)))) if (!HidD_GetInputReport(m_hidHandle, m_recvBuf.data(), ULONG(std::max(m_minInputSz, length))))
return 0; return 0;
} } else if (tp == HIDReportType::Feature) {
else if (tp == HIDReportType::Feature)
{
if (!HidD_GetFeature(m_hidHandle, m_recvBuf.data(), ULONG(std::max(m_minFeatureSz, length)))) if (!HidD_GetFeature(m_hidHandle, m_recvBuf.data(), ULONG(std::max(m_minFeatureSz, length))))
return 0; return 0;
} }
@ -329,16 +277,10 @@ class HIDDeviceWinUSB final : public IHIDDevice
} }
public: public:
HIDDeviceWinUSB(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) HIDDeviceWinUSB(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token), : m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {}
m_devImp(devImp),
m_devPath(token.getDevicePath())
{
}
void _startThread() void _startThread() {
{
std::unique_lock<std::mutex> lk(m_initMutex); std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType(); DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB) if (dType == DeviceType::USB)
@ -352,8 +294,7 @@ public:
m_initCond.wait(lk); m_initCond.wait(lk);
} }
~HIDDeviceWinUSB() ~HIDDeviceWinUSB() {
{
m_runningTransferLoop = false; m_runningTransferLoop = false;
if (m_thread.joinable()) if (m_thread.joinable())
m_thread.detach(); m_thread.detach();
@ -361,27 +302,20 @@ public:
OVERLAPPED m_overlapped = {}; OVERLAPPED m_overlapped = {};
void ReadCycle(uint8_t* inBuffer, size_t inBufferSz) void ReadCycle(uint8_t* inBuffer, size_t inBufferSz) {
{
ResetEvent(m_overlapped.hEvent); ResetEvent(m_overlapped.hEvent);
ZeroMemory(inBuffer, inBufferSz); ZeroMemory(inBuffer, inBufferSz);
DWORD BytesRead = 0; DWORD BytesRead = 0;
BOOL Result = ReadFile(m_hidHandle, inBuffer, DWORD(inBufferSz), &BytesRead, &m_overlapped); BOOL Result = ReadFile(m_hidHandle, inBuffer, DWORD(inBufferSz), &BytesRead, &m_overlapped);
if (!Result) if (!Result) {
{
DWORD Error = GetLastError(); DWORD Error = GetLastError();
if (Error == ERROR_DEVICE_NOT_CONNECTED) if (Error == ERROR_DEVICE_NOT_CONNECTED) {
{
m_runningTransferLoop = false; m_runningTransferLoop = false;
return; return;
} } else if (Error != ERROR_IO_PENDING) {
else if (Error != ERROR_IO_PENDING)
{
fprintf(stderr, "Read Failed: %08X\n", int(Error)); fprintf(stderr, "Read Failed: %08X\n", int(Error));
return; return;
} } else if (!GetOverlappedResultEx(m_hidHandle, &m_overlapped, &BytesRead, 10, TRUE)) {
else if (!GetOverlappedResultEx(m_hidHandle, &m_overlapped, &BytesRead, 10, TRUE))
{
return; return;
} }
} }
@ -390,9 +324,8 @@ public:
} }
}; };
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
{
return std::make_shared<HIDDeviceWinUSB>(token, devImp); return std::make_shared<HIDDeviceWinUSB>(token, devImp);
} }
} } // namespace boo

View File

@ -2,11 +2,9 @@
#include "boo/inputdev/DeviceToken.hpp" #include "boo/inputdev/DeviceToken.hpp"
#include "boo/inputdev/DeviceBase.hpp" #include "boo/inputdev/DeviceBase.hpp"
namespace boo namespace boo {
{
class HIDDeviceBSD final : public IHIDDevice class HIDDeviceBSD final : public IHIDDevice {
{
DeviceToken& m_token; DeviceToken& m_token;
DeviceBase& m_devImp; DeviceBase& m_devImp;
@ -15,20 +13,14 @@ class HIDDeviceBSD final : public IHIDDevice
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { return 0; } size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { return 0; }
bool _sendHIDReport(const uint8_t* data, size_t length, uint16_t message) { return false; } bool _sendHIDReport(const uint8_t* data, size_t length, uint16_t message) { return false; }
size_t _recieveReport(const uint8_t* data, size_t length, uint16_t message) { return 0; } size_t _recieveReport(const uint8_t* data, size_t length, uint16_t message) { return 0; }
public:
HIDDeviceBSD(DeviceToken& token, DeviceBase& devImp)
: m_token(token),
m_devImp(devImp)
{
}
~HIDDeviceBSD() public:
{ HIDDeviceBSD(DeviceToken& token, DeviceBase& devImp) : m_token(token), m_devImp(devImp) {}
}
~HIDDeviceBSD() {}
}; };
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
{
return std::make_shared<HIDDeviceBSD>(token, devImp); return std::make_shared<HIDDeviceBSD>(token, devImp);
} }
} } // namespace boo

View File

@ -11,24 +11,20 @@
#include "IOKitPointer.hpp" #include "IOKitPointer.hpp"
#include "../CFPointer.hpp" #include "../CFPointer.hpp"
namespace boo namespace boo {
{
/* /*
* Reference: http://oroboro.com/usb-serial-number-osx/ * Reference: http://oroboro.com/usb-serial-number-osx/
*/ */
static bool getUSBStringDescriptor(const IUnknownPointer<IOUSBDeviceInterface182>& usbDevice, UInt8 idx, char* out) static bool getUSBStringDescriptor(const IUnknownPointer<IOUSBDeviceInterface182>& usbDevice, UInt8 idx, char* out) {
{
UInt16 buffer[128]; UInt16 buffer[128];
// wow... we're actually forced to make hard coded bus requests. Its like // wow... we're actually forced to make hard coded bus requests. Its like
// hard disk programming in the 80's! // hard disk programming in the 80's!
IOUSBDevRequest request; IOUSBDevRequest request;
request.bmRequestType = USBmakebmRequestType(kUSBIn, request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
kUSBStandard,
kUSBDevice);
request.bRequest = kUSBRqGetDescriptor; request.bRequest = kUSBRqGetDescriptor;
request.wValue = (kUSBStringDesc << 8) | idx; request.wValue = (kUSBStringDesc << 8) | idx;
request.wIndex = 0x409; // english request.wIndex = 0x409; // english
@ -36,8 +32,7 @@ static bool getUSBStringDescriptor(const IUnknownPointer<IOUSBDeviceInterface182
request.pData = buffer; request.pData = buffer;
kern_return_t err = usbDevice->DeviceRequest(usbDevice.storage(), &request); kern_return_t err = usbDevice->DeviceRequest(usbDevice.storage(), &request);
if (err != 0) if (err != 0) {
{
// the request failed... fairly uncommon for the USB disk driver, but not // the request failed... fairly uncommon for the USB disk driver, but not
// so uncommon for other devices. This can also be less reliable if your // so uncommon for other devices. This can also be less reliable if your
// disk is mounted through an external USB hub. At this level we actually // disk is mounted through an external USB hub. At this level we actually
@ -60,8 +55,7 @@ static bool getUSBStringDescriptor(const IUnknownPointer<IOUSBDeviceInterface182
return true; return true;
} }
class HIDListenerIOKit : public IHIDListener class HIDListenerIOKit : public IHIDListener {
{
DeviceFinder& m_finder; DeviceFinder& m_finder;
CFRunLoopRef m_listenerRunLoop; CFRunLoopRef m_listenerRunLoop;
@ -71,17 +65,13 @@ class HIDListenerIOKit : public IHIDListener
const char* m_usbClass; const char* m_usbClass;
bool m_scanningEnabled; bool m_scanningEnabled;
static void devicesConnectedUSBLL(HIDListenerIOKit* listener, static void devicesConnectedUSBLL(HIDListenerIOKit* listener, io_iterator_t iterator) {
io_iterator_t iterator) while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) {
{
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator))
{
io_string_t devPath; io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0) if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue; continue;
if (!listener->m_scanningEnabled || if (!listener->m_scanningEnabled || listener->m_finder._hasToken(devPath))
listener->m_finder._hasToken(devPath))
continue; continue;
UInt16 vid, pid; UInt16 vid, pid;
@ -91,17 +81,16 @@ class HIDListenerIOKit : public IHIDListener
IOCFPluginPointer devServ; IOCFPluginPointer devServ;
SInt32 score; SInt32 score;
IOReturn err; IOReturn err;
err = IOCreatePlugInInterfaceForService(obj.get(), kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &devServ, &score); err = IOCreatePlugInInterfaceForService(obj.get(), kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
if (err != kIOReturnSuccess) &devServ, &score);
{ if (err != kIOReturnSuccess) {
fprintf(stderr, "unable to open IOKit plugin interface\n"); fprintf(stderr, "unable to open IOKit plugin interface\n");
continue; continue;
} }
IUnknownPointer<IOUSBDeviceInterface182> dev; IUnknownPointer<IOUSBDeviceInterface182> dev;
err = devServ.As(&dev, kIOUSBDeviceInterfaceID182); err = devServ.As(&dev, kIOUSBDeviceInterfaceID182);
if (err != kIOReturnSuccess) if (err != kIOReturnSuccess) {
{
fprintf(stderr, "unable to open IOKit device interface\n"); fprintf(stderr, "unable to open IOKit device interface\n");
continue; continue;
} }
@ -117,26 +106,20 @@ class HIDListenerIOKit : public IHIDListener
getUSBStringDescriptor(dev, pstridx, pstr); getUSBStringDescriptor(dev, pstridx, pstr);
} }
listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::USB, listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::USB, vid, pid, vstr, pstr, devPath));
vid, pid, vstr, pstr, devPath));
// printf("ADDED %08X %s\n", obj.get(), devPath); // printf("ADDED %08X %s\n", obj.get(), devPath);
} }
} }
static void devicesDisconnectedUSBLL(HIDListenerIOKit* listener, static void devicesDisconnectedUSBLL(HIDListenerIOKit* listener, io_iterator_t iterator) {
io_iterator_t iterator) if (CFRunLoopGetCurrent() != listener->m_listenerRunLoop) {
{ CFRunLoopPerformBlock(listener->m_listenerRunLoop, kCFRunLoopDefaultMode,
if (CFRunLoopGetCurrent() != listener->m_listenerRunLoop) ^{ devicesDisconnectedUSBLL(listener, iterator); });
{
CFRunLoopPerformBlock(listener->m_listenerRunLoop, kCFRunLoopDefaultMode, ^{
devicesDisconnectedUSBLL(listener, iterator);
});
CFRunLoopWakeUp(listener->m_listenerRunLoop); CFRunLoopWakeUp(listener->m_listenerRunLoop);
return; return;
} }
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) {
{
io_string_t devPath; io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0) if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue; continue;
@ -145,17 +128,13 @@ class HIDListenerIOKit : public IHIDListener
} }
} }
static void devicesConnectedHID(HIDListenerIOKit* listener, static void devicesConnectedHID(HIDListenerIOKit* listener, io_iterator_t iterator) {
io_iterator_t iterator) while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) {
{
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator))
{
io_string_t devPath; io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0) if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue; continue;
if (!listener->m_scanningEnabled || if (!listener->m_scanningEnabled || listener->m_finder._hasToken(devPath))
listener->m_finder._hasToken(devPath))
continue; continue;
unsigned vidv, pidv; unsigned vidv, pidv;
@ -165,17 +144,16 @@ class HIDListenerIOKit : public IHIDListener
IOCFPluginPointer devServ; IOCFPluginPointer devServ;
SInt32 score; SInt32 score;
IOReturn err; IOReturn err;
err = IOCreatePlugInInterfaceForService(obj.get(), kIOHIDDeviceTypeID, kIOCFPlugInInterfaceID, &devServ, &score); err =
if (err != kIOReturnSuccess) IOCreatePlugInInterfaceForService(obj.get(), kIOHIDDeviceTypeID, kIOCFPlugInInterfaceID, &devServ, &score);
{ if (err != kIOReturnSuccess) {
fprintf(stderr, "unable to open IOKit plugin interface\n"); fprintf(stderr, "unable to open IOKit plugin interface\n");
continue; continue;
} }
IUnknownPointer<IOHIDDeviceDeviceInterface> dev; IUnknownPointer<IOHIDDeviceDeviceInterface> dev;
err = devServ.As(&dev, kIOHIDDeviceDeviceInterfaceID); err = devServ.As(&dev, kIOHIDDeviceDeviceInterfaceID);
if (err != kIOReturnSuccess) if (err != kIOReturnSuccess) {
{
fprintf(stderr, "unable to open IOKit device interface\n"); fprintf(stderr, "unable to open IOKit device interface\n");
continue; continue;
} }
@ -188,13 +166,10 @@ class HIDListenerIOKit : public IHIDListener
int usagePageV, usageV; int usagePageV, usageV;
CFNumberGetValue(usagePage.get(), kCFNumberIntType, &usagePageV); CFNumberGetValue(usagePage.get(), kCFNumberIntType, &usagePageV);
CFNumberGetValue(usage.get(), kCFNumberIntType, &usageV); CFNumberGetValue(usage.get(), kCFNumberIntType, &usageV);
if (usagePageV == kHIDPage_GenericDesktop) if (usagePageV == kHIDPage_GenericDesktop) {
{
if (usageV != kHIDUsage_GD_Joystick && usageV != kHIDUsage_GD_GamePad) if (usageV != kHIDUsage_GD_Joystick && usageV != kHIDUsage_GD_GamePad)
continue; continue;
} } else {
else
{
continue; continue;
} }
@ -214,26 +189,20 @@ class HIDListenerIOKit : public IHIDListener
CFStringGetCString(pstridx.get(), pstr, 128, kCFStringEncodingUTF8); CFStringGetCString(pstridx.get(), pstr, 128, kCFStringEncodingUTF8);
} }
listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::HID, listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::HID, vidv, pidv, vstr, pstr, devPath));
vidv, pidv, vstr, pstr, devPath));
// printf("ADDED %08X %s\n", obj, devPath); // printf("ADDED %08X %s\n", obj, devPath);
} }
} }
static void devicesDisconnectedHID(HIDListenerIOKit* listener, static void devicesDisconnectedHID(HIDListenerIOKit* listener, io_iterator_t iterator) {
io_iterator_t iterator) if (CFRunLoopGetCurrent() != listener->m_listenerRunLoop) {
{ CFRunLoopPerformBlock(listener->m_listenerRunLoop, kCFRunLoopDefaultMode,
if (CFRunLoopGetCurrent() != listener->m_listenerRunLoop) ^{ devicesDisconnectedHID(listener, iterator); });
{
CFRunLoopPerformBlock(listener->m_listenerRunLoop, kCFRunLoopDefaultMode, ^{
devicesDisconnectedHID(listener, iterator);
});
CFRunLoopWakeUp(listener->m_listenerRunLoop); CFRunLoopWakeUp(listener->m_listenerRunLoop);
return; return;
} }
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) {
{
io_string_t devPath; io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0) if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue; continue;
@ -243,9 +212,7 @@ class HIDListenerIOKit : public IHIDListener
} }
public: public:
HIDListenerIOKit(DeviceFinder& finder) HIDListenerIOKit(DeviceFinder& finder) : m_finder(finder) {
: m_finder(finder)
{
struct utsname kernInfo; struct utsname kernInfo;
uname(&kernInfo); uname(&kernInfo);
int release = atoi(kernInfo.release); int release = atoi(kernInfo.release);
@ -296,41 +263,33 @@ public:
m_scanningEnabled = false; m_scanningEnabled = false;
} }
~HIDListenerIOKit() ~HIDListenerIOKit() {
{
// CFRunLoopRemoveSource(m_listenerRunLoop, IONotificationPortGetRunLoopSource(m_llPort), kCFRunLoopDefaultMode); // CFRunLoopRemoveSource(m_listenerRunLoop, IONotificationPortGetRunLoopSource(m_llPort), kCFRunLoopDefaultMode);
IONotificationPortDestroy(m_llPort); IONotificationPortDestroy(m_llPort);
} }
/* Automatic device scanning */ /* Automatic device scanning */
bool startScanning() bool startScanning() {
{
m_scanningEnabled = true; m_scanningEnabled = true;
return true; return true;
} }
bool stopScanning() bool stopScanning() {
{
m_scanningEnabled = false; m_scanningEnabled = false;
return true; return true;
} }
/* Manual device scanning */ /* Manual device scanning */
bool scanNow() bool scanNow() {
{
IOObjectPointer<io_iterator_t> iter; IOObjectPointer<io_iterator_t> iter;
if (IOServiceGetMatchingServices(kIOMasterPortDefault, if (IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(m_usbClass), &iter) == kIOReturnSuccess) {
IOServiceMatching(m_usbClass), &iter) == kIOReturnSuccess)
{
devicesConnectedUSBLL(this, iter.get()); devicesConnectedUSBLL(this, iter.get());
} }
return true; return true;
} }
}; };
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) {
{
return std::make_unique<HIDListenerIOKit>(finder); return std::make_unique<HIDListenerIOKit>(finder);
} }
} } // namespace boo

View File

@ -1,25 +1,18 @@
#include "boo/inputdev/IHIDListener.hpp" #include "boo/inputdev/IHIDListener.hpp"
namespace boo namespace boo {
{
class HIDListenerNX : public IHIDListener class HIDListenerNX : public IHIDListener {
{
DeviceFinder& m_finder; DeviceFinder& m_finder;
public: public:
HIDListenerNX(DeviceFinder& finder) HIDListenerNX(DeviceFinder& finder) : m_finder(finder) {}
: m_finder(finder)
{}
bool startScanning() { return false; } bool startScanning() { return false; }
bool stopScanning() { return false; } bool stopScanning() { return false; }
bool scanNow() { return false; } bool scanNow() { return false; }
}; };
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) { return std::make_unique<HIDListenerNX>(finder); }
{
return std::make_unique<HIDListenerNX>(finder);
}
} } // namespace boo

View File

@ -2,11 +2,9 @@
#include "boo/inputdev/IHIDListener.hpp" #include "boo/inputdev/IHIDListener.hpp"
#include "boo/inputdev/DeviceFinder.hpp" #include "boo/inputdev/DeviceFinder.hpp"
namespace boo namespace boo {
{
class HIDListenerUWP : public IHIDListener class HIDListenerUWP : public IHIDListener {
{
public: public:
HIDListenerUWP(DeviceFinder& finder) {} HIDListenerUWP(DeviceFinder& finder) {}
@ -18,9 +16,6 @@ public:
bool scanNow() { return false; } bool scanNow() { return false; }
}; };
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) { return std::make_unique<HIDListenerUWP>(finder); }
{
return std::make_unique<HIDListenerUWP>(finder);
}
} } // namespace boo

View File

@ -12,27 +12,23 @@
#include <unistd.h> #include <unistd.h>
#include <thread> #include <thread>
namespace boo namespace boo {
{
static udev* UDEV_INST = nullptr; static udev* UDEV_INST = nullptr;
udev* GetUdev() udev* GetUdev() {
{
if (!UDEV_INST) if (!UDEV_INST)
UDEV_INST = udev_new(); UDEV_INST = udev_new();
return UDEV_INST; return UDEV_INST;
} }
class HIDListenerUdev final : public IHIDListener class HIDListenerUdev final : public IHIDListener {
{
DeviceFinder& m_finder; DeviceFinder& m_finder;
udev_monitor* m_udevMon; udev_monitor* m_udevMon;
std::thread m_udevThread; std::thread m_udevThread;
bool m_scanningEnabled; bool m_scanningEnabled;
void deviceConnected(udev_device* device) void deviceConnected(udev_device* device) {
{
if (!m_scanningEnabled) if (!m_scanningEnabled)
return; return;
@ -47,8 +43,7 @@ class HIDListenerUdev final : public IHIDListener
int vid = 0, pid = 0; int vid = 0, pid = 0;
const char* manuf = nullptr; const char* manuf = nullptr;
const char* product = nullptr; const char* product = nullptr;
if (dt) if (dt) {
{
if (!strcmp(dt, "usb_device")) if (!strcmp(dt, "usb_device"))
type = DeviceType::USB; type = DeviceType::USB;
else if (!strcmp(dt, "bluetooth_device")) else if (!strcmp(dt, "bluetooth_device"))
@ -72,16 +67,13 @@ class HIDListenerUdev final : public IHIDListener
udev_list_entry* producte = udev_list_entry_get_by_name(attrs, "ID_MODEL"); udev_list_entry* producte = udev_list_entry_get_by_name(attrs, "ID_MODEL");
if (producte) if (producte)
product = udev_list_entry_get_value(producte); product = udev_list_entry_get_value(producte);
} } else if (!strcmp(udev_device_get_subsystem(device), "hidraw")) {
else if (!strcmp(udev_device_get_subsystem(device), "hidraw"))
{
type = DeviceType::HID; type = DeviceType::HID;
udev_device* parent = udev_device_get_parent(device); udev_device* parent = udev_device_get_parent(device);
udev_list_entry* attrs = udev_device_get_properties_list_entry(parent); udev_list_entry* attrs = udev_device_get_properties_list_entry(parent);
udev_list_entry* hidide = udev_list_entry_get_by_name(attrs, "HID_ID"); udev_list_entry* hidide = udev_list_entry_get_by_name(attrs, "HID_ID");
if (hidide) if (hidide) {
{
const char* hidid = udev_list_entry_get_value(hidide); const char* hidid = udev_list_entry_get_value(hidide);
const char* vids = strchr(hidid, ':') + 1; const char* vids = strchr(hidid, ':') + 1;
const char* pids = strchr(vids, ':') + 1; const char* pids = strchr(vids, ':') + 1;
@ -90,8 +82,7 @@ class HIDListenerUdev final : public IHIDListener
} }
udev_list_entry* hidnamee = udev_list_entry_get_by_name(attrs, "HID_NAME"); udev_list_entry* hidnamee = udev_list_entry_get_by_name(attrs, "HID_NAME");
if (hidnamee) if (hidnamee) {
{
product = udev_list_entry_get_value(hidnamee); product = udev_list_entry_get_value(hidnamee);
manuf = product; manuf = product;
} }
@ -104,8 +95,7 @@ class HIDListenerUdev final : public IHIDListener
/* Report descriptor size */ /* Report descriptor size */
int reportDescSize; int reportDescSize;
if (ioctl(fd, HIDIOCGRDESCSIZE, &reportDescSize) == -1) if (ioctl(fd, HIDIOCGRDESCSIZE, &reportDescSize) == -1) {
{
// const char* err = strerror(errno); // const char* err = strerror(errno);
close(fd); close(fd);
return; return;
@ -114,16 +104,14 @@ class HIDListenerUdev final : public IHIDListener
/* Get report descriptor */ /* Get report descriptor */
hidraw_report_descriptor reportDesc; hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize; reportDesc.size = reportDescSize;
if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1) if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1) {
{
// const char* err = strerror(errno); // const char* err = strerror(errno);
close(fd); close(fd);
return; return;
} }
close(fd); close(fd);
std::pair<HIDUsagePage, HIDUsage> usage = std::pair<HIDUsagePage, HIDUsage> usage = HIDParser::GetApplicationUsage(reportDesc.value, reportDesc.size);
HIDParser::GetApplicationUsage(reportDesc.value, reportDesc.size);
if (usage.first != HIDUsagePage::GenericDesktop || if (usage.first != HIDUsagePage::GenericDesktop ||
(usage.second != HIDUsage::Joystick && usage.second != HIDUsage::GamePad)) (usage.second != HIDUsage::Joystick && usage.second != HIDUsage::GamePad))
return; return;
@ -143,24 +131,20 @@ class HIDListenerUdev final : public IHIDListener
m_finder._insertToken(std::make_unique<DeviceToken>(type, vid, pid, manuf, product, devPath)); m_finder._insertToken(std::make_unique<DeviceToken>(type, vid, pid, manuf, product, devPath));
} }
void deviceDisconnected(udev_device* device) void deviceDisconnected(udev_device* device) {
{
const char* devPath = udev_device_get_syspath(device); const char* devPath = udev_device_get_syspath(device);
m_finder._removeToken(devPath); m_finder._removeToken(devPath);
} }
void _udevProc() void _udevProc() {
{
logvisor::RegisterThreadName("Boo udev"); logvisor::RegisterThreadName("Boo udev");
udev_monitor_enable_receiving(m_udevMon); udev_monitor_enable_receiving(m_udevMon);
int fd = udev_monitor_get_fd(m_udevMon); int fd = udev_monitor_get_fd(m_udevMon);
while (true) while (true) {
{
fd_set fds; fd_set fds;
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(fd, &fds); FD_SET(fd, &fds);
if (pselect(fd+1, &fds, nullptr, nullptr, nullptr, nullptr) < 0) if (pselect(fd + 1, &fds, nullptr, nullptr, nullptr, nullptr) < 0) {
{
/* SIGTERM handled here */ /* SIGTERM handled here */
if (errno == EINTR) if (errno == EINTR)
break; break;
@ -168,8 +152,7 @@ class HIDListenerUdev final : public IHIDListener
int oldtype; int oldtype;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldtype); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldtype);
udev_device* dev = udev_monitor_receive_device(m_udevMon); udev_device* dev = udev_monitor_receive_device(m_udevMon);
if (dev) if (dev) {
{
const char* action = udev_device_get_action(dev); const char* action = udev_device_get_action(dev);
if (!strcmp(action, "add")) if (!strcmp(action, "add"))
deviceConnected(dev); deviceConnected(dev);
@ -183,13 +166,10 @@ class HIDListenerUdev final : public IHIDListener
} }
public: public:
HIDListenerUdev(DeviceFinder& finder) HIDListenerUdev(DeviceFinder& finder) : m_finder(finder) {
: m_finder(finder)
{
/* Setup hotplug events */ /* Setup hotplug events */
m_udevMon = udev_monitor_new_from_netlink(GetUdev(), "udev"); m_udevMon = udev_monitor_new_from_netlink(GetUdev(), "udev");
if (!m_udevMon) if (!m_udevMon) {
{
fprintf(stderr, "unable to init udev_monitor"); fprintf(stderr, "unable to init udev_monitor");
abort(); abort();
} }
@ -207,8 +187,7 @@ public:
m_udevThread = std::thread(std::bind(&HIDListenerUdev::_udevProc, this), this); m_udevThread = std::thread(std::bind(&HIDListenerUdev::_udevProc, this), this);
} }
~HIDListenerUdev() ~HIDListenerUdev() {
{
pthread_cancel(m_udevThread.native_handle()); pthread_cancel(m_udevThread.native_handle());
if (m_udevThread.joinable()) if (m_udevThread.joinable())
m_udevThread.join(); m_udevThread.join();
@ -216,20 +195,17 @@ public:
} }
/* Automatic device scanning */ /* Automatic device scanning */
bool startScanning() bool startScanning() {
{
m_scanningEnabled = true; m_scanningEnabled = true;
return true; return true;
} }
bool stopScanning() bool stopScanning() {
{
m_scanningEnabled = false; m_scanningEnabled = false;
return true; return true;
} }
/* Manual device scanning */ /* Manual device scanning */
bool scanNow() bool scanNow() {
{
udev_enumerate* uenum = udev_enumerate_new(GetUdev()); udev_enumerate* uenum = udev_enumerate_new(GetUdev());
udev_enumerate_add_match_subsystem(uenum, "usb"); udev_enumerate_add_match_subsystem(uenum, "usb");
udev_enumerate_add_match_subsystem(uenum, "bluetooth"); udev_enumerate_add_match_subsystem(uenum, "bluetooth");
@ -237,8 +213,7 @@ public:
udev_enumerate_scan_devices(uenum); udev_enumerate_scan_devices(uenum);
udev_list_entry* uenumList = udev_enumerate_get_list_entry(uenum); udev_list_entry* uenumList = udev_enumerate_get_list_entry(uenum);
udev_list_entry* uenumItem; udev_list_entry* uenumItem;
udev_list_entry_foreach(uenumItem, uenumList) udev_list_entry_foreach(uenumItem, uenumList) {
{
const char* devPath = udev_list_entry_get_name(uenumItem); const char* devPath = udev_list_entry_get_name(uenumItem);
udev_device* dev = udev_device_new_from_syspath(UDEV_INST, devPath); udev_device* dev = udev_device_new_from_syspath(UDEV_INST, devPath);
if (dev) if (dev)
@ -248,12 +223,10 @@ public:
udev_enumerate_unref(uenum); udev_enumerate_unref(uenum);
return true; return true;
} }
}; };
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) {
{
return std::make_unique<HIDListenerUdev>(finder); return std::make_unique<HIDListenerUdev>(finder);
} }
} } // namespace boo

View File

@ -18,11 +18,9 @@
#include <hidclass.h> #include <hidclass.h>
#include <Xinput.h> #include <Xinput.h>
namespace boo namespace boo {
{
class HIDListenerWinUSB final : public IHIDListener class HIDListenerWinUSB final : public IHIDListener {
{
DeviceFinder& m_finder; DeviceFinder& m_finder;
bool m_scanningEnabled; bool m_scanningEnabled;
@ -31,8 +29,7 @@ class HIDListenerWinUSB final : public IHIDListener
* Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c * Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c
*/ */
void _enumerate(DeviceType type, CONST GUID* TypeGUID, const char* pathFilter) void _enumerate(DeviceType type, CONST GUID* TypeGUID, const char* pathFilter) {
{
/* Don't ask */ /* Don't ask */
static const LPCSTR arPrefix[3] = {"VID_", "PID_", "MI_"}; static const LPCSTR arPrefix[3] = {"VID_", "PID_", "MI_"};
unsigned i, j; unsigned i, j;
@ -58,22 +55,13 @@ class HIDListenerWinUSB final : public IHIDListener
if (hDevInfo == INVALID_HANDLE_VALUE) if (hDevInfo == INVALID_HANDLE_VALUE)
return; return;
for (i=0 ; ; ++i) for (i = 0;; ++i) {
{ if (!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, TypeGUID, i, &DeviceInterfaceData))
if (!SetupDiEnumDeviceInterfaces(hDevInfo,
NULL,
TypeGUID,
i,
&DeviceInterfaceData))
break; break;
DeviceInterfaceDetailData.wtf.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); DeviceInterfaceDetailData.wtf.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetailA(hDevInfo, if (!SetupDiGetDeviceInterfaceDetailA(hDevInfo, &DeviceInterfaceData, &DeviceInterfaceDetailData.wtf,
&DeviceInterfaceData, sizeof(DeviceInterfaceDetailData), NULL, &DeviceInfoData))
&DeviceInterfaceDetailData.wtf,
sizeof(DeviceInterfaceDetailData),
NULL,
&DeviceInfoData))
continue; continue;
r = CM_Get_Device_IDA(DeviceInfoData.DevInst, szDeviceInstanceID, MAX_PATH, 0); r = CM_Get_Device_IDA(DeviceInfoData.DevInst, szDeviceInstanceID, MAX_PATH, 0);
@ -85,14 +73,10 @@ class HIDListenerWinUSB final : public IHIDListener
szVid[0] = '\0'; szVid[0] = '\0';
szPid[0] = '\0'; szPid[0] = '\0';
szMi[0] = '\0'; szMi[0] = '\0';
while (pszToken != NULL) while (pszToken != NULL) {
{ for (j = 0; j < 3; ++j) {
for (j=0 ; j<3 ; ++j) if (strncmp(pszToken, arPrefix[j], 4) == 0) {
{ switch (j) {
if (strncmp(pszToken, arPrefix[j], 4) == 0)
{
switch (j)
{
case 0: case 0:
strcpy_s(szVid, MAX_DEVICE_ID_LEN, pszToken); strcpy_s(szVid, MAX_DEVICE_ID_LEN, pszToken);
break; break;
@ -119,11 +103,11 @@ class HIDListenerWinUSB final : public IHIDListener
CHAR productW[1024] = {0}; CHAR productW[1024] = {0};
// CHAR product[1024] = {0}; // CHAR product[1024] = {0};
DWORD productSz = 0; DWORD productSz = 0;
if (!SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, if (!SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devpropType,
&devpropType, (BYTE*)productW, 1024, &productSz, 0)) { (BYTE*)productW, 1024, &productSz, 0)) {
/* fallback to SPDRP_DEVICEDESC (USB hubs still use it) */ /* fallback to SPDRP_DEVICEDESC (USB hubs still use it) */
SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC, SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC, &reg_type, (BYTE*)productW, 1024,
&reg_type, (BYTE*)productW, 1024, &productSz); &productSz);
} }
/* DAFUQ??? Why isn't this really WCHAR??? */ /* DAFUQ??? Why isn't this really WCHAR??? */
// WideCharToMultiByte(CP_UTF8, 0, productW, -1, product, 1024, nullptr, nullptr); // WideCharToMultiByte(CP_UTF8, 0, productW, -1, product, 1024, nullptr, nullptr);
@ -131,24 +115,18 @@ class HIDListenerWinUSB final : public IHIDListener
WCHAR manufW[1024] = L"Someone"; /* Windows Vista and earlier will use this as the vendor */ WCHAR manufW[1024] = L"Someone"; /* Windows Vista and earlier will use this as the vendor */
CHAR manuf[1024] = {0}; CHAR manuf[1024] = {0};
DWORD manufSz = 0; DWORD manufSz = 0;
SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_Manufacturer, SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_Manufacturer, &devpropType, (BYTE*)manufW,
&devpropType, (BYTE*)manufW, 1024, &manufSz, 0); 1024, &manufSz, 0);
WideCharToMultiByte(CP_UTF8, 0, manufW, -1, manuf, 1024, nullptr, nullptr); WideCharToMultiByte(CP_UTF8, 0, manufW, -1, manuf, 1024, nullptr, nullptr);
if (type == DeviceType::HID) if (type == DeviceType::HID) {
{ HANDLE devHnd = CreateFileA(DeviceInterfaceDetailData.wtf.DevicePath, GENERIC_WRITE | GENERIC_READ,
HANDLE devHnd = CreateFileA(DeviceInterfaceDetailData.wtf.DevicePath, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING,
GENERIC_WRITE | GENERIC_READ, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == devHnd) if (INVALID_HANDLE_VALUE == devHnd)
continue; continue;
PHIDP_PREPARSED_DATA preparsedData; PHIDP_PREPARSED_DATA preparsedData;
if (!HidD_GetPreparsedData(devHnd, &preparsedData)) if (!HidD_GetPreparsedData(devHnd, &preparsedData)) {
{
CloseHandle(devHnd); CloseHandle(devHnd);
continue; continue;
} }
@ -172,75 +150,59 @@ class HIDListenerWinUSB final : public IHIDListener
continue; continue;
/* Whew!! that's a single device enumerated!! */ /* Whew!! that's a single device enumerated!! */
m_finder._insertToken(std::make_unique<DeviceToken>( m_finder._insertToken(
type, vid, pid, manuf, productW, std::make_unique<DeviceToken>(type, vid, pid, manuf, productW, DeviceInterfaceDetailData.wtf.DevicePath));
DeviceInterfaceDetailData.wtf.DevicePath));
} }
SetupDiDestroyDeviceInfoList(hDevInfo); SetupDiDestroyDeviceInfoList(hDevInfo);
} }
void _pollDevices(const char* pathFilter) void _pollDevices(const char* pathFilter) {
{
_enumerate(DeviceType::HID, &GUID_DEVINTERFACE_HID, pathFilter); _enumerate(DeviceType::HID, &GUID_DEVINTERFACE_HID, pathFilter);
_enumerate(DeviceType::USB, &GUID_DEVINTERFACE_USB_DEVICE, pathFilter); _enumerate(DeviceType::USB, &GUID_DEVINTERFACE_USB_DEVICE, pathFilter);
} }
static XInputPadState ConvertXInputState(const XINPUT_GAMEPAD& pad) static XInputPadState ConvertXInputState(const XINPUT_GAMEPAD& pad) {
{ return {pad.wButtons, pad.bLeftTrigger, pad.bRightTrigger, pad.sThumbLX, pad.sThumbLY, pad.sThumbLY, pad.sThumbRY};
return {pad.wButtons, pad.bLeftTrigger, pad.bRightTrigger,
pad.sThumbLX, pad.sThumbLY, pad.sThumbLY, pad.sThumbRY};
} }
std::thread m_xinputThread; std::thread m_xinputThread;
bool m_xinputRunning = true; bool m_xinputRunning = true;
DWORD m_xinputPackets[4] = {DWORD(-1), DWORD(-1), DWORD(-1), DWORD(-1)}; DWORD m_xinputPackets[4] = {DWORD(-1), DWORD(-1), DWORD(-1), DWORD(-1)};
std::vector<DeviceToken> m_xinputTokens; std::vector<DeviceToken> m_xinputTokens;
void _xinputProc() void _xinputProc() {
{
m_xinputTokens.reserve(4); m_xinputTokens.reserve(4);
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
m_xinputTokens.emplace_back(DeviceType::XInput, 0, i, "", "", ""); m_xinputTokens.emplace_back(DeviceType::XInput, 0, i, "", "", "");
while (m_xinputRunning) while (m_xinputRunning) {
{ for (int i = 0; i < 4; ++i) {
for (int i=0 ; i<4 ; ++i)
{
DeviceToken& tok = m_xinputTokens[i]; DeviceToken& tok = m_xinputTokens[i];
XINPUT_STATE state; XINPUT_STATE state;
if (XInputGetState(i, &state) == ERROR_SUCCESS) if (XInputGetState(i, &state) == ERROR_SUCCESS) {
{ if (state.dwPacketNumber != m_xinputPackets[i]) {
if (state.dwPacketNumber != m_xinputPackets[i])
{
if (m_xinputPackets[i] == -1) if (m_xinputPackets[i] == -1)
m_finder.deviceConnected(tok); m_finder.deviceConnected(tok);
m_xinputPackets[i] = state.dwPacketNumber; m_xinputPackets[i] = state.dwPacketNumber;
if (tok.m_connectedDev) if (tok.m_connectedDev) {
{
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev); XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
std::lock_guard<std::mutex> lk(pad.m_callbackLock); std::lock_guard<std::mutex> lk(pad.m_callbackLock);
if (pad.m_callback) if (pad.m_callback)
pad.m_callback->controllerUpdate(pad, ConvertXInputState(state.Gamepad)); pad.m_callback->controllerUpdate(pad, ConvertXInputState(state.Gamepad));
} }
} }
if (tok.m_connectedDev) if (tok.m_connectedDev) {
{
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev); XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
if (pad.m_rumbleRequest[0] != pad.m_rumbleState[0] || if (pad.m_rumbleRequest[0] != pad.m_rumbleState[0] || pad.m_rumbleRequest[1] != pad.m_rumbleState[1]) {
pad.m_rumbleRequest[1] != pad.m_rumbleState[1])
{
pad.m_rumbleState[0] = pad.m_rumbleRequest[0]; pad.m_rumbleState[0] = pad.m_rumbleRequest[0];
pad.m_rumbleState[1] = pad.m_rumbleRequest[1]; pad.m_rumbleState[1] = pad.m_rumbleRequest[1];
XINPUT_VIBRATION vibe = {pad.m_rumbleRequest[0], pad.m_rumbleRequest[1]}; XINPUT_VIBRATION vibe = {pad.m_rumbleRequest[0], pad.m_rumbleRequest[1]};
XInputSetState(i, &vibe); XInputSetState(i, &vibe);
} }
} }
} } else if (m_xinputPackets[i] != -1) {
else if (m_xinputPackets[i] != -1)
{
m_xinputPackets[i] = -1; m_xinputPackets[i] = -1;
if (tok.m_connectedDev) if (tok.m_connectedDev) {
{
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev); XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
pad.deviceDisconnected(); pad.deviceDisconnected();
} }
@ -252,51 +214,42 @@ class HIDListenerWinUSB final : public IHIDListener
} }
public: public:
HIDListenerWinUSB(DeviceFinder& finder) HIDListenerWinUSB(DeviceFinder& finder) : m_finder(finder) {
: m_finder(finder)
{
/* Initial HID Device Add */ /* Initial HID Device Add */
_pollDevices(nullptr); _pollDevices(nullptr);
/* XInput arbitration thread */ /* XInput arbitration thread */
for (const DeviceSignature* sig : m_finder.getTypes()) for (const DeviceSignature* sig : m_finder.getTypes()) {
{ if (sig->m_type == DeviceType::XInput) {
if (sig->m_type == DeviceType::XInput)
{
m_xinputThread = std::thread(std::bind(&HIDListenerWinUSB::_xinputProc, this)); m_xinputThread = std::thread(std::bind(&HIDListenerWinUSB::_xinputProc, this));
break; break;
} }
} }
} }
~HIDListenerWinUSB() ~HIDListenerWinUSB() {
{
m_xinputRunning = false; m_xinputRunning = false;
if (m_xinputThread.joinable()) if (m_xinputThread.joinable())
m_xinputThread.join(); m_xinputThread.join();
} }
/* Automatic device scanning */ /* Automatic device scanning */
bool startScanning() bool startScanning() {
{
m_scanningEnabled = true; m_scanningEnabled = true;
return true; return true;
} }
bool stopScanning() bool stopScanning() {
{
m_scanningEnabled = false; m_scanningEnabled = false;
return true; return true;
} }
/* Manual device scanning */ /* Manual device scanning */
bool scanNow() bool scanNow() {
{
_pollDevices(nullptr); _pollDevices(nullptr);
return true; return true;
} }
bool _extDevConnect(const char* path) bool _extDevConnect(const char* path) {
{
char upperPath[1024]; char upperPath[1024];
strcpy_s(upperPath, 1024, path); strcpy_s(upperPath, 1024, path);
CharUpperA(upperPath); CharUpperA(upperPath);
@ -305,8 +258,7 @@ public:
return true; return true;
} }
bool _extDevDisconnect(const char* path) bool _extDevDisconnect(const char* path) {
{
char upperPath[1024]; char upperPath[1024];
strcpy_s(upperPath, 1024, path); strcpy_s(upperPath, 1024, path);
CharUpperA(upperPath); CharUpperA(upperPath);
@ -315,9 +267,8 @@ public:
} }
}; };
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) {
{
return std::make_unique<HIDListenerWinUSB>(finder); return std::make_unique<HIDListenerWinUSB>(finder);
} }
} } // namespace boo

View File

@ -5,34 +5,17 @@
#undef min #undef min
#undef max #undef max
namespace boo namespace boo {
{
/* Based on "Device Class Definition for Human Interface Devices (HID)" /* Based on "Device Class Definition for Human Interface Devices (HID)"
* http://www.usb.org/developers/hidpage/HID1_11.pdf * http://www.usb.org/developers/hidpage/HID1_11.pdf
*/ */
static const char* UsagePageNames[] = static const char* UsagePageNames[] = {"Undefined", "Generic Desktop", "Simulation", "VR", "Sport",
{ "Game Controls", "Generic Device", "Keyboard", "LEDs", "Button",
"Undefined", "Ordinal", "Telephony", "Consumer", "Digitizer"};
"Generic Desktop",
"Simulation",
"VR",
"Sport",
"Game Controls",
"Generic Device",
"Keyboard",
"LEDs",
"Button",
"Ordinal",
"Telephony",
"Consumer",
"Digitizer"
};
static const char* GenericDesktopUsages[] = static const char* GenericDesktopUsages[] = {"Undefined",
{
"Undefined",
"Pointer", "Pointer",
"Mouse", "Mouse",
"Reserved", "Reserved",
@ -42,13 +25,44 @@ static const char* GenericDesktopUsages[] =
"Keypad", "Keypad",
"Multi-axis Controller", "Multi-axis Controller",
"Tablet PC System Controls", "Tablet PC System Controls",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"X", "X",
"Y", "Y",
"Z", "Z",
@ -74,16 +88,61 @@ static const char* GenericDesktopUsages[] =
"Vno", "Vno",
"Feature Notification", "Feature Notification",
"Resolution Multiplier", "Resolution Multiplier",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"System Control", "System Control",
"System Power Down", "System Power Down",
"System Sleep", "System Sleep",
@ -104,8 +163,18 @@ static const char* GenericDesktopUsages[] =
"D-pad Down", "D-pad Down",
"D-pad Right", "D-pad Right",
"D-pad Left", "D-pad Left",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"System Dock", "System Dock",
"System Undock", "System Undock",
"System Setup", "System Setup",
@ -115,26 +184,52 @@ static const char* GenericDesktopUsages[] =
"Application Debugger Break", "Application Debugger Break",
"System Speaker Mute", "System Speaker Mute",
"System Hibernate", "System Hibernate",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"System Display Invert", "System Display Invert",
"System Display Internal", "System Display Internal",
"System Display External", "System Display External",
"System Display Both", "System Display Both",
"System Display Dual", "System Display Dual",
"System Display Toggle Int/Ext" "System Display Toggle Int/Ext"};
};
static const char* GameUsages[] = static const char* GameUsages[] = {"Undefined",
{
"Undefined",
"3D Game Controller", "3D Game Controller",
"Pinball Device", "Pinball Device",
"Gun Device", "Gun Device",
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"Point of View", "Point of View",
"Turn Right/Left", "Turn Right/Left",
"Pitch Forward/Backward", "Pitch Forward/Backward",
@ -160,11 +255,9 @@ static const char* GameUsages[] =
"Gun Safety", "Gun Safety",
"Gemepad Fire/Jump", "Gemepad Fire/Jump",
nullptr, nullptr,
"Gamepad Trigger" "Gamepad Trigger"};
};
enum class HIDCollectionType : uint8_t enum class HIDCollectionType : uint8_t {
{
Physical, Physical,
Application, Application,
Logical, Logical,
@ -174,16 +267,9 @@ enum class HIDCollectionType : uint8_t
UsageModifier UsageModifier
}; };
enum class HIDItemType : uint8_t enum class HIDItemType : uint8_t { Main, Global, Local, Reserved };
{
Main,
Global,
Local,
Reserved
};
enum class HIDItemTag : uint8_t enum class HIDItemTag : uint8_t {
{
/* [6.2.2.4] Main Items */ /* [6.2.2.4] Main Items */
Input = 0b1000, Input = 0b1000,
Output = 0b1001, Output = 0b1001,
@ -218,8 +304,7 @@ enum class HIDItemTag : uint8_t
Delimiter = 0b1010, Delimiter = 0b1010,
}; };
struct HIDItemState struct HIDItemState {
{
/* [6.2.2.7] Global items */ /* [6.2.2.7] Global items */
HIDUsagePage m_usagePage = HIDUsagePage::Undefined; HIDUsagePage m_usagePage = HIDUsagePage::Undefined;
HIDRange m_logicalRange = {}; HIDRange m_logicalRange = {};
@ -241,8 +326,7 @@ struct HIDItemState
std::vector<int32_t> m_delimiter; std::vector<int32_t> m_delimiter;
#endif #endif
void ResetLocalItems() void ResetLocalItems() {
{
m_usage.clear(); m_usage.clear();
m_usageRange = HIDRange(); m_usageRange = HIDRange();
#if 0 #if 0
@ -255,8 +339,7 @@ struct HIDItemState
} }
template <typename T> template <typename T>
static T _GetLocal(const std::vector<T>& v, uint32_t idx) static T _GetLocal(const std::vector<T>& v, uint32_t idx) {
{
if (v.empty()) if (v.empty())
return {}; return {};
if (idx >= v.size()) if (idx >= v.size())
@ -264,52 +347,46 @@ struct HIDItemState
return v[idx]; return v[idx];
} }
HIDUsage GetUsage(uint32_t idx) const HIDUsage GetUsage(uint32_t idx) const {
{
if (m_usageRange.second - m_usageRange.first != 0) if (m_usageRange.second - m_usageRange.first != 0)
return HIDUsage(m_usageRange.first + idx); return HIDUsage(m_usageRange.first + idx);
return _GetLocal(m_usage, idx); return _GetLocal(m_usage, idx);
} }
}; };
struct HIDCollectionItem struct HIDCollectionItem {
{
/* [6.2.2.6] Collection, End Collection Items */ /* [6.2.2.6] Collection, End Collection Items */
HIDCollectionType m_type; HIDCollectionType m_type;
HIDUsagePage m_usagePage; HIDUsagePage m_usagePage;
HIDUsage m_usage; HIDUsage m_usage;
HIDCollectionItem(HIDCollectionType type, const HIDItemState& state) HIDCollectionItem(HIDCollectionType type, const HIDItemState& state)
: m_type(type), m_usagePage(state.m_usagePage), m_usage(state.GetUsage(0)) : m_type(type), m_usagePage(state.m_usagePage), m_usage(state.GetUsage(0)) {}
{}
}; };
HIDMainItem::HIDMainItem(uint32_t flags, const HIDItemState& state, uint32_t reportIdx) HIDMainItem::HIDMainItem(uint32_t flags, const HIDItemState& state, uint32_t reportIdx) : m_flags(uint16_t(flags)) {
: m_flags(uint16_t(flags))
{
m_usagePage = state.m_usagePage; m_usagePage = state.m_usagePage;
m_usage = state.GetUsage(reportIdx); m_usage = state.GetUsage(reportIdx);
m_logicalRange = state.m_logicalRange; m_logicalRange = state.m_logicalRange;
m_reportSize = state.m_reportSize; m_reportSize = state.m_reportSize;
} }
HIDMainItem::HIDMainItem(uint32_t flags, HIDUsagePage usagePage, HIDUsage usage, HIDMainItem::HIDMainItem(uint32_t flags, HIDUsagePage usagePage, HIDUsage usage, HIDRange logicalRange,
HIDRange logicalRange, int32_t reportSize) int32_t reportSize)
: m_flags(uint16_t(flags)), m_usagePage(usagePage), m_usage(usage), : m_flags(uint16_t(flags))
m_logicalRange(logicalRange), m_reportSize(reportSize) , m_usagePage(usagePage)
{} , m_usage(usage)
, m_logicalRange(logicalRange)
, m_reportSize(reportSize) {}
const char* HIDMainItem::GetUsagePageName() const const char* HIDMainItem::GetUsagePageName() const {
{
if (int(m_usagePage) >= std::extent<decltype(UsagePageNames)>::value) if (int(m_usagePage) >= std::extent<decltype(UsagePageNames)>::value)
return nullptr; return nullptr;
return UsagePageNames[int(m_usagePage)]; return UsagePageNames[int(m_usagePage)];
} }
const char* HIDMainItem::GetUsageName() const const char* HIDMainItem::GetUsageName() const {
{ switch (m_usagePage) {
switch (m_usagePage)
{
case HIDUsagePage::GenericDesktop: case HIDUsagePage::GenericDesktop:
if (int(m_usage) >= std::extent<decltype(GenericDesktopUsages)>::value) if (int(m_usage) >= std::extent<decltype(GenericDesktopUsages)>::value)
return nullptr; return nullptr;
@ -323,14 +400,12 @@ const char* HIDMainItem::GetUsageName() const
} }
} }
struct HIDReports struct HIDReports {
{
std::map<int32_t, std::vector<HIDMainItem>> m_inputReports; std::map<int32_t, std::vector<HIDMainItem>> m_inputReports;
std::map<int32_t, std::vector<HIDMainItem>> m_outputReports; std::map<int32_t, std::vector<HIDMainItem>> m_outputReports;
std::map<int32_t, std::vector<HIDMainItem>> m_featureReports; std::map<int32_t, std::vector<HIDMainItem>> m_featureReports;
static void _AddItem(std::map<int32_t, std::vector<HIDMainItem>>& m, uint32_t flags, const HIDItemState& state) static void _AddItem(std::map<int32_t, std::vector<HIDMainItem>>& m, uint32_t flags, const HIDItemState& state) {
{
std::vector<HIDMainItem>& report = m[state.m_reportID]; std::vector<HIDMainItem>& report = m[state.m_reportID];
report.reserve(report.size() + state.m_reportCount); report.reserve(report.size() + state.m_reportCount);
for (int i = 0; i < state.m_reportCount; ++i) for (int i = 0; i < state.m_reportCount; ++i)
@ -344,8 +419,7 @@ struct HIDReports
#if _WIN32 #if _WIN32
#if !WINDOWS_STORE #if !WINDOWS_STORE
HIDParser::ParserStatus HIDParser::Parse(const PHIDP_PREPARSED_DATA descriptorData) HIDParser::ParserStatus HIDParser::Parse(const PHIDP_PREPARSED_DATA descriptorData) {
{
/* User mode HID report descriptor isn't available on Win32. /* User mode HID report descriptor isn't available on Win32.
* Opaque preparsed data must be enumerated and sorted into * Opaque preparsed data must be enumerated and sorted into
* iterable items. * iterable items.
@ -369,20 +443,14 @@ HIDParser::ParserStatus HIDParser::Parse(const PHIDP_PREPARSED_DATA descriptorDa
USHORT length = caps.NumberInputButtonCaps; USHORT length = caps.NumberInputButtonCaps;
std::vector<HIDP_BUTTON_CAPS> bCaps(caps.NumberInputButtonCaps, HIDP_BUTTON_CAPS()); std::vector<HIDP_BUTTON_CAPS> bCaps(caps.NumberInputButtonCaps, HIDP_BUTTON_CAPS());
HidP_GetButtonCaps(HidP_Input, bCaps.data(), &length, descriptorData); HidP_GetButtonCaps(HidP_Input, bCaps.data(), &length, descriptorData);
for (const HIDP_BUTTON_CAPS& caps : bCaps) for (const HIDP_BUTTON_CAPS& caps : bCaps) {
{ if (caps.IsRange) {
if (caps.IsRange)
{
int usage = caps.Range.UsageMin; int usage = caps.Range.UsageMin;
for (int i=caps.Range.DataIndexMin ; i<=caps.Range.DataIndexMax ; ++i, ++usage) for (int i = caps.Range.DataIndexMin; i <= caps.Range.DataIndexMax; ++i, ++usage) {
{ inputItems.insert(std::make_pair(
inputItems.insert(std::make_pair(i, i, HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(usage), std::make_pair(0, 1), 1)));
HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage),
HIDUsage(usage), std::make_pair(0, 1), 1)));
} }
} } else {
else
{
inputItems.insert(std::make_pair(caps.NotRange.DataIndex, inputItems.insert(std::make_pair(caps.NotRange.DataIndex,
HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage),
HIDUsage(caps.NotRange.Usage), std::make_pair(0, 1), 1))); HIDUsage(caps.NotRange.Usage), std::make_pair(0, 1), 1)));
@ -395,21 +463,17 @@ HIDParser::ParserStatus HIDParser::Parse(const PHIDP_PREPARSED_DATA descriptorDa
USHORT length = caps.NumberInputValueCaps; USHORT length = caps.NumberInputValueCaps;
std::vector<HIDP_VALUE_CAPS> vCaps(caps.NumberInputValueCaps, HIDP_VALUE_CAPS()); std::vector<HIDP_VALUE_CAPS> vCaps(caps.NumberInputValueCaps, HIDP_VALUE_CAPS());
HidP_GetValueCaps(HidP_Input, vCaps.data(), &length, descriptorData); HidP_GetValueCaps(HidP_Input, vCaps.data(), &length, descriptorData);
for (const HIDP_VALUE_CAPS& caps : vCaps) for (const HIDP_VALUE_CAPS& caps : vCaps) {
{ if (caps.IsRange) {
if (caps.IsRange)
{
int usage = caps.Range.UsageMin; int usage = caps.Range.UsageMin;
for (int i=caps.Range.DataIndexMin ; i<=caps.Range.DataIndexMax ; ++i, ++usage) for (int i = caps.Range.DataIndexMin; i <= caps.Range.DataIndexMax; ++i, ++usage) {
{ inputItems.insert(
inputItems.insert(std::make_pair(i, std::make_pair(i, HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(usage),
HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(usage),
std::make_pair(caps.LogicalMin, caps.LogicalMax), caps.BitSize))); std::make_pair(caps.LogicalMin, caps.LogicalMax), caps.BitSize)));
} }
} } else {
else inputItems.insert(
{ std::make_pair(caps.NotRange.DataIndex,
inputItems.insert(std::make_pair(caps.NotRange.DataIndex,
HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(caps.NotRange.Usage), HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(caps.NotRange.Usage),
HIDRange(caps.LogicalMin, caps.LogicalMax), caps.BitSize))); HIDRange(caps.LogicalMin, caps.LogicalMax), caps.BitSize)));
} }
@ -426,25 +490,18 @@ HIDParser::ParserStatus HIDParser::Parse(const PHIDP_PREPARSED_DATA descriptorDa
#endif #endif
#else #else
static HIDParser::ParserStatus static HIDParser::ParserStatus AdvanceIt(const uint8_t*& it, const uint8_t* end, size_t adv) {
AdvanceIt(const uint8_t*& it, const uint8_t* end, size_t adv)
{
it += adv; it += adv;
if (it > end) if (it > end) {
{
it = end; it = end;
return HIDParser::ParserStatus::Error; return HIDParser::ParserStatus::Error;
} } else if (it == end) {
else if (it == end)
{
return HIDParser::ParserStatus::Done; return HIDParser::ParserStatus::Done;
} }
return HIDParser::ParserStatus::OK; return HIDParser::ParserStatus::OK;
} }
static uint8_t static uint8_t GetByteValue(const uint8_t*& it, const uint8_t* end, HIDParser::ParserStatus& status) {
GetByteValue(const uint8_t*& it, const uint8_t* end, HIDParser::ParserStatus& status)
{
const uint8_t* oldIt = it; const uint8_t* oldIt = it;
status = AdvanceIt(it, end, 1); status = AdvanceIt(it, end, 1);
if (status == HIDParser::ParserStatus::Error) if (status == HIDParser::ParserStatus::Error)
@ -452,12 +509,9 @@ GetByteValue(const uint8_t*& it, const uint8_t* end, HIDParser::ParserStatus& st
return *oldIt; return *oldIt;
} }
static uint32_t static uint32_t GetShortValue(const uint8_t*& it, const uint8_t* end, int adv, HIDParser::ParserStatus& status) {
GetShortValue(const uint8_t*& it, const uint8_t* end, int adv, HIDParser::ParserStatus& status)
{
const uint8_t* oldIt = it; const uint8_t* oldIt = it;
switch (adv) switch (adv) {
{
case 1: case 1:
status = AdvanceIt(it, end, 1); status = AdvanceIt(it, end, 1);
if (status == HIDParser::ParserStatus::Error) if (status == HIDParser::ParserStatus::Error)
@ -479,17 +533,12 @@ GetShortValue(const uint8_t*& it, const uint8_t* end, int adv, HIDParser::Parser
return 0; return 0;
} }
HIDParser::ParserStatus HIDParser::ParserStatus HIDParser::ParseItem(HIDReports& reportsOut, std::stack<HIDItemState>& stateStack,
HIDParser::ParseItem(HIDReports& reportsOut, std::stack<HIDCollectionItem>& collectionStack, const uint8_t*& it,
std::stack<HIDItemState>& stateStack, const uint8_t* end, bool& multipleReports) {
std::stack<HIDCollectionItem>& collectionStack,
const uint8_t*& it, const uint8_t* end,
bool& multipleReports)
{
ParserStatus status = ParserStatus::OK; ParserStatus status = ParserStatus::OK;
uint8_t head = *it++; uint8_t head = *it++;
if (head == 0b11111110) if (head == 0b11111110) {
{
/* Long item */ /* Long item */
uint8_t bDataSize = GetByteValue(it, end, status); uint8_t bDataSize = GetByteValue(it, end, status);
if (status == ParserStatus::Error) if (status == ParserStatus::Error)
@ -500,19 +549,15 @@ HIDParser::ParseItem(HIDReports& reportsOut,
status = AdvanceIt(it, end, bDataSize); status = AdvanceIt(it, end, bDataSize);
if (status == ParserStatus::Error) if (status == ParserStatus::Error)
return ParserStatus::Error; return ParserStatus::Error;
} } else {
else
{
/* Short Item */ /* Short Item */
uint32_t data = GetShortValue(it, end, head & 0x3, status); uint32_t data = GetShortValue(it, end, head & 0x3, status);
if (status == ParserStatus::Error) if (status == ParserStatus::Error)
return ParserStatus::Error; return ParserStatus::Error;
switch (HIDItemType((head >> 2) & 0x3)) switch (HIDItemType((head >> 2) & 0x3)) {
{
case HIDItemType::Main: case HIDItemType::Main:
switch (HIDItemTag(head >> 4)) switch (HIDItemTag(head >> 4)) {
{
case HIDItemTag::Input: case HIDItemTag::Input:
reportsOut.AddInputItem(data, stateStack.top()); reportsOut.AddInputItem(data, stateStack.top());
break; break;
@ -536,8 +581,7 @@ HIDParser::ParseItem(HIDReports& reportsOut,
stateStack.top().ResetLocalItems(); stateStack.top().ResetLocalItems();
break; break;
case HIDItemType::Global: case HIDItemType::Global:
switch (HIDItemTag(head >> 4)) switch (HIDItemTag(head >> 4)) {
{
case HIDItemTag::UsagePage: case HIDItemTag::UsagePage:
stateStack.top().m_usagePage = HIDUsagePage(data); stateStack.top().m_usagePage = HIDUsagePage(data);
break; break;
@ -582,8 +626,7 @@ HIDParser::ParseItem(HIDReports& reportsOut,
} }
break; break;
case HIDItemType::Local: case HIDItemType::Local:
switch (HIDItemTag(head >> 4)) switch (HIDItemTag(head >> 4)) {
{
case HIDItemTag::Usage: case HIDItemTag::Usage:
stateStack.top().m_usage.push_back(HIDUsage(data)); stateStack.top().m_usage.push_back(HIDUsage(data));
break; break;
@ -608,14 +651,12 @@ HIDParser::ParseItem(HIDReports& reportsOut,
default: default:
return ParserStatus::Error; return ParserStatus::Error;
} }
} }
return it == end ? ParserStatus::Done : ParserStatus::OK; return it == end ? ParserStatus::Done : ParserStatus::OK;
} }
HIDParser::ParserStatus HIDParser::Parse(const uint8_t* descriptorData, size_t len) HIDParser::ParserStatus HIDParser::Parse(const uint8_t* descriptorData, size_t len) {
{
std::stack<HIDItemState> stateStack; std::stack<HIDItemState> stateStack;
stateStack.emplace(); stateStack.emplace();
std::stack<HIDCollectionItem> collectionStack; std::stack<HIDCollectionItem> collectionStack;
@ -623,16 +664,15 @@ HIDParser::ParserStatus HIDParser::Parse(const uint8_t* descriptorData, size_t l
const uint8_t* end = descriptorData + len; const uint8_t* end = descriptorData + len;
for (const uint8_t* it = descriptorData; it != end;) for (const uint8_t* it = descriptorData; it != end;)
if ((m_status = if ((m_status = ParseItem(reports, stateStack, collectionStack, it, end, m_multipleReports)) != ParserStatus::OK)
ParseItem(reports, stateStack, collectionStack, it, end, m_multipleReports)) != ParserStatus::OK)
break; break;
if (m_status != ParserStatus::Done) if (m_status != ParserStatus::Done)
return m_status; return m_status;
uint32_t itemCount = 0; uint32_t itemCount = 0;
uint32_t reportCount = uint32_t(reports.m_inputReports.size() + reports.m_outputReports.size() + uint32_t reportCount =
reports.m_featureReports.size()); uint32_t(reports.m_inputReports.size() + reports.m_outputReports.size() + reports.m_featureReports.size());
for (const auto& rep : reports.m_inputReports) for (const auto& rep : reports.m_inputReports)
itemCount += rep.second.size(); itemCount += rep.second.size();
@ -647,13 +687,10 @@ HIDParser::ParserStatus HIDParser::Parse(const uint8_t* descriptorData, size_t l
uint32_t itemIndex = 0; uint32_t itemIndex = 0;
uint32_t reportIndex = 0; uint32_t reportIndex = 0;
auto func = [&](std::pair<uint32_t, uint32_t>& out, const std::map<int32_t, std::vector<HIDMainItem>>& in) auto func = [&](std::pair<uint32_t, uint32_t>& out, const std::map<int32_t, std::vector<HIDMainItem>>& in) {
{
out = std::make_pair(reportIndex, reportIndex + in.size()); out = std::make_pair(reportIndex, reportIndex + in.size());
for (const auto& rep : in) for (const auto& rep : in) {
{ m_reportPool[reportIndex++] = std::make_pair(rep.first, std::make_pair(itemIndex, itemIndex + rep.second.size()));
m_reportPool[reportIndex++] =
std::make_pair(rep.first, std::make_pair(itemIndex, itemIndex + rep.second.size()));
for (const auto& item : rep.second) for (const auto& item : rep.second)
m_itemPool[itemIndex++] = item; m_itemPool[itemIndex++] = item;
} }
@ -665,8 +702,7 @@ HIDParser::ParserStatus HIDParser::Parse(const uint8_t* descriptorData, size_t l
return m_status; return m_status;
} }
size_t HIDParser::CalculateMaxInputReportSize(const uint8_t* descriptorData, size_t len) size_t HIDParser::CalculateMaxInputReportSize(const uint8_t* descriptorData, size_t len) {
{
std::stack<HIDItemState> stateStack; std::stack<HIDItemState> stateStack;
stateStack.emplace(); stateStack.emplace();
std::stack<HIDCollectionItem> collectionStack; std::stack<HIDCollectionItem> collectionStack;
@ -683,8 +719,7 @@ size_t HIDParser::CalculateMaxInputReportSize(const uint8_t* descriptorData, siz
return 0; return 0;
size_t maxSize = 0; size_t maxSize = 0;
for (const auto& rep : reports.m_inputReports) for (const auto& rep : reports.m_inputReports) {
{
size_t repSize = 0; size_t repSize = 0;
for (const auto& item : rep.second) for (const auto& item : rep.second)
repSize += item.m_reportSize; repSize += item.m_reportSize;
@ -695,8 +730,7 @@ size_t HIDParser::CalculateMaxInputReportSize(const uint8_t* descriptorData, siz
return (maxSize + 7) / 8 + multipleReports; return (maxSize + 7) / 8 + multipleReports;
} }
std::pair<HIDUsagePage, HIDUsage> HIDParser::GetApplicationUsage(const uint8_t* descriptorData, size_t len) std::pair<HIDUsagePage, HIDUsage> HIDParser::GetApplicationUsage(const uint8_t* descriptorData, size_t len) {
{
std::stack<HIDItemState> stateStack; std::stack<HIDItemState> stateStack;
stateStack.emplace(); stateStack.emplace();
std::stack<HIDCollectionItem> collectionStack; std::stack<HIDCollectionItem> collectionStack;
@ -705,8 +739,7 @@ std::pair<HIDUsagePage, HIDUsage> HIDParser::GetApplicationUsage(const uint8_t*
bool multipleReports = false; bool multipleReports = false;
const uint8_t* end = descriptorData + len; const uint8_t* end = descriptorData + len;
for (const uint8_t* it = descriptorData; it != end;) for (const uint8_t* it = descriptorData; it != end;) {
{
status = ParseItem(reports, stateStack, collectionStack, it, end, multipleReports); status = ParseItem(reports, stateStack, collectionStack, it, end, multipleReports);
if (collectionStack.empty()) if (collectionStack.empty())
continue; continue;
@ -721,14 +754,12 @@ std::pair<HIDUsagePage, HIDUsage> HIDParser::GetApplicationUsage(const uint8_t*
#endif #endif
#if _WIN32 #if _WIN32
void HIDParser::EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const void HIDParser::EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const {
{
#if !WINDOWS_STORE #if !WINDOWS_STORE
if (m_status != ParserStatus::Done) if (m_status != ParserStatus::Done)
return; return;
for (const HIDMainItem& item : m_itemPool) for (const HIDMainItem& item : m_itemPool) {
{
if (item.IsConstant()) if (item.IsConstant())
continue; continue;
if (!valueCB(item)) if (!valueCB(item))
@ -737,16 +768,13 @@ void HIDParser::EnumerateValues(const std::function<bool(const HIDMainItem& item
#endif #endif
} }
#else #else
void HIDParser::EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const void HIDParser::EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const {
{
if (m_status != ParserStatus::Done) if (m_status != ParserStatus::Done)
return; return;
for (uint32_t i=m_inputReports.first ; i<m_inputReports.second ; ++i) for (uint32_t i = m_inputReports.first; i < m_inputReports.second; ++i) {
{
const Report& rep = m_reportPool[i]; const Report& rep = m_reportPool[i];
for (uint32_t j=rep.second.first ; j<rep.second.second ; ++j) for (uint32_t j = rep.second.first; j < rep.second.second; ++j) {
{
const HIDMainItem& item = m_itemPool[j]; const HIDMainItem& item = m_itemPool[j];
if (item.IsConstant()) if (item.IsConstant())
continue; continue;
@ -759,30 +787,25 @@ void HIDParser::EnumerateValues(const std::function<bool(const HIDMainItem& item
#if _WIN32 #if _WIN32
void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB, void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB,
const uint8_t* data, size_t len) const const uint8_t* data, size_t len) const {
{
#if !WINDOWS_STORE #if !WINDOWS_STORE
if (m_status != ParserStatus::Done) if (m_status != ParserStatus::Done)
return; return;
ULONG dataLen = m_dataList.size(); ULONG dataLen = m_dataList.size();
if (HidP_GetData(HidP_Input, m_dataList.data(), &dataLen, if (HidP_GetData(HidP_Input, m_dataList.data(), &dataLen, m_descriptorData, PCHAR(data), len) != HIDP_STATUS_SUCCESS)
m_descriptorData, PCHAR(data), len) != HIDP_STATUS_SUCCESS)
return; return;
int idx = 0; int idx = 0;
auto it = m_dataList.begin(); auto it = m_dataList.begin();
auto end = m_dataList.begin() + dataLen; auto end = m_dataList.begin() + dataLen;
for (const HIDMainItem& item : m_itemPool) for (const HIDMainItem& item : m_itemPool) {
{
if (item.IsConstant()) if (item.IsConstant())
continue; continue;
int32_t value = 0; int32_t value = 0;
if (it != end) if (it != end) {
{
const HIDP_DATA& data = *it; const HIDP_DATA& data = *it;
if (data.DataIndex == idx) if (data.DataIndex == idx) {
{
value = data.RawValue; value = data.RawValue;
++it; ++it;
} }
@ -795,22 +818,18 @@ void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int
} }
#else #else
class BitwiseIterator class BitwiseIterator {
{
const uint8_t*& m_it; const uint8_t*& m_it;
const uint8_t* m_end; const uint8_t* m_end;
int m_bit = 0; int m_bit = 0;
public:
BitwiseIterator(const uint8_t*& it, const uint8_t* end)
: m_it(it), m_end(end) {}
uint32_t GetUnsignedValue(int numBits, HIDParser::ParserStatus& status) public:
{ BitwiseIterator(const uint8_t*& it, const uint8_t* end) : m_it(it), m_end(end) {}
uint32_t GetUnsignedValue(int numBits, HIDParser::ParserStatus& status) {
uint32_t val = 0; uint32_t val = 0;
for (int i=0 ; i<numBits ;) for (int i = 0; i < numBits;) {
{ if (m_it >= m_end) {
if (m_it >= m_end)
{
status = HIDParser::ParserStatus::Error; status = HIDParser::ParserStatus::Error;
return 0; return 0;
} }
@ -818,8 +837,7 @@ public:
val |= uint32_t((*m_it >> m_bit) & ((1 << remBits) - 1)) << i; val |= uint32_t((*m_it >> m_bit) & ((1 << remBits) - 1)) << i;
i += remBits; i += remBits;
m_bit += remBits; m_bit += remBits;
if (m_bit == 8) if (m_bit == 8) {
{
m_bit = 0; m_bit = 0;
AdvanceIt(m_it, m_end, 1); AdvanceIt(m_it, m_end, 1);
} }
@ -829,8 +847,7 @@ public:
}; };
void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB, void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB,
const uint8_t* data, size_t len) const const uint8_t* data, size_t len) const {
{
if (m_status != ParserStatus::Done) if (m_status != ParserStatus::Done)
return; return;
@ -845,13 +862,11 @@ void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int
BitwiseIterator bitIt(it, end); BitwiseIterator bitIt(it, end);
for (uint32_t i=m_inputReports.first ; i<m_inputReports.second ; ++i) for (uint32_t i = m_inputReports.first; i < m_inputReports.second; ++i) {
{
const Report& rep = m_reportPool[i]; const Report& rep = m_reportPool[i];
if (rep.first != reportId) if (rep.first != reportId)
continue; continue;
for (uint32_t j=rep.second.first ; j<rep.second.second ; ++j) for (uint32_t j = rep.second.first; j < rep.second.second; ++j) {
{
const HIDMainItem& item = m_itemPool[j]; const HIDMainItem& item = m_itemPool[j];
int32_t val = bitIt.GetUnsignedValue(item.m_reportSize, status); int32_t val = bitIt.GetUnsignedValue(item.m_reportSize, status);
if (status == ParserStatus::Error) if (status == ParserStatus::Error)
@ -866,4 +881,4 @@ void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int
} }
#endif #endif
} } // namespace boo

View File

@ -8,11 +8,9 @@
#include <hidsdi.h> #include <hidsdi.h>
#endif #endif
namespace boo namespace boo {
{
class IHIDDevice : public std::enable_shared_from_this<IHIDDevice> class IHIDDevice : public std::enable_shared_from_this<IHIDDevice> {
{
friend class DeviceBase; friend class DeviceBase;
friend struct DeviceSignature; friend struct DeviceSignature;
virtual void _deviceDisconnected() = 0; virtual void _deviceDisconnected() = 0;
@ -28,9 +26,9 @@ class IHIDDevice : public std::enable_shared_from_this<IHIDDevice>
virtual bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) = 0; virtual bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) = 0;
virtual size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) = 0; virtual size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) = 0;
virtual void _startThread() = 0; virtual void _startThread() = 0;
public: public:
virtual ~IHIDDevice() = default; virtual ~IHIDDevice() = default;
}; };
} } // namespace boo

View File

@ -42,15 +42,10 @@ public:
} }
} }
static inline IOObjectPointer<T> adopt(T ptr) { static inline IOObjectPointer<T> adopt(T ptr) { return IOObjectPointer<T>(ptr, IOObjectPointer<T>::Adopt); }
return IOObjectPointer<T>(ptr, IOObjectPointer<T>::Adopt);
}
T get() const { T get() const { return fromStorageType(storage); }
return fromStorageType(storage); io_object_t* operator&() {
}
io_object_t* operator&()
{
if (io_object_t pointer = storage) { if (io_object_t pointer = storage) {
IOObjectRelease(pointer); IOObjectRelease(pointer);
} }
@ -64,17 +59,11 @@ private:
enum AdoptTag { Adopt }; enum AdoptTag { Adopt };
IOObjectPointer(T ptr, AdoptTag) : storage(toStorageType(ptr)) {} IOObjectPointer(T ptr, AdoptTag) : storage(toStorageType(ptr)) {}
inline io_object_t toStorageType(io_object_t ptr) const { inline io_object_t toStorageType(io_object_t ptr) const { return (io_object_t)ptr; }
return (io_object_t)ptr;
}
inline T fromStorageType(io_object_t pointer) const { inline T fromStorageType(io_object_t pointer) const { return (T)pointer; }
return (T)pointer;
}
void swap(IOObjectPointer &other) { void swap(IOObjectPointer& other) { std::swap(storage, other.storage); }
std::swap(storage, other.storage);
}
}; };
/// A smart pointer that can manage the lifecycle of IOKit plugin objects. /// A smart pointer that can manage the lifecycle of IOKit plugin objects.
@ -92,16 +81,14 @@ public:
} }
} }
IOCFPlugInInterface*** operator&() IOCFPlugInInterface*** operator&() {
{
if (IOCFPlugInInterface** pointer = _storage) { if (IOCFPlugInInterface** pointer = _storage) {
IODestroyPlugInInterface(pointer); IODestroyPlugInInterface(pointer);
} }
return &_storage; return &_storage;
} }
HRESULT As(LPVOID* p, CFUUIDRef uuid) const HRESULT As(LPVOID* p, CFUUIDRef uuid) const {
{
(*_storage)->AddRef(_storage); // Needed for some reason (*_storage)->AddRef(_storage); // Needed for some reason
return (*_storage)->QueryInterface(_storage, CFUUIDGetUUIDBytes(uuid), p); return (*_storage)->QueryInterface(_storage, CFUUIDGetUUIDBytes(uuid), p);
} }
@ -112,8 +99,5 @@ public:
private: private:
IOCFPlugInInterface** _storage; IOCFPlugInInterface** _storage;
void swap(IOCFPluginPointer &other) { void swap(IOCFPluginPointer& other) { std::swap(_storage, other._storage); }
std::swap(_storage, other._storage);
}
}; };

View File

@ -1,20 +1,13 @@
#include "boo/inputdev/NintendoPowerA.hpp" #include "boo/inputdev/NintendoPowerA.hpp"
#include "boo/inputdev/DeviceSignature.hpp" #include "boo/inputdev/DeviceSignature.hpp"
#include <memory.h> #include <memory.h>
namespace boo namespace boo {
{
NintendoPowerA::NintendoPowerA(DeviceToken* token) NintendoPowerA::NintendoPowerA(DeviceToken* token)
: TDeviceBase<INintendoPowerACallback>(dev_typeid(NintendoPowerA), token) : TDeviceBase<INintendoPowerACallback>(dev_typeid(NintendoPowerA), token) {}
{
} NintendoPowerA::~NintendoPowerA() {}
NintendoPowerA::~NintendoPowerA() void NintendoPowerA::deviceDisconnected() {
{
}
void NintendoPowerA::deviceDisconnected()
{
std::lock_guard<std::mutex> lk(m_callbackLock); std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback) if (m_callback)
m_callback->controllerDisconnected(); m_callback->controllerDisconnected();
@ -22,8 +15,7 @@ void NintendoPowerA::deviceDisconnected()
void NintendoPowerA::initialCycle() {} void NintendoPowerA::initialCycle() {}
void NintendoPowerA::transferCycle() void NintendoPowerA::transferCycle() {
{
uint8_t payload[8]; uint8_t payload[8];
size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload)); size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload));
if (recvSz != 8) if (recvSz != 8)
@ -39,18 +31,14 @@ void NintendoPowerA::transferCycle()
void NintendoPowerA::finalCycle() {} void NintendoPowerA::finalCycle() {}
void NintendoPowerA::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) void NintendoPowerA::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {}
{
}
bool NintendoPowerAState::operator==(const NintendoPowerAState &other) bool NintendoPowerAState::operator==(const NintendoPowerAState& other) {
{
return !memcmp(this, &other, sizeof(NintendoPowerAState)); return !memcmp(this, &other, sizeof(NintendoPowerAState));
} }
bool NintendoPowerAState::operator!=(const NintendoPowerAState &other) bool NintendoPowerAState::operator!=(const NintendoPowerAState& other) {
{
return memcmp(this, &other, sizeof(NintendoPowerAState)); return memcmp(this, &other, sizeof(NintendoPowerAState));
} }
} } // namespace boo

View File

@ -12,15 +12,12 @@
#include <unordered_map> #include <unordered_map>
#include <mutex> #include <mutex>
namespace boo namespace boo {
{
class IWindow; class IWindow;
struct MetalContext struct MetalContext {
{
id<MTLDevice> m_dev = nullptr; id<MTLDevice> m_dev = nullptr;
id<MTLCommandQueue> m_q = nullptr; id<MTLCommandQueue> m_q = nullptr;
struct Window struct Window {
{
CAMetalLayer* m_metalLayer = nullptr; CAMetalLayer* m_metalLayer = nullptr;
std::mutex m_resizeLock; std::mutex m_resizeLock;
bool m_needsResize; bool m_needsResize;
@ -31,13 +28,12 @@ struct MetalContext
uint32_t m_anisotropy = 1; uint32_t m_anisotropy = 1;
MTLPixelFormat m_pixelFormat = MTLPixelFormatBGRA8Unorm; MTLPixelFormat m_pixelFormat = MTLPixelFormatBGRA8Unorm;
}; };
} } // namespace boo
#else #else
namespace boo namespace boo {
{
struct MetalContext {}; struct MetalContext {};
} } // namespace boo
#endif #endif
#endif // __APPLE__ #endif // __APPLE__

View File

@ -7,14 +7,12 @@
#include <switch.h> #include <switch.h>
namespace boo namespace boo {
{
static logvisor::Module Log("boo::NXApplication"); static logvisor::Module Log("boo::NXApplication");
std::shared_ptr<IWindow> _WindowNXNew(std::string_view title, NXContext* nxCtx); std::shared_ptr<IWindow> _WindowNXNew(std::string_view title, NXContext* nxCtx);
class ApplicationNX : public IApplication class ApplicationNX : public IApplication {
{
IApplicationCallback& m_callback; IApplicationCallback& m_callback;
const std::string m_uniqueName; const std::string m_uniqueName;
const std::string m_friendlyName; const std::string m_friendlyName;
@ -26,34 +24,20 @@ class ApplicationNX : public IApplication
void _deletedWindow(IWindow* window) {} void _deletedWindow(IWindow* window) {}
public: public:
ApplicationNX(IApplicationCallback& callback, ApplicationNX(IApplicationCallback& callback, std::string_view uniqueName, std::string_view friendlyName,
std::string_view uniqueName, std::string_view pname, const std::vector<std::string>& args, std::string_view gfxApi, uint32_t samples,
std::string_view friendlyName, uint32_t anisotropy, bool deepColor, bool singleInstance)
std::string_view pname, : m_callback(callback), m_uniqueName(uniqueName), m_friendlyName(friendlyName), m_pname(pname), m_args(args) {}
const std::vector<std::string>& args,
std::string_view gfxApi,
uint32_t samples,
uint32_t anisotropy,
bool deepColor,
bool singleInstance)
: m_callback(callback),
m_uniqueName(uniqueName),
m_friendlyName(friendlyName),
m_pname(pname),
m_args(args)
{}
EPlatformType getPlatformType() const { return EPlatformType::NX; } EPlatformType getPlatformType() const { return EPlatformType::NX; }
int run() int run() {
{
/* Spawn client thread */ /* Spawn client thread */
int clientReturn = INT_MIN; int clientReturn = INT_MIN;
std::mutex initmt; std::mutex initmt;
std::condition_variable initcv; std::condition_variable initcv;
std::unique_lock<std::mutex> outerLk(initmt); std::unique_lock<std::mutex> outerLk(initmt);
std::thread clientThread([&]() std::thread clientThread([&]() {
{
std::unique_lock<std::mutex> innerLk(initmt); std::unique_lock<std::mutex> innerLk(initmt);
innerLk.unlock(); innerLk.unlock();
initcv.notify_one(); initcv.notify_one();
@ -64,8 +48,7 @@ public:
initcv.wait(outerLk); initcv.wait(outerLk);
// Main graphics loop // Main graphics loop
while (clientReturn == INT_MIN && appletMainLoop()) while (clientReturn == INT_MIN && appletMainLoop()) {
{
// Get and process input // Get and process input
hidScanInput(); hidScanInput();
u32 kDown = hidKeysDown(CONTROLLER_P1_AUTO); u32 kDown = hidKeysDown(CONTROLLER_P1_AUTO);
@ -80,29 +63,16 @@ public:
return 0; return 0;
} }
std::string_view getUniqueName() const std::string_view getUniqueName() const { return m_uniqueName; }
{
return m_uniqueName;
}
std::string_view getFriendlyName() const std::string_view getFriendlyName() const { return m_friendlyName; }
{
return m_friendlyName;
}
std::string_view getProcessName() const std::string_view getProcessName() const { return m_pname; }
{
return m_pname;
}
const std::vector<std::string>& getArgs() const const std::vector<std::string>& getArgs() const { return m_args; }
{
return m_args;
}
std::shared_ptr<IWindow> m_window; std::shared_ptr<IWindow> m_window;
std::shared_ptr<IWindow> newWindow(std::string_view title) std::shared_ptr<IWindow> newWindow(std::string_view title) {
{
if (m_window) if (m_window)
Log.report(logvisor::Fatal, "Only 1 window allowed on NX"); Log.report(logvisor::Fatal, "Only 1 window allowed on NX");
m_window = _WindowNXNew(title, &m_nxCtx); m_window = _WindowNXNew(title, &m_nxCtx);
@ -111,29 +81,21 @@ public:
}; };
IApplication* APP = nullptr; IApplication* APP = nullptr;
int ApplicationRun(IApplication::EPlatformType platform, int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb, SystemStringView uniqueName,
IApplicationCallback& cb, SystemStringView friendlyName, SystemStringView pname, const std::vector<SystemString>& args,
SystemStringView uniqueName, std::string_view gfxApi, uint32_t samples, uint32_t anisotropy, bool deepColor,
SystemStringView friendlyName, bool singleInstance) {
SystemStringView pname,
const std::vector<SystemString>& args,
std::string_view gfxApi,
uint32_t samples,
uint32_t anisotropy,
bool deepColor,
bool singleInstance)
{
std::string thrName = std::string(friendlyName) + " Main Thread"; std::string thrName = std::string(friendlyName) + " Main Thread";
logvisor::RegisterThreadName(thrName.c_str()); logvisor::RegisterThreadName(thrName.c_str());
if (APP) if (APP)
return 1; return 1;
APP = new ApplicationNX(cb, uniqueName, friendlyName, pname, args, gfxApi, APP = new ApplicationNX(cb, uniqueName, friendlyName, pname, args, gfxApi, samples, anisotropy, deepColor,
samples, anisotropy, deepColor, singleInstance); singleInstance);
int ret = APP->run(); int ret = APP->run();
delete APP; delete APP;
APP = nullptr; APP = nullptr;
return ret; return ret;
} }
} } // namespace boo

View File

@ -5,21 +5,18 @@
#include <switch.h> #include <switch.h>
namespace boo namespace boo {
{
std::unique_ptr<IGraphicsCommandQueue> _NewNXCommandQueue(NXContext* ctx, IGraphicsContext* parent); std::unique_ptr<IGraphicsCommandQueue> _NewNXCommandQueue(NXContext* ctx, IGraphicsContext* parent);
std::unique_ptr<IGraphicsDataFactory> _NewNXDataFactory(IGraphicsContext* parent, NXContext* ctx); std::unique_ptr<IGraphicsDataFactory> _NewNXDataFactory(IGraphicsContext* parent, NXContext* ctx);
struct GraphicsContextNX : IGraphicsContext struct GraphicsContextNX : IGraphicsContext {
{
NXContext* m_nxCtx; NXContext* m_nxCtx;
std::unique_ptr<IGraphicsDataFactory> m_dataFactory; std::unique_ptr<IGraphicsDataFactory> m_dataFactory;
std::unique_ptr<IGraphicsCommandQueue> m_commandQueue; std::unique_ptr<IGraphicsCommandQueue> m_commandQueue;
public: public:
explicit GraphicsContextNX(NXContext* nxCtx) explicit GraphicsContextNX(NXContext* nxCtx) : m_nxCtx(nxCtx) {
: m_nxCtx(nxCtx)
{
m_dataFactory = _NewNXDataFactory(this, nxCtx); m_dataFactory = _NewNXDataFactory(this, nxCtx);
m_commandQueue = _NewNXCommandQueue(nxCtx, this); m_commandQueue = _NewNXCommandQueue(nxCtx, this);
} }
@ -38,15 +35,13 @@ public:
IGraphicsDataFactory* getLoadContextDataFactory() { return m_dataFactory.get(); } IGraphicsDataFactory* getLoadContextDataFactory() { return m_dataFactory.get(); }
}; };
class WindowNX : public IWindow class WindowNX : public IWindow {
{
std::string m_title; std::string m_title;
std::unique_ptr<GraphicsContextNX> m_gfxCtx; std::unique_ptr<GraphicsContextNX> m_gfxCtx;
IWindowCallback* m_callback = nullptr; IWindowCallback* m_callback = nullptr;
public: public:
WindowNX(std::string_view title, NXContext* nxCtx) WindowNX(std::string_view title, NXContext* nxCtx) : m_title(title), m_gfxCtx(new GraphicsContextNX(nxCtx)) {
: m_title(title), m_gfxCtx(new GraphicsContextNX(nxCtx))
{
m_gfxCtx->initializeContext(nullptr); m_gfxCtx->initializeContext(nullptr);
} }
@ -63,8 +58,7 @@ public:
void setWaitCursor(bool wait) {} void setWaitCursor(bool wait) {}
void setWindowFrameDefault() {} void setWindowFrameDefault() {}
void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const {
{
u32 width, height; u32 width, height;
gfxGetFramebufferResolution(&width, &height); gfxGetFramebufferResolution(&width, &height);
xOut = 0; xOut = 0;
@ -72,8 +66,7 @@ public:
wOut = width; wOut = width;
hOut = height; hOut = height;
} }
void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const void getWindowFrame(int& xOut, int& yOut, int& wOut, int& hOut) const {
{
u32 width, height; u32 width, height;
gfxGetFramebufferResolution(&width, &height); gfxGetFramebufferResolution(&width, &height);
xOut = 0; xOut = 0;
@ -95,7 +88,10 @@ public:
void waitForRetrace() {} void waitForRetrace() {}
uintptr_t getPlatformHandle() const { return 0; } uintptr_t getPlatformHandle() const { return 0; }
bool _incomingEvent(void* event) {(void)event; return false;} bool _incomingEvent(void* event) {
(void)event;
return false;
}
void _cleanup() {} void _cleanup() {}
ETouchType getTouchType() const { return ETouchType::Display; } ETouchType getTouchType() const { return ETouchType::Display; }
@ -111,10 +107,9 @@ public:
IGraphicsDataFactory* getLoadContextDataFactory() { return m_gfxCtx->getLoadContextDataFactory(); } IGraphicsDataFactory* getLoadContextDataFactory() { return m_gfxCtx->getLoadContextDataFactory(); }
}; };
std::shared_ptr<IWindow> _WindowNXNew(std::string_view title, NXContext* nxCtx) std::shared_ptr<IWindow> _WindowNXNew(std::string_view title, NXContext* nxCtx) {
{
std::shared_ptr<IWindow> ret = std::make_shared<WindowNX>(title, nxCtx); std::shared_ptr<IWindow> ret = std::make_shared<WindowNX>(title, nxCtx);
return ret; return ret;
} }
} } // namespace boo

View File

@ -25,21 +25,18 @@ PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignaturePROC = nullptr;
pD3DCompile D3DCompilePROC = nullptr; pD3DCompile D3DCompilePROC = nullptr;
pD3DCreateBlob D3DCreateBlobPROC = nullptr; pD3DCreateBlob D3DCreateBlobPROC = nullptr;
static bool FindBestD3DCompile() static bool FindBestD3DCompile() {
{
D3DCompilePROC = D3DCompile; D3DCompilePROC = D3DCompile;
D3DCreateBlobPROC = D3DCreateBlob; D3DCreateBlobPROC = D3DCreateBlob;
return D3DCompilePROC != nullptr && D3DCreateBlobPROC != nullptr; return D3DCompilePROC != nullptr && D3DCreateBlobPROC != nullptr;
} }
namespace boo namespace boo {
{
static logvisor::Module Log("boo::ApplicationUWP"); static logvisor::Module Log("boo::ApplicationUWP");
std::shared_ptr<IWindow> _WindowUWPNew(SystemStringView title, Boo3DAppContextUWP& d3dCtx); std::shared_ptr<IWindow> _WindowUWPNew(SystemStringView title, Boo3DAppContextUWP& d3dCtx);
class ApplicationUWP final : public IApplication class ApplicationUWP final : public IApplication {
{
friend ref class AppView; friend ref class AppView;
IApplicationCallback& m_callback; IApplicationCallback& m_callback;
const SystemString m_uniqueName; const SystemString m_uniqueName;
@ -52,25 +49,17 @@ class ApplicationUWP final : public IApplication
Boo3DAppContextUWP m_3dCtx; Boo3DAppContextUWP m_3dCtx;
void _deletedWindow(IWindow* window) void _deletedWindow(IWindow* window) {}
{
}
public: public:
ApplicationUWP(IApplicationCallback& callback, SystemStringView uniqueName, SystemStringView friendlyName,
ApplicationUWP(IApplicationCallback& callback, SystemStringView pname, const std::vector<SystemString>& args, bool singleInstance)
SystemStringView uniqueName, : m_callback(callback)
SystemStringView friendlyName, , m_uniqueName(uniqueName)
SystemStringView pname, , m_friendlyName(friendlyName)
const std::vector<SystemString>& args, , m_pname(pname)
bool singleInstance) , m_args(args)
: m_callback(callback), , m_singleInstance(singleInstance) {
m_uniqueName(uniqueName),
m_friendlyName(friendlyName),
m_pname(pname),
m_args(args),
m_singleInstance(singleInstance)
{
typedef HRESULT(WINAPI * CreateDXGIFactory1PROC)(REFIID riid, _COM_Outptr_ void** ppFactory); typedef HRESULT(WINAPI * CreateDXGIFactory1PROC)(REFIID riid, _COM_Outptr_ void** ppFactory);
CreateDXGIFactory1PROC MyCreateDXGIFactory1 = CreateDXGIFactory1; CreateDXGIFactory1PROC MyCreateDXGIFactory1 = CreateDXGIFactory1;
@ -80,8 +69,7 @@ public:
no12 = false; no12 = false;
#if _WIN32_WINNT_WIN10 #if _WIN32_WINNT_WIN10
if (!no12) if (!no12) {
{
if (!FindBestD3DCompile()) if (!FindBestD3DCompile())
Log.report(logvisor::Fatal, "unable to find D3DCompile_[43-47].dll"); Log.report(logvisor::Fatal, "unable to find D3DCompile_[43-47].dll");
@ -97,53 +85,49 @@ public:
/* Adapter */ /* Adapter */
ComPtr<IDXGIAdapter1> ppAdapter; ComPtr<IDXGIAdapter1> ppAdapter;
for (UINT adapterIndex = 0; ; ++adapterIndex) for (UINT adapterIndex = 0;; ++adapterIndex) {
{
ComPtr<IDXGIAdapter1> pAdapter; ComPtr<IDXGIAdapter1> pAdapter;
if (DXGI_ERROR_NOT_FOUND == m_3dCtx.m_ctx12.m_dxFactory->EnumAdapters1(adapterIndex, &pAdapter)) if (DXGI_ERROR_NOT_FOUND == m_3dCtx.m_ctx12.m_dxFactory->EnumAdapters1(adapterIndex, &pAdapter))
break; break;
// Check to see if the adapter supports Direct3D 12, but don't create the // Check to see if the adapter supports Direct3D 12, but don't create the
// actual device yet. // actual device yet.
if (SUCCEEDED(MyD3D12CreateDevice(pAdapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) if (SUCCEEDED(MyD3D12CreateDevice(pAdapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) {
{
ppAdapter = std::move(pAdapter); ppAdapter = std::move(pAdapter);
break; break;
} }
} }
/* Create device */ /* Create device */
hr = ppAdapter ? MyD3D12CreateDevice(ppAdapter.Get(), D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), &m_3dCtx.m_ctx12.m_dev) : E_FAIL; hr = ppAdapter ? MyD3D12CreateDevice(ppAdapter.Get(), D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device),
if (!FAILED(hr)) &m_3dCtx.m_ctx12.m_dev)
{ : E_FAIL;
if (!FAILED(hr)) {
/* Establish loader objects */ /* Establish loader objects */
if (FAILED(m_3dCtx.m_ctx12.m_dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, if (FAILED(m_3dCtx.m_ctx12.m_dev->CreateCommandAllocator(
__uuidof(ID3D12CommandAllocator), &m_3dCtx.m_ctx12.m_loadqalloc))) D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), &m_3dCtx.m_ctx12.m_loadqalloc)))
Log.report(logvisor::Fatal, "unable to create loader allocator"); Log.report(logvisor::Fatal, "unable to create loader allocator");
D3D12_COMMAND_QUEUE_DESC desc = D3D12_COMMAND_QUEUE_DESC desc = {D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL,
{ D3D12_COMMAND_QUEUE_FLAG_NONE};
D3D12_COMMAND_LIST_TYPE_DIRECT, if (FAILED(m_3dCtx.m_ctx12.m_dev->CreateCommandQueue(&desc, __uuidof(ID3D12CommandQueue),
D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, &m_3dCtx.m_ctx12.m_loadq)))
D3D12_COMMAND_QUEUE_FLAG_NONE
};
if (FAILED(m_3dCtx.m_ctx12.m_dev->CreateCommandQueue(&desc, __uuidof(ID3D12CommandQueue), &m_3dCtx.m_ctx12.m_loadq)))
Log.report(logvisor::Fatal, "unable to create loader queue"); Log.report(logvisor::Fatal, "unable to create loader queue");
if (FAILED(m_3dCtx.m_ctx12.m_dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence), &m_3dCtx.m_ctx12.m_loadfence))) if (FAILED(m_3dCtx.m_ctx12.m_dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence),
&m_3dCtx.m_ctx12.m_loadfence)))
Log.report(logvisor::Fatal, "unable to create loader fence"); Log.report(logvisor::Fatal, "unable to create loader fence");
m_3dCtx.m_ctx12.m_loadfencehandle = CreateEvent(nullptr, FALSE, FALSE, nullptr); m_3dCtx.m_ctx12.m_loadfencehandle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (FAILED(m_3dCtx.m_ctx12.m_dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_3dCtx.m_ctx12.m_loadqalloc.Get(), if (FAILED(m_3dCtx.m_ctx12.m_dev->CreateCommandList(
nullptr, __uuidof(ID3D12GraphicsCommandList), &m_3dCtx.m_ctx12.m_loadlist))) 0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_3dCtx.m_ctx12.m_loadqalloc.Get(), nullptr,
__uuidof(ID3D12GraphicsCommandList), &m_3dCtx.m_ctx12.m_loadlist)))
Log.report(logvisor::Fatal, "unable to create loader list"); Log.report(logvisor::Fatal, "unable to create loader list");
Log.report(logvisor::Info, "initialized D3D12 renderer"); Log.report(logvisor::Info, "initialized D3D12 renderer");
return; return;
} } else {
else
{
/* Some Win10 client HW doesn't support D3D12 (despite being supposedly HW-agnostic) */ /* Some Win10 client HW doesn't support D3D12 (despite being supposedly HW-agnostic) */
m_3dCtx.m_ctx12.m_dev.Reset(); m_3dCtx.m_ctx12.m_dev.Reset();
m_3dCtx.m_ctx12.m_dxFactory.Reset(); m_3dCtx.m_ctx12.m_dxFactory.Reset();
@ -161,15 +145,14 @@ public:
D3D_FEATURE_LEVEL level = D3D_FEATURE_LEVEL_11_0; D3D_FEATURE_LEVEL level = D3D_FEATURE_LEVEL_11_0;
ComPtr<ID3D11Device> tempDev; ComPtr<ID3D11Device> tempDev;
ComPtr<ID3D11DeviceContext> tempCtx; ComPtr<ID3D11DeviceContext> tempCtx;
if (FAILED(MyD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_FLAGS, &level, if (FAILED(MyD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_FLAGS, &level, 1,
1, D3D11_SDK_VERSION, &tempDev, nullptr, &tempCtx))) D3D11_SDK_VERSION, &tempDev, nullptr, &tempCtx)))
Log.report(logvisor::Fatal, "unable to create D3D11 device"); Log.report(logvisor::Fatal, "unable to create D3D11 device");
ComPtr<IDXGIDevice2> device; ComPtr<IDXGIDevice2> device;
if (FAILED(tempDev.As<ID3D11Device1>(&m_3dCtx.m_ctx11.m_dev)) || !m_3dCtx.m_ctx11.m_dev || if (FAILED(tempDev.As<ID3D11Device1>(&m_3dCtx.m_ctx11.m_dev)) || !m_3dCtx.m_ctx11.m_dev ||
FAILED(tempCtx.As<ID3D11DeviceContext1>(&m_3dCtx.m_ctx11.m_devCtx)) || !m_3dCtx.m_ctx11.m_devCtx || FAILED(tempCtx.As<ID3D11DeviceContext1>(&m_3dCtx.m_ctx11.m_devCtx)) || !m_3dCtx.m_ctx11.m_devCtx ||
FAILED(m_3dCtx.m_ctx11.m_dev.As<IDXGIDevice2>(&device)) || !device) FAILED(m_3dCtx.m_ctx11.m_dev.As<IDXGIDevice2>(&device)) || !device) {
{
exit(1); exit(1);
} }
@ -197,19 +180,13 @@ public:
Log.report(logvisor::Fatal, "system doesn't support D3D11 or D3D12"); Log.report(logvisor::Fatal, "system doesn't support D3D11 or D3D12");
} }
EPlatformType getPlatformType() const EPlatformType getPlatformType() const { return EPlatformType::UWP; }
{
return EPlatformType::UWP;
}
std::thread m_clientThread; std::thread m_clientThread;
int run() int run() {
{
/* Spawn client thread */ /* Spawn client thread */
int clientReturn = 0; int clientReturn = 0;
m_clientThread = std::thread([&]() m_clientThread = std::thread([&]() {
{
std::string thrName = WCSTMBS(getFriendlyName().data()) + " Client Thread"; std::string thrName = WCSTMBS(getFriendlyName().data()) + " Client Thread";
logvisor::RegisterThreadName(thrName.c_str()); logvisor::RegisterThreadName(thrName.c_str());
clientReturn = m_callback.appMain(this); clientReturn = m_callback.appMain(this);
@ -220,99 +197,62 @@ public:
return 0; return 0;
} }
void quit() void quit() {
{
m_callback.appQuitting(this); m_callback.appQuitting(this);
if (m_clientThread.joinable()) if (m_clientThread.joinable())
m_clientThread.join(); m_clientThread.join();
} }
SystemStringView getUniqueName() const SystemStringView getUniqueName() const { return m_uniqueName; }
{
return m_uniqueName;
}
SystemStringView getFriendlyName() const SystemStringView getFriendlyName() const { return m_friendlyName; }
{
return m_friendlyName;
}
SystemStringView getProcessName() const SystemStringView getProcessName() const { return m_pname; }
{
return m_pname;
}
const std::vector<SystemString>& getArgs() const const std::vector<SystemString>& getArgs() const { return m_args; }
{
return m_args;
}
std::shared_ptr<IWindow> newWindow(SystemStringView title, uint32_t sampleCount) std::shared_ptr<IWindow> newWindow(SystemStringView title, uint32_t sampleCount) {
{ if (!m_issuedWindow) {
if (!m_issuedWindow)
{
m_issuedWindow = true; m_issuedWindow = true;
return m_window; return m_window;
} }
return {}; return {};
} }
void _setWindow(CoreWindow^ window) void _setWindow(CoreWindow ^ window) { m_window = _WindowUWPNew(m_friendlyName, m_3dCtx); }
{
m_window = _WindowUWPNew(m_friendlyName, m_3dCtx);
}
}; };
IApplication* APP = NULL; IApplication* APP = NULL;
ref class AppView sealed : public IFrameworkView ref class AppView sealed : public IFrameworkView {
{
ApplicationUWP m_app; ApplicationUWP m_app;
internal: internal : AppView(IApplicationCallback& callback, SystemStringView uniqueName, SystemStringView friendlyName,
AppView(IApplicationCallback& callback, SystemStringView pname, const std::vector<SystemString>& args, bool singleInstance)
SystemStringView uniqueName, : m_app(callback, uniqueName, friendlyName, pname, args, singleInstance) {
SystemStringView friendlyName, APP = &m_app;
SystemStringView pname, }
const std::vector<SystemString>& args,
bool singleInstance)
: m_app(callback, uniqueName, friendlyName, pname, args, singleInstance) { APP = &m_app; }
public: public:
virtual void Initialize(CoreApplicationView^ applicationView) virtual void Initialize(CoreApplicationView ^ applicationView) {
{ applicationView->Activated +=
applicationView->Activated += ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &AppView::OnActivated); ref new TypedEventHandler<CoreApplicationView ^, IActivatedEventArgs ^>(this, &AppView::OnActivated);
} }
virtual void SetWindow(CoreWindow^ window) virtual void SetWindow(CoreWindow ^ window) { m_app._setWindow(window); }
{
m_app._setWindow(window);
}
virtual void Load(String^ entryPoint) virtual void Load(String ^ entryPoint) {}
{
} virtual void Run() { m_app.run(); }
virtual void Run() virtual void Uninitialize() { m_app.quit(); }
{
m_app.run();
}
virtual void Uninitialize() void OnActivated(CoreApplicationView ^ applicationView, IActivatedEventArgs ^ args) {
{
m_app.quit();
}
void OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
{
CoreWindow::GetForCurrentThread()->Activate(); CoreWindow::GetForCurrentThread()->Activate();
} }
}; };
IFrameworkView^ ViewProvider::CreateView() IFrameworkView ^ ViewProvider::CreateView() {
{
return ref new AppView(m_appCb, m_uniqueName, m_friendlyName, m_pname, m_args, m_singleInstance); return ref new AppView(m_appCb, m_uniqueName, m_friendlyName, m_pname, m_args, m_singleInstance);
} }
} } // namespace boo

View File

@ -33,27 +33,21 @@ static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
pD3DCompile D3DCompilePROC = nullptr; pD3DCompile D3DCompilePROC = nullptr;
pD3DCreateBlob D3DCreateBlobPROC = nullptr; pD3DCreateBlob D3DCreateBlobPROC = nullptr;
static bool FindBestD3DCompile() static bool FindBestD3DCompile() {
{
HMODULE d3dCompilelib = LoadLibraryW(L"D3DCompiler_47.dll"); HMODULE d3dCompilelib = LoadLibraryW(L"D3DCompiler_47.dll");
if (!d3dCompilelib) if (!d3dCompilelib) {
{
d3dCompilelib = LoadLibraryW(L"D3DCompiler_46.dll"); d3dCompilelib = LoadLibraryW(L"D3DCompiler_46.dll");
if (!d3dCompilelib) if (!d3dCompilelib) {
{
d3dCompilelib = LoadLibraryW(L"D3DCompiler_45.dll"); d3dCompilelib = LoadLibraryW(L"D3DCompiler_45.dll");
if (!d3dCompilelib) if (!d3dCompilelib) {
{
d3dCompilelib = LoadLibraryW(L"D3DCompiler_44.dll"); d3dCompilelib = LoadLibraryW(L"D3DCompiler_44.dll");
if (!d3dCompilelib) if (!d3dCompilelib) {
{
d3dCompilelib = LoadLibraryW(L"D3DCompiler_43.dll"); d3dCompilelib = LoadLibraryW(L"D3DCompiler_43.dll");
} }
} }
} }
} }
if (d3dCompilelib) if (d3dCompilelib) {
{
D3DCompilePROC = (pD3DCompile)GetProcAddress(d3dCompilelib, "D3DCompile"); D3DCompilePROC = (pD3DCompile)GetProcAddress(d3dCompilelib, "D3DCompile");
D3DCreateBlobPROC = (pD3DCreateBlob)GetProcAddress(d3dCompilelib, "D3DCreateBlob"); D3DCreateBlobPROC = (pD3DCreateBlob)GetProcAddress(d3dCompilelib, "D3DCreateBlob");
return D3DCompilePROC != nullptr && D3DCreateBlobPROC != nullptr; return D3DCompilePROC != nullptr && D3DCreateBlobPROC != nullptr;
@ -61,15 +55,13 @@ static bool FindBestD3DCompile()
return false; return false;
} }
namespace boo namespace boo {
{
static logvisor::Module Log("boo::ApplicationWin32"); static logvisor::Module Log("boo::ApplicationWin32");
Win32Cursors WIN32_CURSORS; Win32Cursors WIN32_CURSORS;
std::shared_ptr<IWindow> _WindowWin32New(SystemStringView title, Boo3DAppContextWin32& d3dCtx); std::shared_ptr<IWindow> _WindowWin32New(SystemStringView title, Boo3DAppContextWin32& d3dCtx);
class ApplicationWin32 final : public IApplication class ApplicationWin32 final : public IApplication {
{
IApplicationCallback& m_callback; IApplicationCallback& m_callback;
const SystemString m_uniqueName; const SystemString m_uniqueName;
const SystemString m_friendlyName; const SystemString m_friendlyName;
@ -82,29 +74,13 @@ class ApplicationWin32 final : public IApplication
PFN_vkGetInstanceProcAddr m_getVkProc = nullptr; PFN_vkGetInstanceProcAddr m_getVkProc = nullptr;
#endif #endif
void _deletedWindow(IWindow* window) void _deletedWindow(IWindow* window) { m_allWindows.erase(HWND(window->getPlatformHandle())); }
{
m_allWindows.erase(HWND(window->getPlatformHandle()));
}
public: public:
ApplicationWin32(IApplicationCallback& callback, SystemStringView uniqueName, SystemStringView friendlyName,
ApplicationWin32(IApplicationCallback& callback, SystemStringView pname, const std::vector<SystemString>& args, std::string_view gfxApi,
SystemStringView uniqueName, uint32_t samples, uint32_t anisotropy, bool deepColor, bool singleInstance)
SystemStringView friendlyName, : m_callback(callback), m_uniqueName(uniqueName), m_friendlyName(friendlyName), m_pname(pname), m_args(args) {
SystemStringView pname,
const std::vector<SystemString>& args,
std::string_view gfxApi,
uint32_t samples,
uint32_t anisotropy,
bool deepColor,
bool singleInstance)
: m_callback(callback),
m_uniqueName(uniqueName),
m_friendlyName(friendlyName),
m_pname(pname),
m_args(args)
{
m_3dCtx.m_ctx11.m_sampleCount = samples; m_3dCtx.m_ctx11.m_sampleCount = samples;
m_3dCtx.m_ctx11.m_anisotropy = anisotropy; m_3dCtx.m_ctx11.m_anisotropy = anisotropy;
m_3dCtx.m_ctx11.m_fbFormat = deepColor ? DXGI_FORMAT_R16G16B16A16_FLOAT : DXGI_FORMAT_R8G8B8A8_UNORM; m_3dCtx.m_ctx11.m_fbFormat = deepColor ? DXGI_FORMAT_R16G16B16A16_FLOAT : DXGI_FORMAT_R8G8B8A8_UNORM;
@ -131,16 +107,13 @@ public:
#if BOO_HAS_VULKAN #if BOO_HAS_VULKAN
bool useVulkan = false; bool useVulkan = false;
#endif #endif
if (!gfxApi.empty()) if (!gfxApi.empty()) {
{
#if BOO_HAS_VULKAN #if BOO_HAS_VULKAN
if (!gfxApi.compare("Vulkan")) if (!gfxApi.compare("Vulkan")) {
{
noD3d = true; noD3d = true;
useVulkan = true; useVulkan = true;
} }
if (!gfxApi.compare("OpenGL")) if (!gfxApi.compare("OpenGL")) {
{
noD3d = true; noD3d = true;
useVulkan = false; useVulkan = false;
} }
@ -149,21 +122,17 @@ public:
noD3d = true; noD3d = true;
#endif #endif
} }
for (const SystemString& arg : args) for (const SystemString& arg : args) {
{
#if BOO_HAS_VULKAN #if BOO_HAS_VULKAN
if (!arg.compare(L"--d3d11")) if (!arg.compare(L"--d3d11")) {
{
useVulkan = false; useVulkan = false;
noD3d = false; noD3d = false;
} }
if (!arg.compare(L"--vulkan")) if (!arg.compare(L"--vulkan")) {
{
noD3d = true; noD3d = true;
useVulkan = true; useVulkan = true;
} }
if (!arg.compare(L"--gl")) if (!arg.compare(L"--gl")) {
{
noD3d = true; noD3d = true;
useVulkan = false; useVulkan = false;
} }
@ -178,13 +147,13 @@ public:
HMODULE d3d11lib = nullptr; HMODULE d3d11lib = nullptr;
if (!noD3d) if (!noD3d)
d3d11lib = LoadLibraryW(L"D3D11.dll"); d3d11lib = LoadLibraryW(L"D3D11.dll");
if (d3d11lib) if (d3d11lib) {
{
if (!FindBestD3DCompile()) if (!FindBestD3DCompile())
Log.report(logvisor::Fatal, "unable to find D3DCompile_[43-47].dll"); Log.report(logvisor::Fatal, "unable to find D3DCompile_[43-47].dll");
/* Create device proc */ /* Create device proc */
PFN_D3D11_CREATE_DEVICE MyD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(d3d11lib, "D3D11CreateDevice"); PFN_D3D11_CREATE_DEVICE MyD3D11CreateDevice =
(PFN_D3D11_CREATE_DEVICE)GetProcAddress(d3d11lib, "D3D11CreateDevice");
if (!MyD3D11CreateDevice) if (!MyD3D11CreateDevice)
Log.report(logvisor::Fatal, "unable to find D3D11CreateDevice in D3D11.dll"); Log.report(logvisor::Fatal, "unable to find D3D11CreateDevice in D3D11.dll");
@ -192,16 +161,16 @@ public:
D3D_FEATURE_LEVEL level = D3D_FEATURE_LEVEL_11_0; D3D_FEATURE_LEVEL level = D3D_FEATURE_LEVEL_11_0;
ComPtr<ID3D11Device> tempDev; ComPtr<ID3D11Device> tempDev;
ComPtr<ID3D11DeviceContext> tempCtx; ComPtr<ID3D11DeviceContext> tempCtx;
if (FAILED(MyD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_FLAGS, &level, if (FAILED(MyD3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_FLAGS, &level, 1,
1, D3D11_SDK_VERSION, &tempDev, nullptr, &tempCtx))) D3D11_SDK_VERSION, &tempDev, nullptr, &tempCtx)))
Log.report(logvisor::Fatal, "unable to create D3D11 device"); Log.report(logvisor::Fatal, "unable to create D3D11 device");
ComPtr<IDXGIDevice2> device; ComPtr<IDXGIDevice2> device;
if (FAILED(tempDev.As<ID3D11Device1>(&m_3dCtx.m_ctx11.m_dev)) || !m_3dCtx.m_ctx11.m_dev || if (FAILED(tempDev.As<ID3D11Device1>(&m_3dCtx.m_ctx11.m_dev)) || !m_3dCtx.m_ctx11.m_dev ||
FAILED(tempCtx.As<ID3D11DeviceContext1>(&m_3dCtx.m_ctx11.m_devCtx)) || !m_3dCtx.m_ctx11.m_devCtx || FAILED(tempCtx.As<ID3D11DeviceContext1>(&m_3dCtx.m_ctx11.m_devCtx)) || !m_3dCtx.m_ctx11.m_devCtx ||
FAILED(m_3dCtx.m_ctx11.m_dev.As<IDXGIDevice2>(&device)) || !device) FAILED(m_3dCtx.m_ctx11.m_dev.As<IDXGIDevice2>(&device)) || !device) {
{ MessageBoxW(nullptr,
MessageBoxW(nullptr, L"Windows 7 users should install 'Platform Update for Windows 7':\n" L"Windows 7 users should install 'Platform Update for Windows 7':\n"
L"https://www.microsoft.com/en-us/download/details.aspx?id=36805", L"https://www.microsoft.com/en-us/download/details.aspx?id=36805",
L"IDXGIDevice2 interface error", MB_OK | MB_ICONERROR); L"IDXGIDevice2 interface error", MB_OK | MB_ICONERROR);
exit(1); exit(1);
@ -250,22 +219,16 @@ public:
} }
#if BOO_HAS_VULKAN #if BOO_HAS_VULKAN
if (useVulkan) if (useVulkan) {
{
HMODULE vulkanLib = LoadLibraryW(L"vulkan-1.dll"); HMODULE vulkanLib = LoadLibraryW(L"vulkan-1.dll");
if (vulkanLib) if (vulkanLib) {
{
m_getVkProc = (PFN_vkGetInstanceProcAddr)GetProcAddress(vulkanLib, "vkGetInstanceProcAddr"); m_getVkProc = (PFN_vkGetInstanceProcAddr)GetProcAddress(vulkanLib, "vkGetInstanceProcAddr");
if (m_getVkProc) if (m_getVkProc) {
{
/* Check device support for vulkan */ /* Check device support for vulkan */
if (g_VulkanContext.m_instance == VK_NULL_HANDLE) if (g_VulkanContext.m_instance == VK_NULL_HANDLE) {
{
auto appName = getUniqueName(); auto appName = getUniqueName();
if (g_VulkanContext.initVulkan(WCSTMBS(appName.data()).c_str(), m_getVkProc)) if (g_VulkanContext.initVulkan(WCSTMBS(appName.data()).c_str(), m_getVkProc)) {
{ if (g_VulkanContext.enumerateDevices()) {
if (g_VulkanContext.enumerateDevices())
{
/* Obtain DXGI Factory */ /* Obtain DXGI Factory */
HRESULT hr = MyCreateDXGIFactory1(__uuidof(IDXGIFactory1), &m_3dCtx.m_vulkanDxFactory); HRESULT hr = MyCreateDXGIFactory1(__uuidof(IDXGIFactory1), &m_3dCtx.m_vulkanDxFactory);
if (FAILED(hr)) if (FAILED(hr))
@ -295,24 +258,20 @@ public:
Log.report(logvisor::Fatal, "system doesn't support Vulkan, D3D11, or OpenGL"); Log.report(logvisor::Fatal, "system doesn't support Vulkan, D3D11, or OpenGL");
} }
EPlatformType getPlatformType() const EPlatformType getPlatformType() const { return EPlatformType::Win32; }
{
return EPlatformType::Win32;
}
LRESULT winHwndHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) LRESULT winHwndHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
{
/* Lookup boo window instance */ /* Lookup boo window instance */
auto search = m_allWindows.find(hwnd); auto search = m_allWindows.find(hwnd);
if (search == m_allWindows.end()) if (search == m_allWindows.end())
return DefWindowProc(hwnd, uMsg, wParam, lParam);; return DefWindowProc(hwnd, uMsg, wParam, lParam);
;
std::shared_ptr<IWindow> window = search->second.lock(); std::shared_ptr<IWindow> window = search->second.lock();
if (!window) if (!window)
return DefWindowProc(hwnd, uMsg, wParam, lParam); return DefWindowProc(hwnd, uMsg, wParam, lParam);
switch (uMsg) switch (uMsg) {
{
case WM_CREATE: case WM_CREATE:
return 0; return 0;
@ -342,8 +301,7 @@ public:
case WM_MOUSEWHEEL: case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL: case WM_MOUSEHWHEEL:
case WM_CHAR: case WM_CHAR:
case WM_UNICHAR: case WM_UNICHAR: {
{
HWNDEvent eventData(uMsg, wParam, lParam); HWNDEvent eventData(uMsg, wParam, lParam);
window->_incomingEvent(&eventData); window->_incomingEvent(&eventData);
} }
@ -354,54 +312,44 @@ public:
} }
template <class W> template <class W>
static void DoSetFullscreen(W& win, bool fs) static void DoSetFullscreen(W& win, bool fs) {
{
std::lock_guard<std::mutex> lk(g_nwmt); std::lock_guard<std::mutex> lk(g_nwmt);
if (fs) if (fs) {
{
win.m_fsStyle = GetWindowLong(win.m_hwnd, GWL_STYLE); win.m_fsStyle = GetWindowLong(win.m_hwnd, GWL_STYLE);
win.m_fsExStyle = GetWindowLong(win.m_hwnd, GWL_EXSTYLE); win.m_fsExStyle = GetWindowLong(win.m_hwnd, GWL_EXSTYLE);
GetWindowRect(win.m_hwnd, &win.m_fsRect); GetWindowRect(win.m_hwnd, &win.m_fsRect);
SetWindowLong(win.m_hwnd, GWL_STYLE, SetWindowLong(win.m_hwnd, GWL_STYLE, win.m_fsStyle & ~(WS_CAPTION | WS_THICKFRAME));
win.m_fsStyle & ~(WS_CAPTION | WS_THICKFRAME));
SetWindowLong(win.m_hwnd, GWL_EXSTYLE, SetWindowLong(win.m_hwnd, GWL_EXSTYLE,
win.m_fsExStyle & ~(WS_EX_DLGMODALFRAME | win.m_fsExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
MONITORINFO monitor_info; MONITORINFO monitor_info;
monitor_info.cbSize = sizeof(monitor_info); monitor_info.cbSize = sizeof(monitor_info);
GetMonitorInfo(MonitorFromWindow(win.m_hwnd, MONITOR_DEFAULTTONEAREST), GetMonitorInfo(MonitorFromWindow(win.m_hwnd, MONITOR_DEFAULTTONEAREST), &monitor_info);
&monitor_info);
SetWindowPos(win.m_hwnd, NULL, monitor_info.rcMonitor.left, monitor_info.rcMonitor.top, SetWindowPos(win.m_hwnd, NULL, monitor_info.rcMonitor.left, monitor_info.rcMonitor.top,
monitor_info.rcMonitor.right - monitor_info.rcMonitor.left, monitor_info.rcMonitor.right - monitor_info.rcMonitor.left,
monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top, monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top,
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
win.m_fs = true; win.m_fs = true;
} } else {
else
{
SetWindowLong(win.m_hwnd, GWL_STYLE, win.m_fsStyle); SetWindowLong(win.m_hwnd, GWL_STYLE, win.m_fsStyle);
SetWindowLong(win.m_hwnd, GWL_EXSTYLE, win.m_fsExStyle); SetWindowLong(win.m_hwnd, GWL_EXSTYLE, win.m_fsExStyle);
SetWindowPos(win.m_hwnd, NULL, win.m_fsRect.left, win.m_fsRect.top, SetWindowPos(win.m_hwnd, NULL, win.m_fsRect.left, win.m_fsRect.top, win.m_fsRect.right - win.m_fsRect.left,
win.m_fsRect.right - win.m_fsRect.left, win.m_fsRect.bottom - win.m_fsRect.top, win.m_fsRect.bottom - win.m_fsRect.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
win.m_fs = false; win.m_fs = false;
} }
g_nwcv.notify_one(); g_nwcv.notify_one();
} }
int run() int run() {
{
g_mainThreadId = GetCurrentThreadId(); g_mainThreadId = GetCurrentThreadId();
/* Spawn client thread */ /* Spawn client thread */
int clientReturn = 0; int clientReturn = 0;
std::thread clientThread([&]() std::thread clientThread([&]() {
{
std::string thrName = WCSTMBS(getFriendlyName().data()) + " Client Thread"; std::string thrName = WCSTMBS(getFriendlyName().data()) + " Client Thread";
logvisor::RegisterThreadName(thrName.c_str()); logvisor::RegisterThreadName(thrName.c_str());
CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
@ -411,15 +359,11 @@ public:
/* Pump messages */ /* Pump messages */
MSG msg = {0}; MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0)) while (GetMessage(&msg, NULL, 0, 0)) {
{ if (!msg.hwnd) {
if (!msg.hwnd)
{
/* PostThreadMessage events */ /* PostThreadMessage events */
switch (msg.message) switch (msg.message) {
{ case WM_USER: {
case WM_USER:
{
/* New-window message (coalesced onto main thread) */ /* New-window message (coalesced onto main thread) */
std::lock_guard<std::mutex> lk(g_nwmt); std::lock_guard<std::mutex> lk(g_nwmt);
SystemStringView* title = reinterpret_cast<SystemStringView*>(msg.wParam); SystemStringView* title = reinterpret_cast<SystemStringView*>(msg.wParam);
@ -453,7 +397,8 @@ public:
DoSetFullscreen(*reinterpret_cast<boo::VulkanContext::Window*>(msg.wParam), msg.lParam); DoSetFullscreen(*reinterpret_cast<boo::VulkanContext::Window*>(msg.wParam), msg.lParam);
continue; continue;
#endif #endif
default: break; default:
break;
} }
} }
TranslateMessage(&msg); TranslateMessage(&msg);
@ -465,38 +410,23 @@ public:
return clientReturn; return clientReturn;
} }
~ApplicationWin32() ~ApplicationWin32() {
{
for (auto& p : m_allWindows) for (auto& p : m_allWindows)
if (auto w = p.second.lock()) if (auto w = p.second.lock())
w->_cleanup(); w->_cleanup();
} }
SystemStringView getUniqueName() const SystemStringView getUniqueName() const { return m_uniqueName; }
{
return m_uniqueName;
}
SystemStringView getFriendlyName() const SystemStringView getFriendlyName() const { return m_friendlyName; }
{
return m_friendlyName;
}
SystemStringView getProcessName() const SystemStringView getProcessName() const { return m_pname; }
{
return m_pname;
}
const std::vector<SystemString>& getArgs() const const std::vector<SystemString>& getArgs() const { return m_args; }
{
return m_args;
}
std::shared_ptr<IWindow> m_mwret; std::shared_ptr<IWindow> m_mwret;
std::shared_ptr<IWindow> newWindow(SystemStringView title) std::shared_ptr<IWindow> newWindow(SystemStringView title) {
{ if (GetCurrentThreadId() != g_mainThreadId) {
if (GetCurrentThreadId() != g_mainThreadId)
{
std::unique_lock<std::mutex> lk(g_nwmt); std::unique_lock<std::mutex> lk(g_nwmt);
if (!PostThreadMessageW(g_mainThreadId, WM_USER, WPARAM(&title), 0)) if (!PostThreadMessageW(g_mainThreadId, WM_USER, WPARAM(&title), 0))
Log.report(logvisor::Fatal, "PostThreadMessage error"); Log.report(logvisor::Fatal, "PostThreadMessage error");
@ -514,32 +444,22 @@ public:
}; };
IApplication* APP = NULL; IApplication* APP = NULL;
int ApplicationRun(IApplication::EPlatformType platform, int ApplicationRun(IApplication::EPlatformType platform, IApplicationCallback& cb, SystemStringView uniqueName,
IApplicationCallback& cb, SystemStringView friendlyName, SystemStringView pname, const std::vector<SystemString>& args,
SystemStringView uniqueName, std::string_view gfxApi, uint32_t samples, uint32_t anisotropy, bool deepColor,
SystemStringView friendlyName, bool singleInstance) {
SystemStringView pname,
const std::vector<SystemString>& args,
std::string_view gfxApi,
uint32_t samples,
uint32_t anisotropy,
bool deepColor,
bool singleInstance)
{
std::string thrName = WCSTMBS(friendlyName.data()) + " Main Thread"; std::string thrName = WCSTMBS(friendlyName.data()) + " Main Thread";
logvisor::RegisterThreadName(thrName.c_str()); logvisor::RegisterThreadName(thrName.c_str());
if (APP) if (APP)
return 1; return 1;
if (platform != IApplication::EPlatformType::Win32 && if (platform != IApplication::EPlatformType::Win32 && platform != IApplication::EPlatformType::Auto)
platform != IApplication::EPlatformType::Auto)
return 1; return 1;
#if _WIN32_WINNT_WINBLUE #if _WIN32_WINNT_WINBLUE
/* HI-DPI support */ /* HI-DPI support */
HMODULE shcoreLib = LoadLibraryW(L"Shcore.dll"); HMODULE shcoreLib = LoadLibraryW(L"Shcore.dll");
if (shcoreLib) if (shcoreLib)
MyGetScaleFactorForMonitor = MyGetScaleFactorForMonitor = (PFN_GetScaleFactorForMonitor)GetProcAddress(shcoreLib, "GetScaleFactorForMonitor");
(PFN_GetScaleFactorForMonitor)GetProcAddress(shcoreLib, "GetScaleFactorForMonitor");
#endif #endif
WIN32_CURSORS.m_arrow = LoadCursor(nullptr, IDC_ARROW); WIN32_CURSORS.m_arrow = LoadCursor(nullptr, IDC_ARROW);
@ -550,43 +470,26 @@ int ApplicationRun(IApplication::EPlatformType platform,
WIN32_CURSORS.m_wait = LoadCursor(nullptr, IDC_WAIT); WIN32_CURSORS.m_wait = LoadCursor(nullptr, IDC_WAIT);
/* One class for *all* boo windows */ /* One class for *all* boo windows */
WNDCLASS wndClass = WNDCLASS wndClass = {0, WindowProc, 0, 0, GetModuleHandle(nullptr), 0, 0, 0, 0, L"BooWindow"};
{
0,
WindowProc,
0,
0,
GetModuleHandle(nullptr),
0,
0,
0,
0,
L"BooWindow"
};
wndClass.hIcon = LoadIconW(wndClass.hInstance, MAKEINTRESOURCEW(101)); wndClass.hIcon = LoadIconW(wndClass.hInstance, MAKEINTRESOURCEW(101));
wndClass.hCursor = WIN32_CURSORS.m_arrow; wndClass.hCursor = WIN32_CURSORS.m_arrow;
RegisterClassW(&wndClass); RegisterClassW(&wndClass);
APP = new ApplicationWin32(cb, uniqueName, friendlyName, pname, args, APP = new ApplicationWin32(cb, uniqueName, friendlyName, pname, args, gfxApi, samples, anisotropy, deepColor,
gfxApi, samples, anisotropy, deepColor, singleInstance); singleInstance);
int ret = APP->run(); int ret = APP->run();
delete APP; delete APP;
APP = nullptr; APP = nullptr;
return ret; return ret;
} }
} } // namespace boo
static const DEV_BROADCAST_DEVICEINTERFACE HOTPLUG_CONF = static const DEV_BROADCAST_DEVICEINTERFACE HOTPLUG_CONF = {sizeof(DEV_BROADCAST_DEVICEINTERFACE),
{ DBT_DEVTYP_DEVICEINTERFACE};
sizeof(DEV_BROADCAST_DEVICEINTERFACE),
DBT_DEVTYP_DEVICEINTERFACE
};
static bool HOTPLUG_REGISTERED = false; static bool HOTPLUG_REGISTERED = false;
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
{ if (!HOTPLUG_REGISTERED && uMsg == WM_CREATE) {
if (!HOTPLUG_REGISTERED && uMsg == WM_CREATE)
{
/* Register hotplug notification with windows */ /* Register hotplug notification with windows */
RegisterDeviceNotification(hwnd, (LPVOID)&HOTPLUG_CONF, RegisterDeviceNotification(hwnd, (LPVOID)&HOTPLUG_CONF,
DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
@ -594,4 +497,3 @@ static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
} }
return static_cast<boo::ApplicationWin32*>(boo::APP)->winHwndHandler(hwnd, uMsg, wParam, lParam); return static_cast<boo::ApplicationWin32*>(boo::APP)->winHwndHandler(hwnd, uMsg, wParam, lParam);
} }

Some files were not shown because too many files have changed in this diff Show More