mirror of https://github.com/AxioDL/boo.git
New code style refactor
This commit is contained in:
parent
2c2c72bfd1
commit
058ea23a00
|
@ -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()};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,50 +4,80 @@
|
||||||
#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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
@ -43,52 +40,35 @@ public:
|
||||||
NX = 10,
|
NX = 10,
|
||||||
Qt = 11
|
Qt = 11
|
||||||
};
|
};
|
||||||
virtual EPlatformType getPlatformType() const=0;
|
virtual EPlatformType getPlatformType() const = 0;
|
||||||
|
|
||||||
virtual int run()=0;
|
virtual int run() = 0;
|
||||||
virtual SystemStringView getUniqueName() const=0;
|
virtual SystemStringView getUniqueName() const = 0;
|
||||||
virtual SystemStringView getFriendlyName() const=0;
|
virtual SystemStringView getFriendlyName() const = 0;
|
||||||
virtual SystemStringView getProcessName() const=0;
|
virtual SystemStringView getProcessName() const = 0;
|
||||||
virtual const std::vector<SystemString>& getArgs() const=0;
|
virtual const std::vector<SystemString>& getArgs() const = 0;
|
||||||
|
|
||||||
/* Constructors/initializers for sub-objects */
|
/* Constructors/initializers for sub-objects */
|
||||||
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,
|
bool singleInstance = true);
|
||||||
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);
|
|
||||||
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
|
||||||
|
|
|
@ -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,
|
||||||
|
@ -41,23 +36,22 @@ public:
|
||||||
|
|
||||||
virtual ~IGraphicsContext() = default;
|
virtual ~IGraphicsContext() = default;
|
||||||
|
|
||||||
virtual EGraphicsAPI getAPI() const=0;
|
virtual EGraphicsAPI getAPI() const = 0;
|
||||||
virtual EPixelFormat getPixelFormat() const=0;
|
virtual EPixelFormat getPixelFormat() const = 0;
|
||||||
virtual void setPixelFormat(EPixelFormat pf)=0;
|
virtual void setPixelFormat(EPixelFormat pf) = 0;
|
||||||
virtual bool initializeContext(void* handle)=0;
|
virtual bool initializeContext(void* handle) = 0;
|
||||||
virtual void makeCurrent()=0;
|
virtual void makeCurrent() = 0;
|
||||||
virtual void postInit()=0;
|
virtual void postInit() = 0;
|
||||||
virtual void present()=0;
|
virtual void present() = 0;
|
||||||
|
|
||||||
virtual IGraphicsCommandQueue* getCommandQueue()=0;
|
virtual IGraphicsCommandQueue* getCommandQueue() = 0;
|
||||||
virtual IGraphicsDataFactory* getDataFactory()=0;
|
virtual IGraphicsDataFactory* getDataFactory() = 0;
|
||||||
|
|
||||||
/* Creates a new context on current thread!! Call from main client thread */
|
/* Creates a new context on current thread!! Call from main client thread */
|
||||||
virtual IGraphicsDataFactory* getMainContextDataFactory()=0;
|
virtual IGraphicsDataFactory* getMainContextDataFactory() = 0;
|
||||||
|
|
||||||
/* Creates a new context on current thread!! Call from client loading thread */
|
/* Creates a new context on current thread!! Call from client loading thread */
|
||||||
virtual IGraphicsDataFactory* getLoadContextDataFactory()=0;
|
virtual IGraphicsDataFactory* getLoadContextDataFactory() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace boo
|
||||||
|
|
||||||
|
|
|
@ -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,183 +118,176 @@ 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,
|
||||||
Shift = 1<<3,
|
Shift = 1 << 3,
|
||||||
Command = 1<<4,
|
Command = 1 << 4,
|
||||||
CtrlCommand = EModifierKey::Ctrl | EModifierKey::Command
|
CtrlCommand = EModifierKey::Ctrl | EModifierKey::Command
|
||||||
};
|
};
|
||||||
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, const std::pair<int, int>& selectedRange,
|
||||||
virtual void setMarkedText(std::string_view str,
|
const std::pair<int, int>& replacementRange) = 0;
|
||||||
const std::pair<int,int>& selectedRange,
|
virtual void unmarkText() = 0;
|
||||||
const std::pair<int,int>& replacementRange)=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) {
|
||||||
virtual void modKeyUp(EModifierKey mod) {(void)mod;}
|
(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 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,
|
||||||
Close = 1<<2,
|
Close = 1 << 2,
|
||||||
|
|
||||||
Default = Titlebar | Resize | Close
|
Default = Titlebar | Resize | Close
|
||||||
};
|
};
|
||||||
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;
|
||||||
|
|
||||||
virtual void closeWindow()=0;
|
virtual void closeWindow() = 0;
|
||||||
virtual void showWindow()=0;
|
virtual void showWindow() = 0;
|
||||||
virtual void hideWindow()=0;
|
virtual void hideWindow() = 0;
|
||||||
|
|
||||||
virtual SystemString getTitle()=0;
|
virtual SystemString getTitle() = 0;
|
||||||
virtual void setTitle(SystemStringView title)=0;
|
virtual void setTitle(SystemStringView title) = 0;
|
||||||
|
|
||||||
virtual void setCursor(EMouseCursor cursor)=0;
|
virtual void setCursor(EMouseCursor cursor) = 0;
|
||||||
virtual void setWaitCursor(bool wait)=0;
|
virtual void setWaitCursor(bool wait) = 0;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
virtual bool isFullscreen() const=0;
|
virtual bool isFullscreen() const = 0;
|
||||||
virtual void setFullscreen(bool fs)=0;
|
virtual void setFullscreen(bool fs) = 0;
|
||||||
|
|
||||||
virtual void claimKeyboardFocus(const int coord[2])=0;
|
virtual void claimKeyboardFocus(const int coord[2]) = 0;
|
||||||
virtual bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz)=0;
|
virtual bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) = 0;
|
||||||
virtual std::unique_ptr<uint8_t[]> clipboardPaste(EClipboardType type, size_t& sz)=0;
|
virtual std::unique_ptr<uint8_t[]> clipboardPaste(EClipboardType type, size_t& sz) = 0;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
virtual void setStyle(EWindowStyle style)=0;
|
virtual void setStyle(EWindowStyle style) = 0;
|
||||||
virtual EWindowStyle getStyle() const=0;
|
virtual EWindowStyle getStyle() const = 0;
|
||||||
|
|
||||||
virtual void setTouchBarProvider(void*) {}
|
virtual void setTouchBarProvider(void*) {}
|
||||||
|
|
||||||
virtual IGraphicsCommandQueue* getCommandQueue()=0;
|
virtual IGraphicsCommandQueue* getCommandQueue() = 0;
|
||||||
virtual IGraphicsDataFactory* getDataFactory()=0;
|
virtual IGraphicsDataFactory* getDataFactory() = 0;
|
||||||
|
|
||||||
/* Creates a new context on current thread!! Call from main client thread */
|
/* Creates a new context on current thread!! Call from main client thread */
|
||||||
virtual IGraphicsDataFactory* getMainContextDataFactory()=0;
|
virtual IGraphicsDataFactory* getMainContextDataFactory() = 0;
|
||||||
|
|
||||||
/* Creates a new context on current thread!! Call from client loading thread */
|
/* Creates a new context on current thread!! Call from client loading thread */
|
||||||
virtual IGraphicsDataFactory* getLoadContextDataFactory()=0;
|
virtual IGraphicsDataFactory* getLoadContextDataFactory() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace boo
|
||||||
|
|
||||||
|
|
|
@ -14,68 +14,65 @@
|
||||||
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>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#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>; \
|
||||||
{\
|
return type(static_cast<T>(a) & static_cast<T>(b)); \
|
||||||
using T = std::underlying_type_t<type>;\
|
} \
|
||||||
return type(static_cast<T>(a) & static_cast<T>(b));\
|
inline type& operator|=(type& a, const type& b) { \
|
||||||
}\
|
using T = std::underlying_type_t<type>; \
|
||||||
inline type& operator|=(type& a, const type& b)\
|
a = type(static_cast<T>(a) | static_cast<T>(b)); \
|
||||||
{\
|
return a; \
|
||||||
using T = std::underlying_type_t<type>;\
|
} \
|
||||||
a = type(static_cast<T>(a) | static_cast<T>(b));\
|
inline type& operator&=(type& a, const type& b) { \
|
||||||
return a;\
|
using T = std::underlying_type_t<type>; \
|
||||||
}\
|
a = type(static_cast<T>(a) & static_cast<T>(b)); \
|
||||||
inline type& operator&=(type& a, const type& b)\
|
return a; \
|
||||||
{\
|
} \
|
||||||
using T = std::underlying_type_t<type>;\
|
inline type operator~(const type& key) { \
|
||||||
a = type(static_cast<T>(a) & static_cast<T>(b));\
|
using T = std::underlying_type_t<type>; \
|
||||||
return a;\
|
return type(~static_cast<T>(key)); \
|
||||||
}\
|
}
|
||||||
inline type operator~(const type& key)\
|
|
||||||
{\
|
|
||||||
using T = std::underlying_type_t<type>;\
|
|
||||||
return type(~static_cast<T>(key));\
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace boo
|
namespace boo {
|
||||||
{
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
using SystemString = std::wstring;
|
using SystemString = std::wstring;
|
||||||
using SystemStringView = std::wstring_view;
|
using SystemStringView = std::wstring_view;
|
||||||
using SystemChar = wchar_t;
|
using SystemChar = wchar_t;
|
||||||
# ifndef _SYS_STR
|
#ifndef _SYS_STR
|
||||||
# define _SYS_STR(val) L ## val
|
#define _SYS_STR(val) L##val
|
||||||
# endif
|
#endif
|
||||||
#else
|
#else
|
||||||
using SystemString = std::string;
|
using SystemString = std::string;
|
||||||
using SystemStringView = std::string_view;
|
using SystemStringView = std::string_view;
|
||||||
using SystemChar = char;
|
using SystemChar = char;
|
||||||
# ifndef _SYS_STR
|
#ifndef _SYS_STR
|
||||||
# define _SYS_STR(val) val
|
#define _SYS_STR(val) val
|
||||||
# endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#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
|
||||||
|
|
||||||
|
|
|
@ -9,25 +9,25 @@
|
||||||
|
|
||||||
/** 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); }
|
||||||
T* get() const {return static_cast<T*>(TlsGetValue(m_key));}
|
T* get() const { return static_cast<T*>(TlsGetValue(m_key)); }
|
||||||
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); }
|
||||||
T* get() const {return static_cast<T*>(pthread_getspecific(m_key));}
|
T* get() const { return static_cast<T*>(pthread_getspecific(m_key)); }
|
||||||
void reset(T* v=nullptr) {pthread_setspecific(m_key, v);}
|
void reset(T* v = nullptr) { pthread_setspecific(m_key, v); }
|
||||||
#endif
|
#endif
|
||||||
T* operator->() {return get();}
|
T* operator->() { return get(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -2,36 +2,31 @@
|
||||||
|
|
||||||
#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);
|
||||||
m_args.emplace_back(selfPath);
|
m_args.emplace_back(selfPath);
|
||||||
for (Platform::String^ str : params)
|
for (Platform::String ^ str : params)
|
||||||
m_args.emplace_back(str->Data());
|
m_args.emplace_back(str->Data());
|
||||||
}
|
}
|
||||||
public:
|
|
||||||
virtual IFrameworkView^ CreateView();
|
|
||||||
|
|
||||||
internal:
|
public:
|
||||||
boo::IApplicationCallback& m_appCb;
|
virtual IFrameworkView ^ CreateView();
|
||||||
|
|
||||||
|
internal : 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
|
||||||
|
|
||||||
|
|
|
@ -5,51 +5,39 @@
|
||||||
#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;
|
||||||
|
|
||||||
/** Set channel-levels for target submix (AudioChannel enum for array index) */
|
/** Set channel-levels for target submix (AudioChannel enum for array index) */
|
||||||
virtual void setSendLevel(IAudioSubmix* submix, float level, bool slew)=0;
|
virtual void setSendLevel(IAudioSubmix* submix, float level, bool slew) = 0;
|
||||||
|
|
||||||
/** Gets fixed sample rate of submix this way */
|
/** Gets fixed sample rate of submix this way */
|
||||||
virtual double getSampleRate() const=0;
|
virtual double getSampleRate() const = 0;
|
||||||
|
|
||||||
/** Gets fixed sample format of submix this way */
|
/** Gets fixed sample format of submix this way */
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -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,62 +37,57 @@ 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;
|
||||||
|
|
||||||
/** Reset channel-levels to silence; unbind all submixes */
|
/** Reset channel-levels to silence; unbind all submixes */
|
||||||
virtual void resetChannelLevels()=0;
|
virtual void resetChannelLevels() = 0;
|
||||||
|
|
||||||
/** Set channel-levels for mono audio source (AudioChannel enum for array index) */
|
/** Set channel-levels for mono audio source (AudioChannel enum for array index) */
|
||||||
virtual void setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew)=0;
|
virtual void setMonoChannelLevels(IAudioSubmix* submix, const float coefs[8], bool slew) = 0;
|
||||||
|
|
||||||
/** Set channel-levels for stereo audio source (AudioChannel enum for array index) */
|
/** Set channel-levels for stereo audio source (AudioChannel enum for array index) */
|
||||||
virtual void setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew)=0;
|
virtual void setStereoChannelLevels(IAudioSubmix* submix, const float coefs[8][2], bool slew) = 0;
|
||||||
|
|
||||||
/** Called by client to dynamically adjust the pitch of voices with dynamic pitch enabled */
|
/** Called by client to dynamically adjust the pitch of voices with dynamic pitch enabled */
|
||||||
virtual void setPitchRatio(double ratio, bool slew)=0;
|
virtual void setPitchRatio(double ratio, bool slew) = 0;
|
||||||
|
|
||||||
/** Instructs platform to begin consuming sample data; invoking callback as needed */
|
/** Instructs platform to begin consuming sample data; invoking callback as needed */
|
||||||
virtual void start()=0;
|
virtual void start() = 0;
|
||||||
|
|
||||||
/** Instructs platform to stop consuming sample data */
|
/** Instructs platform to stop consuming sample data */
|
||||||
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;
|
||||||
|
|
||||||
/** boo calls this on behalf of the audio platform to request more audio
|
/** boo calls this on behalf of the audio platform to request more audio
|
||||||
* frames from the client */
|
* frames from the client */
|
||||||
virtual size_t supplyAudio(IAudioVoice& voice, size_t frames, int16_t* data)=0;
|
virtual size_t supplyAudio(IAudioVoice& voice, size_t frames, int16_t* data) = 0;
|
||||||
|
|
||||||
/** 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
|
||||||
|
|
||||||
|
|
|
@ -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,71 +33,69 @@ 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 */
|
||||||
virtual ObjToken<IAudioSubmix> allocateNewSubmix(bool mainOut, IAudioSubmixCallback* cb, int busId)=0;
|
virtual ObjToken<IAudioSubmix> allocateNewSubmix(bool mainOut, IAudioSubmixCallback* cb, int busId) = 0;
|
||||||
|
|
||||||
/** Client can register for key callback events from the mixing engine this way */
|
/** Client can register for key callback events from the mixing engine this way */
|
||||||
virtual void setCallbackInterface(IAudioVoiceEngineCallback* cb)=0;
|
virtual void setCallbackInterface(IAudioVoiceEngineCallback* cb) = 0;
|
||||||
|
|
||||||
/** Client may use this to determine current speaker-setup */
|
/** Client may use this to determine current speaker-setup */
|
||||||
virtual AudioChannelSet getAvailableSet()=0;
|
virtual AudioChannelSet getAvailableSet() = 0;
|
||||||
|
|
||||||
/** Ensure backing platform buffer is filled as much as possible with mixed samples */
|
/** Ensure backing platform buffer is filled as much as possible with mixed samples */
|
||||||
virtual void pumpAndMixVoices()=0;
|
virtual void pumpAndMixVoices() = 0;
|
||||||
|
|
||||||
/** Set total volume of engine */
|
/** Set total volume of engine */
|
||||||
virtual void setVolume(float vol)=0;
|
virtual void setVolume(float vol) = 0;
|
||||||
|
|
||||||
/** Enable or disable Lt/Rt surround encoding. If successful, getAvailableSet() will return Surround51 */
|
/** Enable or disable Lt/Rt surround encoding. If successful, getAvailableSet() will return Surround51 */
|
||||||
virtual bool enableLtRt(bool enable)=0;
|
virtual bool enableLtRt(bool enable) = 0;
|
||||||
|
|
||||||
/** Get current Audio output in use */
|
/** Get current Audio output in use */
|
||||||
virtual std::string getCurrentAudioOutput() const=0;
|
virtual std::string getCurrentAudioOutput() const = 0;
|
||||||
|
|
||||||
/** Set current Audio output to use */
|
/** Set current Audio output to use */
|
||||||
virtual bool setCurrentAudioOutput(const char* name)=0;
|
virtual bool setCurrentAudioOutput(const char* name) = 0;
|
||||||
|
|
||||||
/** Get list of Audio output devices found on system */
|
/** Get list of Audio output devices found on system */
|
||||||
virtual std::vector<std::pair<std::string, std::string>> enumerateAudioOutputs() const=0;
|
virtual std::vector<std::pair<std::string, std::string>> enumerateAudioOutputs() const = 0;
|
||||||
|
|
||||||
/** Get list of MIDI input devices found on system */
|
/** Get list of MIDI input devices found on system */
|
||||||
virtual std::vector<std::pair<std::string, std::string>> enumerateMIDIInputs() const=0;
|
virtual std::vector<std::pair<std::string, std::string>> enumerateMIDIInputs() const = 0;
|
||||||
|
|
||||||
/** Query if system supports creating a virtual MIDI input */
|
/** Query if system supports creating a virtual MIDI input */
|
||||||
virtual bool supportsVirtualMIDIIn() const=0;
|
virtual bool supportsVirtualMIDIIn() const = 0;
|
||||||
|
|
||||||
/** Create ad-hoc MIDI in port and register with system */
|
/** Create ad-hoc MIDI in port and register with system */
|
||||||
virtual std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver)=0;
|
virtual std::unique_ptr<IMIDIIn> newVirtualMIDIIn(ReceiveFunctor&& receiver) = 0;
|
||||||
|
|
||||||
/** Create ad-hoc MIDI out port and register with system */
|
/** Create ad-hoc MIDI out port and register with system */
|
||||||
virtual std::unique_ptr<IMIDIOut> newVirtualMIDIOut()=0;
|
virtual std::unique_ptr<IMIDIOut> newVirtualMIDIOut() = 0;
|
||||||
|
|
||||||
/** Create ad-hoc MIDI in/out port and register with system */
|
/** Create ad-hoc MIDI in/out port and register with system */
|
||||||
virtual std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver)=0;
|
virtual std::unique_ptr<IMIDIInOut> newVirtualMIDIInOut(ReceiveFunctor&& receiver) = 0;
|
||||||
|
|
||||||
/** Open named MIDI in port, name format depends on OS */
|
/** Open named MIDI in port, name format depends on OS */
|
||||||
virtual std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver)=0;
|
virtual std::unique_ptr<IMIDIIn> newRealMIDIIn(const char* name, ReceiveFunctor&& receiver) = 0;
|
||||||
|
|
||||||
/** Open named MIDI out port, name format depends on OS */
|
/** Open named MIDI out port, name format depends on OS */
|
||||||
virtual std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name)=0;
|
virtual std::unique_ptr<IMIDIOut> newRealMIDIOut(const char* name) = 0;
|
||||||
|
|
||||||
/** Open named MIDI in/out port, name format depends on OS */
|
/** Open named MIDI in/out port, name format depends on OS */
|
||||||
virtual std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver)=0;
|
virtual std::unique_ptr<IMIDIInOut> newRealMIDIInOut(const char* name, ReceiveFunctor&& receiver) = 0;
|
||||||
|
|
||||||
/** If this returns true, MIDI callbacks are assumed to be *not* thread-safe; need protection via mutex */
|
/** If this returns true, MIDI callbacks are assumed to be *not* thread-safe; need protection via mutex */
|
||||||
virtual bool useMIDILock() const=0;
|
virtual bool useMIDILock() const = 0;
|
||||||
|
|
||||||
/** Get canonical count of frames for each 5ms output block */
|
/** Get canonical count of frames for each 5ms output block */
|
||||||
virtual size_t get5MsFrames() const=0;
|
virtual size_t get5MsFrames() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Construct host platform's voice engine */
|
/** Construct host platform's voice engine */
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -5,58 +5,56 @@
|
||||||
#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; }
|
||||||
virtual std::string description() const=0;
|
virtual std::string description() const = 0;
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -3,39 +3,36 @@
|
||||||
#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;
|
||||||
virtual void notePressure(uint8_t chan, uint8_t key, uint8_t pressure)=0;
|
virtual void notePressure(uint8_t chan, uint8_t key, uint8_t pressure) = 0;
|
||||||
virtual void controlChange(uint8_t chan, uint8_t control, uint8_t value)=0;
|
virtual void controlChange(uint8_t chan, uint8_t control, uint8_t value) = 0;
|
||||||
virtual void programChange(uint8_t chan, uint8_t program)=0;
|
virtual void programChange(uint8_t chan, uint8_t program) = 0;
|
||||||
virtual void channelPressure(uint8_t chan, uint8_t pressure)=0;
|
virtual void channelPressure(uint8_t chan, uint8_t pressure) = 0;
|
||||||
virtual void pitchBend(uint8_t chan, int16_t pitch)=0;
|
virtual void pitchBend(uint8_t chan, int16_t pitch) = 0;
|
||||||
|
|
||||||
virtual void allSoundOff(uint8_t chan)=0;
|
virtual void allSoundOff(uint8_t chan) = 0;
|
||||||
virtual void resetAllControllers(uint8_t chan)=0;
|
virtual void resetAllControllers(uint8_t chan) = 0;
|
||||||
virtual void localControl(uint8_t chan, bool on)=0;
|
virtual void localControl(uint8_t chan, bool on) = 0;
|
||||||
virtual void allNotesOff(uint8_t chan)=0;
|
virtual void allNotesOff(uint8_t chan) = 0;
|
||||||
virtual void omniMode(uint8_t chan, bool on)=0;
|
virtual void omniMode(uint8_t chan, bool on) = 0;
|
||||||
virtual void polyMode(uint8_t chan, bool on)=0;
|
virtual void polyMode(uint8_t chan, bool on) = 0;
|
||||||
|
|
||||||
virtual void sysex(const void* data, size_t len)=0;
|
virtual void sysex(const void* data, size_t len) = 0;
|
||||||
virtual void timeCodeQuarterFrame(uint8_t message, uint8_t value)=0;
|
virtual void timeCodeQuarterFrame(uint8_t message, uint8_t value) = 0;
|
||||||
virtual void songPositionPointer(uint16_t pointer)=0;
|
virtual void songPositionPointer(uint16_t pointer) = 0;
|
||||||
virtual void songSelect(uint8_t song)=0;
|
virtual void songSelect(uint8_t song) = 0;
|
||||||
virtual void tuneRequest()=0;
|
virtual void tuneRequest() = 0;
|
||||||
|
|
||||||
virtual void startSeq()=0;
|
virtual void startSeq() = 0;
|
||||||
virtual void continueSeq()=0;
|
virtual void continueSeq() = 0;
|
||||||
virtual void stopSeq()=0;
|
virtual void stopSeq() = 0;
|
||||||
|
|
||||||
virtual void reset()=0;
|
virtual void reset() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace boo
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -9,33 +9,29 @@
|
||||||
#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"); }
|
||||||
|
|
||||||
boo::ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
|
boo::ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
|
||||||
boo::ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
|
boo::ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -4,47 +4,46 @@
|
||||||
#define BOO_GLSL_MAX_TEXTURE_COUNT 8
|
#define BOO_GLSL_MAX_TEXTURE_COUNT 8
|
||||||
|
|
||||||
#define BOO_GLSL_BINDING_HEAD \
|
#define BOO_GLSL_BINDING_HEAD \
|
||||||
"#ifdef VULKAN\n" \
|
"#ifdef VULKAN\n" \
|
||||||
"#define gl_VertexID gl_VertexIndex\n" \
|
"#define gl_VertexID gl_VertexIndex\n" \
|
||||||
"#extension GL_ARB_separate_shader_objects: enable\n" \
|
"#extension GL_ARB_separate_shader_objects: enable\n" \
|
||||||
"#define SBINDING(idx) layout(location=idx)\n" \
|
"#define SBINDING(idx) layout(location=idx)\n" \
|
||||||
"#else\n" \
|
"#else\n" \
|
||||||
"#define SBINDING(idx)\n" \
|
"#define SBINDING(idx)\n" \
|
||||||
"#endif\n" \
|
"#endif\n" \
|
||||||
"#extension GL_ARB_shading_language_420pack: enable\n" \
|
"#extension GL_ARB_shading_language_420pack: enable\n" \
|
||||||
"#ifdef GL_ARB_shading_language_420pack\n" \
|
"#ifdef GL_ARB_shading_language_420pack\n" \
|
||||||
"#define UBINDING0 layout(binding=0)\n" \
|
"#define UBINDING0 layout(binding=0)\n" \
|
||||||
"#define UBINDING1 layout(binding=1)\n" \
|
"#define UBINDING1 layout(binding=1)\n" \
|
||||||
"#define UBINDING2 layout(binding=2)\n" \
|
"#define UBINDING2 layout(binding=2)\n" \
|
||||||
"#define UBINDING3 layout(binding=3)\n" \
|
"#define UBINDING3 layout(binding=3)\n" \
|
||||||
"#define UBINDING4 layout(binding=4)\n" \
|
"#define UBINDING4 layout(binding=4)\n" \
|
||||||
"#define UBINDING5 layout(binding=5)\n" \
|
"#define UBINDING5 layout(binding=5)\n" \
|
||||||
"#define UBINDING6 layout(binding=6)\n" \
|
"#define UBINDING6 layout(binding=6)\n" \
|
||||||
"#define UBINDING7 layout(binding=7)\n" \
|
"#define UBINDING7 layout(binding=7)\n" \
|
||||||
"#define TBINDING0 layout(binding=8)\n" \
|
"#define TBINDING0 layout(binding=8)\n" \
|
||||||
"#define TBINDING1 layout(binding=9)\n" \
|
"#define TBINDING1 layout(binding=9)\n" \
|
||||||
"#define TBINDING2 layout(binding=10)\n" \
|
"#define TBINDING2 layout(binding=10)\n" \
|
||||||
"#define TBINDING3 layout(binding=11)\n" \
|
"#define TBINDING3 layout(binding=11)\n" \
|
||||||
"#define TBINDING4 layout(binding=12)\n" \
|
"#define TBINDING4 layout(binding=12)\n" \
|
||||||
"#define TBINDING5 layout(binding=13)\n" \
|
"#define TBINDING5 layout(binding=13)\n" \
|
||||||
"#define TBINDING6 layout(binding=14)\n" \
|
"#define TBINDING6 layout(binding=14)\n" \
|
||||||
"#define TBINDING7 layout(binding=15)\n" \
|
"#define TBINDING7 layout(binding=15)\n" \
|
||||||
"#else\n" \
|
"#else\n" \
|
||||||
"#define UBINDING0\n" \
|
"#define UBINDING0\n" \
|
||||||
"#define UBINDING1\n" \
|
"#define UBINDING1\n" \
|
||||||
"#define UBINDING2\n" \
|
"#define UBINDING2\n" \
|
||||||
"#define UBINDING3\n" \
|
"#define UBINDING3\n" \
|
||||||
"#define UBINDING4\n" \
|
"#define UBINDING4\n" \
|
||||||
"#define UBINDING5\n" \
|
"#define UBINDING5\n" \
|
||||||
"#define UBINDING6\n" \
|
"#define UBINDING6\n" \
|
||||||
"#define UBINDING7\n" \
|
"#define UBINDING7\n" \
|
||||||
"#define TBINDING0\n" \
|
"#define TBINDING0\n" \
|
||||||
"#define TBINDING1\n" \
|
"#define TBINDING1\n" \
|
||||||
"#define TBINDING2\n" \
|
"#define TBINDING2\n" \
|
||||||
"#define TBINDING3\n" \
|
"#define TBINDING3\n" \
|
||||||
"#define TBINDING4\n" \
|
"#define TBINDING4\n" \
|
||||||
"#define TBINDING5\n" \
|
"#define TBINDING5\n" \
|
||||||
"#define TBINDING6\n" \
|
"#define TBINDING6\n" \
|
||||||
"#define TBINDING7\n" \
|
"#define TBINDING7\n" \
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
|
|
||||||
|
|
|
@ -4,41 +4,38 @@
|
||||||
#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;
|
||||||
virtual Platform platform() const=0;
|
virtual Platform platform() const = 0;
|
||||||
virtual const SystemChar* platformName() const=0;
|
virtual const SystemChar* platformName() const = 0;
|
||||||
|
|
||||||
virtual void setShaderDataBinding(const ObjToken<IShaderDataBinding>& binding)=0;
|
virtual void setShaderDataBinding(const ObjToken<IShaderDataBinding>& binding) = 0;
|
||||||
virtual void setRenderTarget(const ObjToken<ITextureR>& target)=0;
|
virtual void setRenderTarget(const ObjToken<ITextureR>& target) = 0;
|
||||||
virtual void setViewport(const SWindowRect& rect, float znear=0.f, float zfar=1.f)=0;
|
virtual void setViewport(const SWindowRect& rect, float znear = 0.f, float zfar = 1.f) = 0;
|
||||||
virtual void setScissor(const SWindowRect& rect)=0;
|
virtual void setScissor(const SWindowRect& rect) = 0;
|
||||||
|
|
||||||
virtual void resizeRenderTexture(const ObjToken<ITextureR>& tex, size_t width, size_t height)=0;
|
virtual void resizeRenderTexture(const ObjToken<ITextureR>& tex, size_t width, size_t height) = 0;
|
||||||
virtual void schedulePostFrameHandler(std::function<void(void)>&& func)=0;
|
virtual void schedulePostFrameHandler(std::function<void(void)>&& func) = 0;
|
||||||
|
|
||||||
virtual void setClearColor(const float rgba[4])=0;
|
virtual void setClearColor(const float rgba[4]) = 0;
|
||||||
virtual void clearTarget(bool render=true, bool depth=true)=0;
|
virtual void clearTarget(bool render = true, bool depth = true) = 0;
|
||||||
|
|
||||||
virtual void draw(size_t start, size_t count)=0;
|
virtual void draw(size_t start, size_t count) = 0;
|
||||||
virtual void drawIndexed(size_t start, size_t count)=0;
|
virtual void drawIndexed(size_t start, size_t count) = 0;
|
||||||
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;
|
||||||
|
|
||||||
virtual void startRenderer()=0;
|
virtual void startRenderer() = 0;
|
||||||
virtual void stopRenderer()=0;
|
virtual void stopRenderer() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace boo
|
||||||
|
|
||||||
|
|
|
@ -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,103 +199,76 @@ 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 };
|
||||||
{
|
virtual Platform platform() const = 0;
|
||||||
Null,
|
virtual const SystemChar* platformName() const = 0;
|
||||||
OpenGL,
|
|
||||||
D3D11,
|
|
||||||
Metal,
|
|
||||||
Vulkan,
|
|
||||||
GX,
|
|
||||||
NX
|
|
||||||
};
|
|
||||||
virtual Platform platform() 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> newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
|
||||||
virtual ObjToken<ITextureSA>
|
TextureFormat fmt, TextureClampMode clampMode, const void* data,
|
||||||
newStaticArrayTexture(size_t width, size_t height, size_t layers, size_t mips,
|
size_t sz) = 0;
|
||||||
TextureFormat fmt, TextureClampMode clampMode, const void* data, size_t sz)=0;
|
virtual ObjToken<ITextureD> newDynamicTexture(size_t width, size_t height, TextureFormat fmt,
|
||||||
virtual ObjToken<ITextureD>
|
TextureClampMode clampMode) = 0;
|
||||||
newDynamicTexture(size_t width, size_t height, TextureFormat fmt, TextureClampMode clampMode)=0;
|
virtual ObjToken<ITextureR> newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
|
||||||
virtual ObjToken<ITextureR>
|
size_t colorBindingCount, size_t depthBindingCount) = 0;
|
||||||
newRenderTexture(size_t width, size_t height, TextureClampMode clampMode,
|
|
||||||
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 AdditionalPipelineInfo& additionalInfo)=0;
|
const VertexFormatInfo& vtxFmt,
|
||||||
|
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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void commitTransaction(const std::function<bool(Context& ctx)>& __BooTraceArgs)=0;
|
virtual void commitTransaction(const std::function<bool(Context& ctx)>& __BooTraceArgs) = 0;
|
||||||
virtual ObjToken<IGraphicsBufferD> newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs)=0;
|
virtual ObjToken<IGraphicsBufferD> newPoolBuffer(BufferUse use, size_t stride, size_t count __BooTraceArgs) = 0;
|
||||||
virtual void setDisplayGamma(float gamma)=0;
|
virtual void setDisplayGamma(float gamma) = 0;
|
||||||
virtual bool isTessellationSupported(uint32_t& maxPatchSizeOut)=0;
|
virtual bool isTessellationSupported(uint32_t& maxPatchSizeOut) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
using GraphicsDataFactoryContext = IGraphicsDataFactory::Context;
|
using GraphicsDataFactoryContext = IGraphicsDataFactory::Context;
|
||||||
using FactoryCommitFunc = std::function<bool(GraphicsDataFactoryContext& ctx)>;
|
using FactoryCommitFunc = std::function<bool(GraphicsDataFactoryContext& ctx)>;
|
||||||
|
|
||||||
}
|
} // namespace boo
|
||||||
|
|
||||||
|
|
|
@ -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__
|
||||||
|
|
|
@ -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,19 +38,18 @@ 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"); }
|
||||||
|
|
||||||
boo::ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
|
boo::ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
|
||||||
boo::ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
|
boo::ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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,41 +100,36 @@ 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"); }
|
||||||
|
|
||||||
boo::ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
|
boo::ObjToken<IGraphicsBufferS> newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count);
|
||||||
boo::ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
|
boo::ObjToken<IGraphicsBufferD> newDynamicBuffer(BufferUse use, size_t stride, size_t count);
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,23 +57,22 @@ 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;
|
||||||
struct st_context *m_st = nullptr;
|
struct st_context* m_st = nullptr;
|
||||||
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> offline_link(unsigned num_stages, const nx_shader_stage_object** stages,
|
||||||
std::pair<std::shared_ptr<uint8_t[]>, size_t>
|
std::string* infoLog = nullptr);
|
||||||
offline_link(unsigned num_stages, const nx_shader_stage_object **stages, std::string* infoLog = nullptr);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace boo
|
namespace boo {}
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -45,7 +38,7 @@ public:
|
||||||
void closeDevice();
|
void closeDevice();
|
||||||
|
|
||||||
/* Callbacks */
|
/* Callbacks */
|
||||||
virtual void deviceDisconnected()=0;
|
virtual void deviceDisconnected() = 0;
|
||||||
virtual void deviceError(const char* error, ...);
|
virtual void deviceError(const char* error, ...);
|
||||||
virtual void initialCycle() {}
|
virtual void initialCycle() {}
|
||||||
virtual void transferCycle() {}
|
virtual void transferCycle() {}
|
||||||
|
@ -68,25 +61,25 @@ public:
|
||||||
#else
|
#else
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -16,16 +16,14 @@
|
||||||
#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;
|
||||||
friend class HIDListenerWinUSB;
|
friend class HIDListenerWinUSB;
|
||||||
static inline DeviceFinder* instance() {return skDevFinder;}
|
static inline DeviceFinder* instance() { return skDevFinder; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static class DeviceFinder* skDevFinder;
|
static class DeviceFinder* skDevFinder;
|
||||||
|
@ -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,62 +71,53 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get interested device-type mask */
|
/* Get interested device-type mask */
|
||||||
inline const DeviceSignature::TDeviceSignatureSet& getTypes() const {return m_types;}
|
inline const DeviceSignature::TDeviceSignatureSet& getTypes() const { return m_types; }
|
||||||
|
|
||||||
/* Iterable set of tokens */
|
/* Iterable set of tokens */
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -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,21 +24,18 @@ 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);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEVICE_SIG(name, vid, pid, type) \
|
#define DEVICE_SIG(name, vid, pid, type) \
|
||||||
DeviceSignature(#name, dev_typeid(name), vid, pid,\
|
DeviceSignature(#name, dev_typeid(name), vid, pid, \
|
||||||
[](DeviceToken* tok) -> std::shared_ptr<DeviceBase> {return std::make_shared<name>(tok);}, type)
|
[](DeviceToken* tok) -> std::shared_ptr<DeviceBase> { return std::make_shared<name>(tok); }, type)
|
||||||
#define DEVICE_SIG_SENTINEL() DeviceSignature()
|
#define DEVICE_SIG_SENTINEL() DeviceSignature()
|
||||||
|
|
||||||
extern const DeviceSignature BOO_DEVICE_SIGS[];
|
extern const DeviceSignature BOO_DEVICE_SIGS[];
|
||||||
|
|
||||||
}
|
} // namespace boo
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,57 +20,46 @@ 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)
|
||||||
m_productName = pname;
|
m_productName = pname;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DeviceType getDeviceType() const {return m_devType;}
|
inline DeviceType getDeviceType() const { return m_devType; }
|
||||||
inline unsigned getVendorId() const {return m_vendorId;}
|
inline unsigned getVendorId() const { return m_vendorId; }
|
||||||
inline unsigned getProductId() const {return m_productId;}
|
inline unsigned getProductId() const { return m_productId; }
|
||||||
inline std::string_view getVendorName() const {return m_vendorName;}
|
inline std::string_view getVendorName() const { return m_vendorName; }
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -4,42 +4,37 @@
|
||||||
#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,
|
L = 1 << 3,
|
||||||
L = 1<<3,
|
A = 1 << 8,
|
||||||
A = 1<<8,
|
B = 1 << 9,
|
||||||
B = 1<<9,
|
X = 1 << 10,
|
||||||
X = 1<<10,
|
Y = 1 << 11,
|
||||||
Y = 1<<11,
|
Left = 1 << 12,
|
||||||
Left = 1<<12,
|
Right = 1 << 13,
|
||||||
Right = 1<<13,
|
Down = 1 << 14,
|
||||||
Down = 1<<14,
|
Up = 1 << 15
|
||||||
Up = 1<<15
|
|
||||||
};
|
};
|
||||||
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;
|
||||||
virtual void controllerDisconnected(unsigned idx) {(void)idx;}
|
(void)type;
|
||||||
virtual void controllerUpdate(unsigned idx, EDolphinControllerType type,
|
}
|
||||||
const DolphinControllerState& state) {(void)idx;(void)type;(void)state;}
|
virtual void controllerDisconnected(unsigned idx) { (void)idx; }
|
||||||
|
virtual void controllerUpdate(unsigned idx, EDolphinControllerType type, const DolphinControllerState& 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
|
||||||
|
|
||||||
|
|
|
@ -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,46 +36,36 @@ 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,
|
Start = 1 << 3,
|
||||||
Start = 1<< 3,
|
Up = 1 << 4,
|
||||||
Up = 1<< 4,
|
Right = 1 << 5,
|
||||||
Right = 1<< 5,
|
Down = 1 << 6,
|
||||||
Down = 1<< 6,
|
Left = 1 << 7,
|
||||||
Left = 1<< 7,
|
L2 = 1 << 8,
|
||||||
L2 = 1<< 8,
|
R2 = 1 << 9,
|
||||||
R2 = 1<< 9,
|
L1 = 1 << 10,
|
||||||
L1 = 1<<10,
|
R1 = 1 << 11,
|
||||||
R1 = 1<<11,
|
Triangle = 1 << 12,
|
||||||
Triangle = 1<<12,
|
Circle = 1 << 13,
|
||||||
Circle = 1<<13,
|
Cross = 1 << 14,
|
||||||
Cross = 1<<14,
|
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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -4,35 +4,31 @@
|
||||||
#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;
|
||||||
|
|
||||||
/* Automatic device scanning */
|
/* Automatic device scanning */
|
||||||
virtual bool startScanning()=0;
|
virtual bool startScanning() = 0;
|
||||||
virtual bool stopScanning()=0;
|
virtual bool stopScanning() = 0;
|
||||||
|
|
||||||
/* Manual device scanning */
|
/* Manual device scanning */
|
||||||
virtual bool scanNow()=0;
|
virtual bool scanNow() = 0;
|
||||||
|
|
||||||
#if _WIN32 && !WINDOWS_STORE
|
#if _WIN32 && !WINDOWS_STORE
|
||||||
/* External listener implementation (for Windows) */
|
/* External listener implementation (for Windows) */
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace boo
|
namespace boo {}
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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,43 +16,38 @@ 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,
|
||||||
};
|
};
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
/// A smart pointer that can manage the lifecycle of Core Foundation objects.
|
/// A smart pointer that can manage the lifecycle of Core Foundation objects.
|
||||||
template<typename T>
|
template <typename T>
|
||||||
class CFPointer {
|
class CFPointer {
|
||||||
public:
|
public:
|
||||||
CFPointer() : storage(nullptr) { }
|
CFPointer() : storage(nullptr) {}
|
||||||
|
|
||||||
CFPointer(T pointer) : storage(toStorageType(pointer)) {
|
CFPointer(T pointer) : storage(toStorageType(pointer)) {
|
||||||
if (storage) {
|
if (storage) {
|
||||||
|
@ -16,13 +16,13 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CFPointer(const CFPointer & other) : storage(other.storage) {
|
CFPointer(const CFPointer& other) : storage(other.storage) {
|
||||||
if (CFTypeRef ptr = storage) {
|
if (CFTypeRef ptr = storage) {
|
||||||
CFRetain(ptr);
|
CFRetain(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CFPointer(CFPointer && other) : storage(std::exchange(other.storage, nullptr)) { }
|
CFPointer(CFPointer&& other) : storage(std::exchange(other.storage, nullptr)) {}
|
||||||
|
|
||||||
~CFPointer() {
|
~CFPointer() {
|
||||||
if (CFTypeRef pointer = storage) {
|
if (CFTypeRef pointer = storage) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -65,26 +58,20 @@ private:
|
||||||
CFTypeRef storage;
|
CFTypeRef storage;
|
||||||
|
|
||||||
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.
|
||||||
template<typename T>
|
template <typename T>
|
||||||
class IUnknownPointer {
|
class IUnknownPointer {
|
||||||
public:
|
public:
|
||||||
IUnknownPointer() : _storage(nullptr) { }
|
IUnknownPointer() : _storage(nullptr) {}
|
||||||
|
|
||||||
IUnknownPointer(T** pointer) : _storage(toStorageType(pointer)) {
|
IUnknownPointer(T** pointer) : _storage(toStorageType(pointer)) {
|
||||||
if (_storage) {
|
if (_storage) {
|
||||||
|
@ -92,12 +79,12 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IUnknownPointer(const IUnknownPointer & other) : _storage(other._storage) {
|
IUnknownPointer(const IUnknownPointer& other) : _storage(other._storage) {
|
||||||
if (IUnknownVTbl** ptr = _storage) {
|
if (IUnknownVTbl** ptr = _storage) {
|
||||||
(*ptr)->AddRef(ptr);
|
(*ptr)->AddRef(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IUnknownPointer& operator=(const IUnknownPointer & other) {
|
IUnknownPointer& operator=(const IUnknownPointer& other) {
|
||||||
if (IUnknownVTbl** pointer = _storage) {
|
if (IUnknownVTbl** pointer = _storage) {
|
||||||
(*pointer)->Release(pointer);
|
(*pointer)->Release(pointer);
|
||||||
}
|
}
|
||||||
|
@ -108,7 +95,7 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
IUnknownPointer(IUnknownPointer && other) : _storage(std::exchange(other._storage, nullptr)) { }
|
IUnknownPointer(IUnknownPointer&& other) : _storage(std::exchange(other._storage, nullptr)) {}
|
||||||
|
|
||||||
~IUnknownPointer() {
|
~IUnknownPointer() {
|
||||||
if (IUnknownVTbl** pointer = _storage) {
|
if (IUnknownVTbl** pointer = _storage) {
|
||||||
|
@ -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; }
|
||||||
|
@ -138,18 +121,11 @@ private:
|
||||||
IUnknownVTbl** _storage;
|
IUnknownVTbl** _storage;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -685,19 +630,14 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -855,9 +782,8 @@ struct AQSAudioVoiceEngine : BaseAudioVoiceEngine
|
||||||
chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::Unknown;
|
chMapOut.m_channels[chMapOut.m_channelCount++] = AudioChannel::Unknown;
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,30 +65,26 @@ 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)
|
||||||
return false;
|
return false;
|
||||||
for (int i=0 ; i<8 ; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
if (m_coefs.v[i] > FLT_EPSILON)
|
if (m_coefs.v[i] > FLT_EPSILON)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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,25 +126,22 @@ 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)
|
||||||
return false;
|
return false;
|
||||||
for (int i=0 ; i<8 ; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
if (m_coefs.v[i][0] > FLT_EPSILON || m_coefs.v[i][1] > FLT_EPSILON)
|
if (m_coefs.v[i][0] > FLT_EPSILON || m_coefs.v[i][1] > FLT_EPSILON)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace boo
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -43,7 +41,7 @@ protected:
|
||||||
/* Deferred sample-rate reset */
|
/* Deferred sample-rate reset */
|
||||||
bool m_resetSampleRate = false;
|
bool m_resetSampleRate = false;
|
||||||
double m_deferredSampleRate;
|
double m_deferredSampleRate;
|
||||||
virtual void _resetSampleRate(double sampleRate)=0;
|
virtual void _resetSampleRate(double sampleRate) = 0;
|
||||||
|
|
||||||
/* Deferred pitch ratio set */
|
/* Deferred pitch ratio set */
|
||||||
bool m_setPitchRatio = false;
|
bool m_setPitchRatio = false;
|
||||||
|
@ -55,10 +53,11 @@ protected:
|
||||||
/* Mid-pump update */
|
/* Mid-pump update */
|
||||||
void _midUpdate();
|
void _midUpdate();
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
@ -72,61 +71,65 @@ public:
|
||||||
void setPitchRatio(double ratio, bool slew);
|
void setPitchRatio(double ratio, bool slew);
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
double getSampleRateIn() const {return m_sampleRateIn;}
|
double getSampleRateIn() const { return m_sampleRateIn; }
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -55,7 +44,7 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, T* dataOut)
|
||||||
if (m_ltRtProcessing)
|
if (m_ltRtProcessing)
|
||||||
std::fill(_getLtRtIn<T>().begin(), _getLtRtIn<T>().end(), 0.f);
|
std::fill(_getLtRtIn<T>().begin(), _getLtRtIn<T>().end(), 0.f);
|
||||||
|
|
||||||
for (auto it = m_linearizedSubmixes.rbegin() ; it != m_linearizedSubmixes.rend() ; ++it)
|
for (auto it = m_linearizedSubmixes.rbegin(); it != m_linearizedSubmixes.rend(); ++it)
|
||||||
(*it)->_zeroFill<T>();
|
(*it)->_zeroFill<T>();
|
||||||
|
|
||||||
if (m_voiceHead)
|
if (m_voiceHead)
|
||||||
|
@ -63,21 +52,20 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, T* dataOut)
|
||||||
if (vox.m_running)
|
if (vox.m_running)
|
||||||
vox.pumpAndMix<T>(thisFrames);
|
vox.pumpAndMix<T>(thisFrames);
|
||||||
|
|
||||||
for (auto it = m_linearizedSubmixes.rbegin() ; it != m_linearizedSubmixes.rend() ; ++it)
|
for (auto it = m_linearizedSubmixes.rbegin(); it != m_linearizedSubmixes.rend(); ++it)
|
||||||
(*it)->_pumpAndMix<T>(thisFrames);
|
(*it)->_pumpAndMix<T>(thisFrames);
|
||||||
|
|
||||||
remFrames -= thisFrames;
|
remFrames -= thisFrames;
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t sampleCount = thisFrames * m_mixInfo.m_channelMap.m_channelCount;
|
size_t sampleCount = thisFrames * m_mixInfo.m_channelMap.m_channelCount;
|
||||||
for (size_t i=0 ; i<sampleCount ; ++i)
|
for (size_t i = 0; i < sampleCount; ++i)
|
||||||
dataOut[i] *= m_totalVol;
|
dataOut[i] *= m_totalVol;
|
||||||
|
|
||||||
dataOut += sampleCount;
|
dataOut += sampleCount;
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
@ -73,22 +70,48 @@ public:
|
||||||
bool enableLtRt(bool enable);
|
bool enableLtRt(bool enable);
|
||||||
const AudioVoiceEngineMixInfo& mixInfo() const;
|
const AudioVoiceEngineMixInfo& mixInfo() const;
|
||||||
const AudioVoiceEngineMixInfo& clientMixInfo() const;
|
const AudioVoiceEngineMixInfo& clientMixInfo() const;
|
||||||
AudioChannelSet getAvailableSet() {return clientMixInfo().m_channels;}
|
AudioChannelSet getAvailableSet() { return clientMixInfo().m_channels; }
|
||||||
void pumpAndMixVoices() {}
|
void pumpAndMixVoices() {}
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,9 +43,8 @@ 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;
|
||||||
int status;
|
int status;
|
||||||
|
@ -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);
|
||||||
|
@ -303,8 +259,7 @@ struct LinuxMidi : BaseAudioVoiceEngine
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool useMIDILock() const {return true;}
|
bool useMIDILock() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace boo
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -100,12 +93,11 @@ WindowedHilbert::WindowedHilbert(int windowFrames, double sampleRate) :
|
||||||
m_buffer = (Ipp8u*)ippMalloc(sizeBuf);
|
m_buffer = (Ipp8u*)ippMalloc(sizeBuf);
|
||||||
ippsHilbertInit_32f32fc(m_windowFrames, ippAlgHintFast, m_spec, m_buffer);
|
ippsHilbertInit_32f32fc(m_windowFrames, ippAlgHintFast, m_spec, m_buffer);
|
||||||
|
|
||||||
for (int i=0 ; i<m_halfFrames ; ++i)
|
for (int i = 0; i < m_halfFrames; ++i)
|
||||||
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,69 +105,54 @@ 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);
|
||||||
_AddWindow();
|
_AddWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
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,25 +169,21 @@ 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]) +
|
output[i * 2] = ClampFull<T>(output[i * 2] + tmp * lCoef);
|
||||||
m_output[last][t].im * m_hammingTable[t];
|
output[i * 2 + 1] = ClampFull<T>(output[i * 2 + 1] + tmp * rCoef);
|
||||||
output[i*2] = ClampFull<T>(output[i*2] + tmp * lCoef);
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -282,20 +273,19 @@ void LtRtProcessing::Process(const T* input, T* output, int frameCount)
|
||||||
int tail = std::min(m_windowFrames * 2, m_bufferTail + frameCount);
|
int tail = std::min(m_windowFrames * 2, m_bufferTail + frameCount);
|
||||||
int samples = (tail - m_bufferTail) * 5;
|
int samples = (tail - m_bufferTail) * 5;
|
||||||
memmove(&inBuf[m_bufferTail * 5], input, samples * sizeof(T));
|
memmove(&inBuf[m_bufferTail * 5], input, samples * sizeof(T));
|
||||||
//printf("input %d to %d\n", tail - m_bufferTail, m_bufferTail);
|
// printf("input %d to %d\n", tail - m_bufferTail, m_bufferTail);
|
||||||
input += samples;
|
input += samples;
|
||||||
frameCount -= tail - m_bufferTail;
|
frameCount -= tail - m_bufferTail;
|
||||||
|
|
||||||
int head = std::min(m_windowFrames * 2, m_bufferHead + outFramesRem);
|
int head = std::min(m_windowFrames * 2, m_bufferHead + outFramesRem);
|
||||||
samples = (head - m_bufferHead) * 2;
|
samples = (head - m_bufferHead) * 2;
|
||||||
memmove(output, outBuf + m_bufferHead * 2, samples * sizeof(T));
|
memmove(output, outBuf + m_bufferHead * 2, samples * sizeof(T));
|
||||||
//printf("output %d from %d\n", head - m_bufferHead, m_bufferHead);
|
// printf("output %d from %d\n", head - m_bufferHead, m_bufferHead);
|
||||||
output += samples;
|
output += samples;
|
||||||
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,32 +295,26 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if INTEL_IPP
|
#if INTEL_IPP
|
||||||
|
@ -341,19 +325,17 @@ 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);
|
||||||
m_bufferHead = outFramesRem;
|
m_bufferHead = outFramesRem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -12,11 +12,12 @@
|
||||||
|
|
||||||
#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,
|
||||||
typedef void (CALLBACK *pfnvirtualMIDIClosePort)( LPVM_MIDI_PORT midiPort );
|
DWORD flags);
|
||||||
typedef BOOL (CALLBACK *pfnvirtualMIDISendData)( LPVM_MIDI_PORT midiPort, LPBYTE midiDataBytes, DWORD length );
|
typedef void(CALLBACK* pfnvirtualMIDIClosePort)(LPVM_MIDI_PORT midiPort);
|
||||||
typedef LPCWSTR (CALLBACK *pfnvirtualMIDIGetDriverVersion)( PWORD major, PWORD minor, PWORD release, PWORD build );
|
typedef BOOL(CALLBACK* pfnvirtualMIDISendData)(LPVM_MIDI_PORT midiPort, LPBYTE midiDataBytes, DWORD length);
|
||||||
|
typedef LPCWSTR(CALLBACK* pfnvirtualMIDIGetDriverVersion)(PWORD major, PWORD minor, PWORD release, PWORD build);
|
||||||
static pfnvirtualMIDICreatePortEx2 virtualMIDICreatePortEx2PROC = nullptr;
|
static pfnvirtualMIDICreatePortEx2 virtualMIDICreatePortEx2PROC = nullptr;
|
||||||
static pfnvirtualMIDIClosePort virtualMIDIClosePortPROC = nullptr;
|
static pfnvirtualMIDIClosePort virtualMIDIClosePortPROC = nullptr;
|
||||||
static pfnvirtualMIDISendData virtualMIDISendDataPROC = nullptr;
|
static pfnvirtualMIDISendData virtualMIDISendDataPROC = nullptr;
|
||||||
|
@ -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,99 +575,64 @@ 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,
|
uint8_t(&ptr)[3] = reinterpret_cast<uint8_t(&)[3]>(dwParam1);
|
||||||
DWORD_PTR dwParam2)
|
|
||||||
{
|
|
||||||
if (wMsg == MIM_DATA)
|
|
||||||
{
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#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,58 +861,33 @@ 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();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -10,24 +10,21 @@
|
||||||
#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;
|
||||||
|
|
||||||
template<class NodeCls, class DataCls = BaseGraphicsData>
|
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
|
@ -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
|
@ -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
|
@ -52,53 +52,26 @@ extern "C" {
|
||||||
#include "nvc0/nvc0_program.h"
|
#include "nvc0/nvc0_program.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
_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,9 +99,8 @@ 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
|
||||||
* variables that are candidates for removal.
|
* variables that are candidates for removal.
|
||||||
|
@ -148,12 +111,11 @@ 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) {
|
||||||
ir_variable *ir = (ir_variable *) entry->key;
|
ir_variable* ir = (ir_variable*)entry->key;
|
||||||
|
|
||||||
assert(ir->ir_type == ir_type_variable);
|
assert(ir->ir_type == ir_type_variable);
|
||||||
ir->remove();
|
ir->remove();
|
||||||
|
@ -161,16 +123,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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;
|
||||||
|
|
||||||
|
@ -247,13 +200,13 @@ bool nx_compiler::initialize(const struct standalone_options* o)
|
||||||
use_api = m_options.glsl_version > 130 ? API_OPENGL_CORE : API_OPENGL_COMPAT;
|
use_api = m_options.glsl_version > 130 ? API_OPENGL_CORE : API_OPENGL_COMPAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nouveau_screen *(*init)(struct nouveau_device *);
|
struct nouveau_screen* (*init)(struct nouveau_device*);
|
||||||
|
|
||||||
struct nouveau_drm *fakedrm = (struct nouveau_drm *)malloc(sizeof(struct nouveau_drm));
|
struct nouveau_drm* fakedrm = (struct nouveau_drm*)malloc(sizeof(struct nouveau_drm));
|
||||||
if (!fakedrm)
|
if (!fakedrm)
|
||||||
return false;
|
return false;
|
||||||
memset(fakedrm, 0, sizeof(*fakedrm));
|
memset(fakedrm, 0, sizeof(*fakedrm));
|
||||||
nouveau_device *ndev;
|
nouveau_device* ndev;
|
||||||
if (nouveau_device_new(&fakedrm->client, 0, nullptr, 0, &ndev))
|
if (nouveau_device_new(&fakedrm->client, 0, nullptr, 0, &ndev))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -284,21 +237,19 @@ bool nx_compiler::initialize(const struct standalone_options* o)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nouveau_screen *screen = init(ndev);
|
struct nouveau_screen* screen = init(ndev);
|
||||||
if (!screen)
|
if (!screen)
|
||||||
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,82 +257,68 @@ 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;
|
||||||
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);
|
||||||
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;
|
||||||
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);
|
||||||
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);
|
||||||
ret.m_shader = rzalloc(nullptr, gl_shader);
|
ret.m_shader = rzalloc(nullptr, gl_shader);
|
||||||
|
@ -399,15 +336,14 @@ 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;
|
||||||
|
|
||||||
struct gl_shader_program *whole_program;
|
struct gl_shader_program* whole_program;
|
||||||
|
|
||||||
whole_program = rzalloc (NULL, struct gl_shader_program);
|
whole_program = rzalloc(NULL, struct gl_shader_program);
|
||||||
assert(whole_program != NULL);
|
assert(whole_program != NULL);
|
||||||
whole_program->Type = GL_SHADER_PROGRAM_MESA;
|
whole_program->Type = GL_SHADER_PROGRAM_MESA;
|
||||||
whole_program->data = rzalloc(whole_program, struct gl_shader_program_data);
|
whole_program->data = rzalloc(whole_program, struct gl_shader_program_data);
|
||||||
|
@ -416,7 +352,7 @@ nx_linked_shader nx_compiler::link(unsigned num_stages, const nx_shader_stage_ob
|
||||||
whole_program->data->InfoLog = ralloc_strdup(whole_program->data, "");
|
whole_program->data->InfoLog = ralloc_strdup(whole_program->data, "");
|
||||||
ret.m_program = whole_program;
|
ret.m_program = whole_program;
|
||||||
|
|
||||||
whole_program->Shaders = (struct gl_shader **)calloc(num_stages, sizeof(struct gl_shader *));
|
whole_program->Shaders = (struct gl_shader**)calloc(num_stages, sizeof(struct gl_shader*));
|
||||||
assert(whole_program->Shaders != NULL);
|
assert(whole_program->Shaders != NULL);
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_stages; i++) {
|
for (unsigned i = 0; i < num_stages; i++) {
|
||||||
|
@ -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,23 +389,16 @@ 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,
|
} while (progress);
|
||||||
false,
|
|
||||||
compiler_options,
|
|
||||||
true)
|
|
||||||
&& progress;
|
|
||||||
} while(progress);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,7 +409,7 @@ nx_linked_shader nx_compiler::link(unsigned num_stages, const nx_shader_stage_ob
|
||||||
|
|
||||||
if (status == EXIT_SUCCESS) {
|
if (status == EXIT_SUCCESS) {
|
||||||
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
||||||
struct gl_linked_shader *shader = whole_program->_LinkedShaders[i];
|
struct gl_linked_shader* shader = whole_program->_LinkedShaders[i];
|
||||||
|
|
||||||
if (!shader)
|
if (!shader)
|
||||||
continue;
|
continue;
|
||||||
|
@ -500,7 +424,7 @@ nx_linked_shader nx_compiler::link(unsigned num_stages, const nx_shader_stage_ob
|
||||||
|
|
||||||
if (m_options.dump_builder) {
|
if (m_options.dump_builder) {
|
||||||
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
||||||
struct gl_linked_shader *shader = whole_program->_LinkedShaders[i];
|
struct gl_linked_shader* shader = whole_program->_LinkedShaders[i];
|
||||||
|
|
||||||
if (!shader)
|
if (!shader)
|
||||||
continue;
|
continue;
|
||||||
|
@ -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,48 +491,48 @@ 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)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
||||||
struct gl_linked_shader *shader = whole_program.m_program->_LinkedShaders[i];
|
struct gl_linked_shader* shader = whole_program.m_program->_LinkedShaders[i];
|
||||||
if (!shader)
|
if (!shader)
|
||||||
continue;
|
continue;
|
||||||
struct gl_program *prog = shader->Program;
|
struct gl_program* prog = shader->Program;
|
||||||
|
|
||||||
switch (prog->Target) {
|
switch (prog->Target) {
|
||||||
case GL_VERTEX_PROGRAM_ARB: {
|
case GL_VERTEX_PROGRAM_ARB: {
|
||||||
struct st_vertex_program *p = (struct st_vertex_program *)prog;
|
struct st_vertex_program* p = (struct st_vertex_program*)prog;
|
||||||
nvc0_program *dp = (nvc0_program *)p->variants->driver_shader;
|
nvc0_program* dp = (nvc0_program*)p->variants->driver_shader;
|
||||||
SizeProgramBuffer(dp, ret.second);
|
SizeProgramBuffer(dp, ret.second);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_TESS_CONTROL_PROGRAM_NV: {
|
case GL_TESS_CONTROL_PROGRAM_NV: {
|
||||||
struct st_common_program *p = st_common_program(prog);
|
struct st_common_program* p = st_common_program(prog);
|
||||||
nvc0_program *dp = (nvc0_program *)p->variants->driver_shader;
|
nvc0_program* dp = (nvc0_program*)p->variants->driver_shader;
|
||||||
SizeProgramBuffer(dp, ret.second);
|
SizeProgramBuffer(dp, ret.second);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_TESS_EVALUATION_PROGRAM_NV: {
|
case GL_TESS_EVALUATION_PROGRAM_NV: {
|
||||||
struct st_common_program *p = st_common_program(prog);
|
struct st_common_program* p = st_common_program(prog);
|
||||||
nvc0_program *dp = (nvc0_program *)p->variants->driver_shader;
|
nvc0_program* dp = (nvc0_program*)p->variants->driver_shader;
|
||||||
SizeProgramBuffer(dp, ret.second);
|
SizeProgramBuffer(dp, ret.second);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_GEOMETRY_PROGRAM_NV: {
|
case GL_GEOMETRY_PROGRAM_NV: {
|
||||||
struct st_common_program *p = st_common_program(prog);
|
struct st_common_program* p = st_common_program(prog);
|
||||||
nvc0_program *dp = (nvc0_program *)p->variants->driver_shader;
|
nvc0_program* dp = (nvc0_program*)p->variants->driver_shader;
|
||||||
SizeProgramBuffer(dp, ret.second);
|
SizeProgramBuffer(dp, ret.second);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_FRAGMENT_PROGRAM_ARB: {
|
case GL_FRAGMENT_PROGRAM_ARB: {
|
||||||
struct st_fragment_program *p = (struct st_fragment_program *)prog;
|
struct st_fragment_program* p = (struct st_fragment_program*)prog;
|
||||||
nvc0_program *dp = (nvc0_program *)p->variants->driver_shader;
|
nvc0_program* dp = (nvc0_program*)p->variants->driver_shader;
|
||||||
SizeProgramBuffer(dp, ret.second);
|
SizeProgramBuffer(dp, ret.second);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -623,42 +542,42 @@ nx_compiler::offline_link(unsigned num_stages, const nx_shader_stage_object **st
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.first.reset(new uint8_t[ret.second]);
|
ret.first.reset(new uint8_t[ret.second]);
|
||||||
uint8_t *pbuf = ret.first.get();
|
uint8_t* pbuf = ret.first.get();
|
||||||
|
|
||||||
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
||||||
struct gl_linked_shader *shader = whole_program.m_program->_LinkedShaders[i];
|
struct gl_linked_shader* shader = whole_program.m_program->_LinkedShaders[i];
|
||||||
if (!shader)
|
if (!shader)
|
||||||
continue;
|
continue;
|
||||||
struct gl_program *prog = shader->Program;
|
struct gl_program* prog = shader->Program;
|
||||||
|
|
||||||
switch (prog->Target) {
|
switch (prog->Target) {
|
||||||
case GL_VERTEX_PROGRAM_ARB: {
|
case GL_VERTEX_PROGRAM_ARB: {
|
||||||
struct st_vertex_program *p = (struct st_vertex_program *)prog;
|
struct st_vertex_program* p = (struct st_vertex_program*)prog;
|
||||||
nvc0_program *dp = (nvc0_program *)p->variants->driver_shader;
|
nvc0_program* dp = (nvc0_program*)p->variants->driver_shader;
|
||||||
BuildProgramBuffer(dp, pbuf);
|
BuildProgramBuffer(dp, pbuf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_TESS_CONTROL_PROGRAM_NV: {
|
case GL_TESS_CONTROL_PROGRAM_NV: {
|
||||||
struct st_common_program *p = st_common_program(prog);
|
struct st_common_program* p = st_common_program(prog);
|
||||||
nvc0_program *dp = (nvc0_program *)p->variants->driver_shader;
|
nvc0_program* dp = (nvc0_program*)p->variants->driver_shader;
|
||||||
BuildProgramBuffer(dp, pbuf);
|
BuildProgramBuffer(dp, pbuf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_TESS_EVALUATION_PROGRAM_NV: {
|
case GL_TESS_EVALUATION_PROGRAM_NV: {
|
||||||
struct st_common_program *p = st_common_program(prog);
|
struct st_common_program* p = st_common_program(prog);
|
||||||
nvc0_program *dp = (nvc0_program *)p->variants->driver_shader;
|
nvc0_program* dp = (nvc0_program*)p->variants->driver_shader;
|
||||||
BuildProgramBuffer(dp, pbuf);
|
BuildProgramBuffer(dp, pbuf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_GEOMETRY_PROGRAM_NV: {
|
case GL_GEOMETRY_PROGRAM_NV: {
|
||||||
struct st_common_program *p = st_common_program(prog);
|
struct st_common_program* p = st_common_program(prog);
|
||||||
nvc0_program *dp = (nvc0_program *)p->variants->driver_shader;
|
nvc0_program* dp = (nvc0_program*)p->variants->driver_shader;
|
||||||
BuildProgramBuffer(dp, pbuf);
|
BuildProgramBuffer(dp, pbuf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GL_FRAGMENT_PROGRAM_ARB: {
|
case GL_FRAGMENT_PROGRAM_ARB: {
|
||||||
struct st_fragment_program *p = (struct st_fragment_program *)prog;
|
struct st_fragment_program* p = (struct st_fragment_program*)prog;
|
||||||
nvc0_program *dp = (nvc0_program *)p->variants->driver_shader;
|
nvc0_program* dp = (nvc0_program*)p->variants->driver_shader;
|
||||||
BuildProgramBuffer(dp, pbuf);
|
BuildProgramBuffer(dp, pbuf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -7,54 +7,40 @@
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static inline uint16_t bswap16(uint16_t val) {return _byteswap_ushort(val);}
|
static inline uint16_t bswap16(uint16_t val) { return _byteswap_ushort(val); }
|
||||||
#elif __GNUC__ && !defined(__FreeBSD__)
|
#elif __GNUC__ && !defined(__FreeBSD__)
|
||||||
static inline uint16_t bswap16(uint16_t val) {return __builtin_bswap16(val); }
|
static inline uint16_t bswap16(uint16_t val) { return __builtin_bswap16(val); }
|
||||||
#elif !defined(__FreeBSD__)
|
#elif !defined(__FreeBSD__)
|
||||||
static inline uint16_t bswap16(uint16_t val) {return __builtin_byteswap(val);}
|
static inline uint16_t bswap16(uint16_t val) { return __builtin_byteswap(val); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef M_PIF
|
#ifndef M_PIF
|
||||||
#define M_PIF 3.14159265358979323846f /* pi */
|
#define M_PIF 3.14159265358979323846f /* pi */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -100,24 +79,20 @@ class HIDDeviceUdev final : public IHIDDevice
|
||||||
device->m_devFd = fd;
|
device->m_devFd = fd;
|
||||||
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
|
||||||
|
|
|
@ -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,66 +221,53 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -14,21 +12,15 @@ class HIDDeviceBSD final : public IHIDDevice
|
||||||
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; }
|
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; }
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
@ -53,15 +48,14 @@ static bool getUSBStringDescriptor(const IUnknownPointer<IOUSBDeviceInterface182
|
||||||
|
|
||||||
unsigned count = (request.wLenDone - 1) / 2;
|
unsigned count = (request.wLenDone - 1) / 2;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
for (i=0 ; i<count ; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
out[i] = buffer[i+1];
|
out[i] = buffer[i + 1];
|
||||||
out[i] = '\0';
|
out[i] = '\0';
|
||||||
|
|
||||||
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,45 +106,35 @@ 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;
|
||||||
listener->m_finder._removeToken(devPath);
|
listener->m_finder._removeToken(devPath);
|
||||||
//printf("REMOVED %08X %s\n", obj.get(), devPath);
|
// printf("REMOVED %08X %s\n", obj.get(), devPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,38 +189,30 @@ 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;
|
||||||
listener->m_finder._removeToken(devPath);
|
listener->m_finder._removeToken(devPath);
|
||||||
//printf("REMOVED %08X %s\n", obj, devPath);
|
// printf("REMOVED %08X %s\n", obj, devPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,9 +95,8 @@ 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
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -81,18 +69,14 @@ class HIDListenerWinUSB final : public IHIDListener
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Retreive the device description as reported by the device itself */
|
/* Retreive the device description as reported by the device itself */
|
||||||
pszToken = strtok_s(szDeviceInstanceID , "\\#&", &pszNextToken);
|
pszToken = strtok_s(szDeviceInstanceID, "\\#&", &pszNextToken);
|
||||||
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;
|
||||||
|
@ -113,42 +97,36 @@ class HIDListenerWinUSB final : public IHIDListener
|
||||||
if (!szVid[0] || !szPid[0])
|
if (!szVid[0] || !szPid[0])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
unsigned vid = strtol(szVid+4, NULL, 16);
|
unsigned vid = strtol(szVid + 4, NULL, 16);
|
||||||
unsigned pid = strtol(szPid+4, NULL, 16);
|
unsigned pid = strtol(szPid + 4, NULL, 16);
|
||||||
|
|
||||||
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, ®_type, (BYTE*)productW, 1024,
|
||||||
®_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);
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -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,17 +400,15 @@ 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)
|
||||||
report.emplace_back(flags, state, i);
|
report.emplace_back(flags, state, 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,40 +533,31 @@ 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)
|
||||||
return ParserStatus::Error;
|
return ParserStatus::Error;
|
||||||
/*uint8_t bLongItemTag =*/ GetByteValue(it, end, status);
|
/*uint8_t bLongItemTag =*/GetByteValue(it, end, status);
|
||||||
if (status == ParserStatus::Error)
|
if (status == ParserStatus::Error)
|
||||||
return ParserStatus::Error;
|
return ParserStatus::Error;
|
||||||
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,13 +739,12 @@ 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;
|
||||||
if (collectionStack.top().m_type == HIDCollectionType::Application)
|
if (collectionStack.top().m_type == HIDCollectionType::Application)
|
||||||
return { collectionStack.top().m_usagePage, collectionStack.top().m_usage };
|
return {collectionStack.top().m_usagePage, collectionStack.top().m_usage};
|
||||||
if (status != ParserStatus::OK)
|
if (status != ParserStatus::OK)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
|
@ -8,29 +8,27 @@
|
||||||
#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;
|
||||||
virtual bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length)=0;
|
virtual bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) = 0;
|
||||||
virtual size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length)=0;
|
virtual size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) = 0;
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#if !WINDOWS_STORE
|
#if !WINDOWS_STORE
|
||||||
virtual const PHIDP_PREPARSED_DATA _getReportDescriptor()=0;
|
virtual const PHIDP_PREPARSED_DATA _getReportDescriptor() = 0;
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
virtual std::vector<uint8_t> _getReportDescriptor()=0;
|
virtual std::vector<uint8_t> _getReportDescriptor() = 0;
|
||||||
#endif
|
#endif
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
/// A smart pointer that can manage the lifecycle of IOKit objects.
|
/// A smart pointer that can manage the lifecycle of IOKit objects.
|
||||||
template<typename T>
|
template <typename T>
|
||||||
class IOObjectPointer {
|
class IOObjectPointer {
|
||||||
public:
|
public:
|
||||||
IOObjectPointer() : storage(0) { }
|
IOObjectPointer() : storage(0) {}
|
||||||
|
|
||||||
IOObjectPointer(T pointer) : storage(toStorageType(pointer)) {
|
IOObjectPointer(T pointer) : storage(toStorageType(pointer)) {
|
||||||
if (storage) {
|
if (storage) {
|
||||||
|
@ -18,12 +18,12 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IOObjectPointer(const IOObjectPointer & other) : storage(other.storage) {
|
IOObjectPointer(const IOObjectPointer& other) : storage(other.storage) {
|
||||||
if (io_object_t ptr = storage) {
|
if (io_object_t ptr = storage) {
|
||||||
IOObjectRetain(ptr);
|
IOObjectRetain(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IOObjectPointer& operator=(const IOObjectPointer & other) {
|
IOObjectPointer& operator=(const IOObjectPointer& other) {
|
||||||
if (io_object_t pointer = storage) {
|
if (io_object_t pointer = storage) {
|
||||||
IOObjectRelease(pointer);
|
IOObjectRelease(pointer);
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
IOObjectPointer(IOObjectPointer && other) : storage(std::exchange(other.storage, 0)) { }
|
IOObjectPointer(IOObjectPointer&& other) : storage(std::exchange(other.storage, 0)) {}
|
||||||
|
|
||||||
~IOObjectPointer() {
|
~IOObjectPointer() {
|
||||||
if (io_object_t pointer = storage) {
|
if (io_object_t pointer = storage) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -62,29 +57,23 @@ private:
|
||||||
io_object_t storage;
|
io_object_t storage;
|
||||||
|
|
||||||
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.
|
||||||
class IOCFPluginPointer {
|
class IOCFPluginPointer {
|
||||||
public:
|
public:
|
||||||
IOCFPluginPointer() : _storage(nullptr) { }
|
IOCFPluginPointer() : _storage(nullptr) {}
|
||||||
|
|
||||||
IOCFPluginPointer(const IOCFPluginPointer & other) = delete;
|
IOCFPluginPointer(const IOCFPluginPointer& other) = delete;
|
||||||
|
|
||||||
IOCFPluginPointer(IOCFPluginPointer && other) : _storage(std::exchange(other._storage, nullptr)) { }
|
IOCFPluginPointer(IOCFPluginPointer&& other) : _storage(std::exchange(other._storage, nullptr)) {}
|
||||||
|
|
||||||
~IOCFPluginPointer() {
|
~IOCFPluginPointer() {
|
||||||
if (IOCFPlugInInterface** pointer = _storage) {
|
if (IOCFPlugInInterface** pointer = _storage) {
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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__
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,26 +49,18 @@ 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),
|
typedef HRESULT(WINAPI * CreateDXGIFactory1PROC)(REFIID riid, _COM_Outptr_ void** ppFactory);
|
||||||
m_friendlyName(friendlyName),
|
|
||||||
m_pname(pname),
|
|
||||||
m_args(args),
|
|
||||||
m_singleInstance(singleInstance)
|
|
||||||
{
|
|
||||||
typedef HRESULT(WINAPI*CreateDXGIFactory1PROC)(REFIID riid, _COM_Outptr_ void **ppFactory);
|
|
||||||
CreateDXGIFactory1PROC MyCreateDXGIFactory1 = CreateDXGIFactory1;
|
CreateDXGIFactory1PROC MyCreateDXGIFactory1 = CreateDXGIFactory1;
|
||||||
|
|
||||||
bool no12 = true;
|
bool no12 = true;
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -122,7 +98,7 @@ public:
|
||||||
if (!dxgilib)
|
if (!dxgilib)
|
||||||
Log.report(logvisor::Fatal, "unable to load dxgi.dll");
|
Log.report(logvisor::Fatal, "unable to load dxgi.dll");
|
||||||
|
|
||||||
typedef HRESULT(WINAPI*CreateDXGIFactory1PROC)(REFIID riid, _COM_Outptr_ void **ppFactory);
|
typedef HRESULT(WINAPI * CreateDXGIFactory1PROC)(REFIID riid, _COM_Outptr_ void** ppFactory);
|
||||||
CreateDXGIFactory1PROC MyCreateDXGIFactory1 = (CreateDXGIFactory1PROC)GetProcAddress(dxgilib, "CreateDXGIFactory1");
|
CreateDXGIFactory1PROC MyCreateDXGIFactory1 = (CreateDXGIFactory1PROC)GetProcAddress(dxgilib, "CreateDXGIFactory1");
|
||||||
if (!MyCreateDXGIFactory1)
|
if (!MyCreateDXGIFactory1)
|
||||||
Log.report(logvisor::Fatal, "unable to find CreateDXGIFactory1 in DXGI.dll\n");
|
Log.report(logvisor::Fatal, "unable to find CreateDXGIFactory1 in DXGI.dll\n");
|
||||||
|
@ -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,72 +312,58 @@ 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);
|
||||||
clientReturn = m_callback.appMain(this);
|
clientReturn = m_callback.appMain(this);
|
||||||
PostThreadMessageW(g_mainThreadId, WM_USER+1, 0, 0);
|
PostThreadMessageW(g_mainThreadId, WM_USER + 1, 0, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* 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);
|
||||||
|
@ -427,33 +371,34 @@ public:
|
||||||
g_nwcv.notify_one();
|
g_nwcv.notify_one();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case WM_USER+1:
|
case WM_USER + 1:
|
||||||
/* Quit message from client thread */
|
/* Quit message from client thread */
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
continue;
|
continue;
|
||||||
case WM_USER+2:
|
case WM_USER + 2:
|
||||||
/* SetCursor call from client thread */
|
/* SetCursor call from client thread */
|
||||||
SetCursor(HCURSOR(msg.wParam));
|
SetCursor(HCURSOR(msg.wParam));
|
||||||
continue;
|
continue;
|
||||||
case WM_USER+3:
|
case WM_USER + 3:
|
||||||
/* ImmSetOpenStatus call from client thread */
|
/* ImmSetOpenStatus call from client thread */
|
||||||
ImmSetOpenStatus(HIMC(msg.wParam), BOOL(msg.lParam));
|
ImmSetOpenStatus(HIMC(msg.wParam), BOOL(msg.lParam));
|
||||||
continue;
|
continue;
|
||||||
case WM_USER+4:
|
case WM_USER + 4:
|
||||||
/* ImmSetCompositionWindow call from client thread */
|
/* ImmSetCompositionWindow call from client thread */
|
||||||
ImmSetCompositionWindow(HIMC(msg.wParam), LPCOMPOSITIONFORM(msg.lParam));
|
ImmSetCompositionWindow(HIMC(msg.wParam), LPCOMPOSITIONFORM(msg.lParam));
|
||||||
continue;
|
continue;
|
||||||
case WM_USER+5:
|
case WM_USER + 5:
|
||||||
/* SetFullscreen call for OpenGL window */
|
/* SetFullscreen call for OpenGL window */
|
||||||
DoSetFullscreen(*reinterpret_cast<OGLContext::Window*>(msg.wParam), msg.lParam);
|
DoSetFullscreen(*reinterpret_cast<OGLContext::Window*>(msg.wParam), msg.lParam);
|
||||||
continue;
|
continue;
|
||||||
#if BOO_HAS_VULKAN
|
#if BOO_HAS_VULKAN
|
||||||
case WM_USER+6:
|
case WM_USER + 6:
|
||||||
/* SetFullscreen call for Vulkan window */
|
/* SetFullscreen call for Vulkan window */
|
||||||
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
Loading…
Reference in New Issue