Initial community commit

This commit is contained in:
Jef 2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit fc06254474
16440 changed files with 4239995 additions and 2 deletions

View file

@ -0,0 +1 @@
ASIO::Modern v0.12.5

View file

@ -0,0 +1,153 @@
# clang-format 13
Language: Cpp
Standard: c++20
AccessModifierOffset: -4 #?
AlignAfterOpenBracket: AlwaysBreak
AlignArrayOfStructures: Left
AlignConsecutiveAssignments: true
AlignConsecutiveBitFields: true
AlignConsecutiveDeclarations: true
AlignConsecutiveMacros: true
AlignEscapedNewlines: DontAlign
AlignOperands: AlignAfterOperator
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLambdasOnASingleLine: Inline
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros: []
BinPackArguments: true
BinPackParameters: false
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: MultiLine
AfterEnum: false
AfterFunction: false
AfterNamespace: false
#AfterObjCDeclaration
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: false
SplitEmptyNamespace: true
#BreakAfterJavaFieldAnnotations
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakBeforeConceptDeclarations: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeComma
BreakStringLiterals: false
ColumnLimit: 0
CommentPragmas: '' #?
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4 #?
ContinuationIndentWidth: 4 #?
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
EmptyLineAfterAccessModifier: Leave
EmptyLineBeforeAccessModifier: Leave
FixNamespaceComments: true
ForEachMacros: []
IfMacros: ['']
IncludeBlocks: Preserve
IncludeCategories: [] #?
IncludeIsMainRegex: '' #?
IncludeIsMainSourceRegex: '' #?
IndentAccessModifiers: false
IndentCaseLabels: true
IndentCaseBlocks: true
IndentExternBlock: NoIndent
IndentGotoLabels: false
IndentPPDirectives: None
#IndentRequiresClause: true
InsertTrailingCommas: None
#BeforeHash
IndentWidth: 4
IndentWrappedFunctionNames: true
#JavaImportGroups
#JavaScriptQuotes
#JavaScriptWrapImports
KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: OuterScope
MacroBlockBegin: '' #?
MacroBlockEnd: '' #?
MaxEmptyLinesToKeep: 5
NamespaceIndentation: None
NamespaceMacros: [] #?
#ObjCBinPackProtocolList
#ObjCBlockIndentWidth
#ObjCBreakBeforeNestedBlockParam
#ObjCSpaceAfterProperty
#ObjCSpaceBeforeProtocolList
#PenaltyBreakAssignment
#PenaltyBreakBeforeFirstCallParameter
#PenaltyBreakComment
#PenaltyBreakFirstLessLess
#PenaltyBreakString
#PenaltyBreakTemplateDeclaration
#PenaltyExcessCharacter
#PenaltyIndentedWhitespace
#PenaltyReturnTypeOnItsOwnLine
PointerAlignment: Middle
PPIndentWidth: -1
#RawStringFormats
ReferenceAlignment: Pointer
ReflowComments: false
ShortNamespaceLines: 1
SortIncludes: false
#SortJavaStaticImport
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: true
SpaceInEmptyParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInParentheses: false
SpacesInSquareBrackets: false
StatementAttributeLikeMacros: []
StatementMacros: [ '_Pragma', '__pragma' ] #?
TabWidth: 4
TypenameMacros: [] #?
UseCRLF: false
UseTab: ForContinuationAndIndentation
WhitespaceSensitiveMacros:
- ASIO_PP_STRINGIFY

View file

@ -0,0 +1,16 @@
#ifndef ASIO_ASIO_HPP
#define ASIO_ASIO_HPP
#include "ASIOVersion.hpp"
#include "ASIOConfig.hpp"
#include "ASIOCore.hpp"
#include "ASIOModern.hpp"
//#include "ASIOSystemWindows.hpp"
//#include "ASIOSampleConvert.hpp"
#endif // ASIO_ASIO_HPP

View file

@ -0,0 +1,385 @@
#ifndef ASIO_ASIOCONFIG_HPP
#define ASIO_ASIOCONFIG_HPP
#include "ASIOVersion.hpp"
#include <algorithm>
#include <string>
#include <string_view>
#include <cstddef>
#include <cstdint>
#include <cstring>
#if defined(_WIN32)
#define ASIO_SYSTEM_WINDOWS 1
#endif
#ifndef ASIO_SYSTEM_WINDOWS
#define ASIO_SYSTEM_WINDOWS 0
#endif
#if defined(__clang__)
#define ASIO_COMPILER_CLANG 1
#elif defined(_MSC_VER)
#define ASIO_COMPILER_MSVC 1
#elif defined(__GNUC__)
#define ASIO_COMPILER_GCC 1
#endif
#ifndef ASIO_COMPILER_CLANG
#define ASIO_COMPILER_CLANG 0
#endif
#ifndef ASIO_COMPILER_MSVC
#define ASIO_COMPILER_MSVC 0
#endif
#ifndef ASIO_COMPILER_GCC
#define ASIO_COMPILER_GCC 0
#endif
#if ASIO_COMPILER_MSVC || ASIO_COMPILER_CLANG || ASIO_COMPILER_GCC || ASIO_SYSTEM_WINDOWS
// assume #pragma pack support on Windows
#define ASIO_HAVE_PRAGMA_PACK 1
#else
#define ASIO_HAVE_PRAGMA_PACK 0
#endif
#if ASIO_COMPILER_MSVC || ASIO_COMPILER_CLANG || ASIO_SYSTEM_WINDOWS
// assume #pragma comment lib support on Windows
#define ASIO_HAVE_PRAGMA_COMMENT_LIB 1
#else
#define ASIO_HAVE_PRAGMA_COMMENT_LIB 0
#endif
#if ASIO_SYSTEM_WINDOWS
#include <objbase.h>
#endif // ASIO_SYSTEM_WINDOWS
namespace ASIO {
#define ASIO_PP_DEFER(m, ...) m(__VA_ARGS__)
#define ASIO_PP_STRINGIFY(x) #x
#define ASIO_PP_JOIN_HELPER(a, b) a##b
#define ASIO_PP_JOIN(a, b) ASIO_PP_JOIN_HELPER(a, b)
#define ASIO_PP_UNIQUE_IDENTIFIER(prefix) ASIO_PP_JOIN(prefix, __LINE__)
#if ASIO_COMPILER_MSVC
#define ASIO_WARNING(text) __pragma(message(__FILE__ "(" ASIO_PP_DEFER(ASIO_PP_STRINGIFY, __LINE__) "): Warning: " text))
#elif ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG
#define ASIO_WARNING(text) _Pragma(MPT_PP_STRINGIFY(GCC warning text))
#else
#define ASIO_WARNING(text) \
static inline int ASIO_PP_UNIQUE_IDENTIFIER(ASIO_WARNING_NAME)() noexcept { \
int warning [[deprecated("Warning: " text)]] = 0; \
return warning; \
} \
/**/
#endif
#if ASIO_SYSTEM_WINDOWS
#if !ASIO_HAVE_PRAGMA_PACK
#error "ASIO on Windows requires #pragma pack support"
#endif // !ASIO_HAVE_PRAGMA_PACK
#define ASIO_INTERFACE interface
#if ASIO_COMPILER_MSVC
#define ASIO_ATTR_DRIVERCALL
#define ASIO_DRIVERCALL __thiscall
#elif ASIO_COMPILER_CLANG
#define ASIO_ATTR_DRIVERCALL
#define ASIO_DRIVERCALL __thiscall
#elif ASIO_COMPILER_GCC
#pragma push_macro("thiscall")
#ifdef thiscall
#undef thiscall
#endif
#define ASIO_ATTR_DRIVERCALL [[gnu::thiscall]]
#define ASIO_DRIVERCALL
#pragma pop_macro("thiscall")
#else
#define ASIO_ATTR_DRIVERCALL
#define ASIO_DRIVERCALL __thiscall
#endif
#if ASIO_COMPILER_MSVC
#define ASIO_ATTR_CALL
#define ASIO_CALL __cdecl
#elif ASIO_COMPILER_CLANG
#define ASIO_ATTR_CALL
#define ASIO_CALL __cdecl
#elif ASIO_COMPILER_GCC
#pragma push_macro("cdecl")
#ifdef cdecl
#undef cdecl
#endif
#define ASIO_ATTR_CALL [[gnu::cdecl]]
#define ASIO_CALL
#pragma pop_macro("cdecl")
#else
#define ASIO_ATTR_CALL
#define ASIO_CALL __cdecl
#endif
#else // !ASIO_SYSTEM_WINDOWS
#error "Only Windows is supported by this ASIO header"
#define ASIO_INTERFACE struct
#define ASIO_ATTR_DRIVERCALL
#define ASIO_DRIVERCALL
#define ASIO_ATTR_CALL
#define ASIO_CALL
#endif // ASIO_SYSTEM_WINDOWS
inline namespace Core {
inline namespace ASIO_VERSION_NAMESPACE {
#if ASIO_SYSTEM_WINDOWS
using SysHandle = void *;
using Byte = std::uint8_t;
using Long = std::int32_t;
using ULong = std::uint32_t;
using LongLong = std::int64_t;
using ULongLong = std::uint64_t;
using Double = double;
using Char = char;
using Padding1 = std::uint8_t;
using PaddingLong = ULong;
#else // !ASIO_SYSTEM_WINDOWS
#error "Only Windows is supported by this ASIO header"
#define ASIO_INTERFACE struct
#define ASIO_ATTR_DRIVERCALL
#define ASIO_DRIVERCALL
#define ASIO_ATTR_CALL
#define ASIO_CALL
using SysHandle = void *;
using Byte = unsigned char;
using Long = signed long;
using ULong = unsigned long;
using LongLong = signed long long;
using ULongLong = unsigned long long;
using Double = double;
using Char = char;
using Padding1 = std::uint8_t;
using PaddingLong = ULong;
#endif // ASIO_SYSTEM_WINDOWS
struct Bool {
private:
ULong m_val;
public:
constexpr Bool() noexcept
: m_val(0) { }
constexpr Bool(bool val) noexcept
: m_val(val ? 1 : 0) { }
constexpr explicit Bool(ULong val) noexcept
: m_val(val ? 1 : 0) { }
constexpr bool operator!() const noexcept {
return m_val ? false : true;
}
constexpr operator bool() const noexcept {
return m_val ? true : false;
}
};
struct HiLoLongLong {
private:
ULong m_hi;
ULong m_lo;
public:
constexpr HiLoLongLong() noexcept
: m_hi(0)
, m_lo(0) {
}
constexpr HiLoLongLong(LongLong val) noexcept
: m_hi(static_cast<ULong>((static_cast<ULongLong>(val) & 0xffffffff00000000ull) >> 32))
, m_lo(static_cast<ULong>((static_cast<ULongLong>(val) & 0x00000000ffffffffull) >> 0)) {
}
constexpr operator LongLong() const noexcept {
return static_cast<LongLong>((static_cast<ULongLong>(m_hi) << 32) | (static_cast<ULongLong>(m_lo) << 0));
}
};
using ResultBool = ULong;
template <std::size_t size>
struct CharBuf {
private:
Char buf[size] = "";
public:
CharBuf() = default;
CharBuf(const CharBuf &) = default;
CharBuf(CharBuf &&) = default;
CharBuf & operator=(const CharBuf &) = default;
CharBuf & operator=(CharBuf &&) = default;
public:
constexpr CharBuf(std::nullptr_t) noexcept
: CharBuf() {
}
inline CharBuf(const char * str) noexcept
: CharBuf() {
if (str) {
std::copy(str, str + std::min(std::strlen(str), size - 1), buf);
std::fill(buf + std::min(std::strlen(str), size - 1), buf + size, Char('\0'));
}
}
inline CharBuf(const std::string_view & str) noexcept
: CharBuf() {
std::copy(str.data(), str.data() + std::min(str.length(), size - 1), buf);
std::fill(buf + std::min(str.length(), size - 1), buf + size, Char('\0'));
}
inline CharBuf(const std::string & str) noexcept
: CharBuf() {
std::copy(str.data(), str.data() + std::min(str.length(), size - 1), buf);
std::fill(buf + std::min(str.length(), size - 1), buf + size, Char('\0'));
}
inline CharBuf & operator=(std::nullptr_t) noexcept {
std::fill(buf, buf + size, Char('\0'));
return *this;
}
inline CharBuf & operator=(const char * str) noexcept {
if (str) {
std::copy(str, str + std::min(std::strlen(str), size - 1), buf);
std::fill(buf + std::min(std::strlen(str), size - 1), buf + size, Char('\0'));
} else {
std::fill(buf, buf + size, Char('\0'));
}
return *this;
}
inline CharBuf & operator=(const std::string & str) noexcept {
std::fill(buf, buf + size, Char('\0'));
std::copy(str.data(), str.data() + std::min(str.length(), size - 1), buf);
std::fill(buf + std::min(str.length(), size - 1), buf + size, Char('\0'));
return *this;
}
inline CharBuf & operator=(const std::string_view & str) noexcept {
std::fill(buf, buf + size, Char('\0'));
std::copy(str.data(), str.data() + std::min(str.length(), size - 1), buf);
std::fill(buf + std::min(str.length(), size - 1), buf + size, Char('\0'));
return *this;
}
inline explicit operator std::string_view() const noexcept {
std::size_t len = std::find(buf, buf + size - 1, Char('\0')) - buf;
return std::string_view(buf, buf + len);
}
inline operator std::string() const {
std::size_t len = std::find(buf, buf + size - 1, Char('\0')) - buf;
return std::string(buf, buf + len);
}
};
inline constexpr std::size_t SizeOfChar = sizeof(Char);
inline constexpr std::size_t SizeOfByte = sizeof(Byte);
inline constexpr std::size_t SizeOfBool = sizeof(Bool);
inline constexpr std::size_t SizeOfLong = sizeof(Long);
inline constexpr std::size_t SizeOfLongLong = sizeof(LongLong);
inline constexpr std::size_t SizeOfDouble = sizeof(Double);
inline constexpr std::size_t SizeOfHiLoLongLong = sizeof(HiLoLongLong);
static_assert(SizeOfChar == 1);
static_assert(SizeOfByte == 1);
static_assert(SizeOfBool == SizeOfLong);
static_assert(SizeOfHiLoLongLong == SizeOfLongLong);
static_assert(SizeOfLongLong == 8);
static_assert(sizeof(Padding1) == 1);
static_assert(sizeof(PaddingLong) == SizeOfLong);
static_assert(sizeof(CharBuf<1>) == 1);
} // namespace ASIO_VERSION_NAMESPACE
} // namespace Core
} // namespace ASIO
#endif // ASIO_ASIOCONFIG_HPP

View file

@ -0,0 +1,469 @@
#ifndef ASIO_ASIOCORE_HPP
#define ASIO_ASIOCORE_HPP
#include "ASIOVersion.hpp"
#include "ASIOConfig.hpp"
#include <algorithm>
#include <string>
#include <type_traits>
#include <cstddef>
#include <cstdint>
namespace ASIO {
inline namespace Core {
inline namespace ASIO_VERSION_NAMESPACE {
using Samples = HiLoLongLong;
using TimeStamp = HiLoLongLong;
using SampleRate = Double;
enum class SampleType : Long {
Int16MSB = 0,
Int24MSB = 1,
Int32MSB = 2,
Float32MSB = 3,
Float64MSB = 4,
Int32MSB16 = 8,
Int32MSB18 = 9,
Int32MSB20 = 10,
Int32MSB24 = 11,
Int16LSB = 16,
Int24LSB = 17,
Int32LSB = 18,
Float32LSB = 19,
Float64LSB = 20,
Int32LSB16 = 24,
Int32LSB18 = 25,
Int32LSB20 = 26,
Int32LSB24 = 27,
DSDInt8LSB1 = 32,
DSDInt8MSB1 = 33,
DSDInt8NER8 = 40,
};
static_assert(sizeof(SampleType) == SizeOfLong);
enum class ErrorCode : Long {
OK = 0,
SUCCESS = 0x3f4847a0,
NotPresent = -1000,
HWMalfunction = -999,
InvalidParameter = -998,
InvalidMode = -997,
SPNotAdvancing = -996,
NoClock = -995,
NoMemory = -994,
};
static_assert(sizeof(ErrorCode) == SizeOfLong);
enum TimeCodeFlags : ULong {
TimeCodeFlagValid = 1 << 0,
TimeCodeFlagRunning = 1 << 1,
TimeCodeFlagReverse = 1 << 2,
TimeCodeFlagOnspeed = 1 << 3,
TimeCodeFlagStill = 1 << 4,
TimeCodeFlagSpeedValid = 1 << 8,
};
constexpr inline TimeCodeFlags operator|(TimeCodeFlags a, TimeCodeFlags b) noexcept {
return static_cast<TimeCodeFlags>(static_cast<std::underlying_type<TimeCodeFlags>::type>(a) | static_cast<std::underlying_type<TimeCodeFlags>::type>(b));
}
constexpr inline TimeCodeFlags operator&(TimeCodeFlags a, TimeCodeFlags b) noexcept {
return static_cast<TimeCodeFlags>(static_cast<std::underlying_type<TimeCodeFlags>::type>(a) & static_cast<std::underlying_type<TimeCodeFlags>::type>(b));
}
constexpr inline TimeCodeFlags operator^(TimeCodeFlags a, TimeCodeFlags b) noexcept {
return static_cast<TimeCodeFlags>(static_cast<std::underlying_type<TimeCodeFlags>::type>(a) ^ static_cast<std::underlying_type<TimeCodeFlags>::type>(b));
}
constexpr inline TimeCodeFlags operator~(TimeCodeFlags a) noexcept {
return static_cast<TimeCodeFlags>(~static_cast<std::underlying_type<TimeCodeFlags>::type>(a));
}
constexpr inline TimeCodeFlags & operator|=(TimeCodeFlags & a, TimeCodeFlags b) noexcept {
return a = a | b;
}
constexpr inline TimeCodeFlags & operator&=(TimeCodeFlags & a, TimeCodeFlags b) noexcept {
return a = a & b;
}
constexpr inline TimeCodeFlags & operator^=(TimeCodeFlags & a, TimeCodeFlags b) noexcept {
return a = a ^ b;
}
static_assert(sizeof(TimeCodeFlags) == SizeOfLong);
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(push, 4)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
struct TimeCode {
Double speed = 0.0;
HiLoLongLong timeCodeSamples = 0;
TimeCodeFlags flags = static_cast<TimeCodeFlags>(0);
Padding1 future[64] = {0};
};
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(pop)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
static_assert(sizeof(TimeCode) == (SizeOfDouble + SizeOfLongLong + SizeOfLong + 64));
enum TimeInfoFlags : ULong {
TimeInfoFlagSystemTimeValid = 1 << 0,
TimeInfoFlagSamplePositionValid = 1 << 1,
TimeInfoFlagSampleRateValid = 1 << 2,
TimeInfoFlagSpeedValid = 1 << 3,
TimeInfoFlagSampleRateChanged = 1 << 4,
TimeInfoFlagClockSourceChanged = 1 << 5,
};
constexpr inline TimeInfoFlags operator|(TimeInfoFlags a, TimeInfoFlags b) noexcept {
return static_cast<TimeInfoFlags>(static_cast<std::underlying_type<TimeInfoFlags>::type>(a) | static_cast<std::underlying_type<TimeInfoFlags>::type>(b));
}
constexpr inline TimeInfoFlags operator&(TimeInfoFlags a, TimeInfoFlags b) noexcept {
return static_cast<TimeInfoFlags>(static_cast<std::underlying_type<TimeInfoFlags>::type>(a) & static_cast<std::underlying_type<TimeInfoFlags>::type>(b));
}
constexpr inline TimeInfoFlags operator^(TimeInfoFlags a, TimeInfoFlags b) noexcept {
return static_cast<TimeInfoFlags>(static_cast<std::underlying_type<TimeInfoFlags>::type>(a) ^ static_cast<std::underlying_type<TimeInfoFlags>::type>(b));
}
constexpr inline TimeInfoFlags operator~(TimeInfoFlags a) noexcept {
return static_cast<TimeInfoFlags>(~static_cast<std::underlying_type<TimeInfoFlags>::type>(a));
}
constexpr inline TimeInfoFlags & operator|=(TimeInfoFlags & a, TimeInfoFlags b) noexcept {
return a = a | b;
}
constexpr inline TimeInfoFlags & operator&=(TimeInfoFlags & a, TimeInfoFlags b) noexcept {
return a = a & b;
}
constexpr inline TimeInfoFlags & operator^=(TimeInfoFlags & a, TimeInfoFlags b) noexcept {
return a = a ^ b;
}
static_assert(sizeof(TimeInfoFlags) == SizeOfLong);
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(push, 4)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
struct TimeInfo {
Double speed = 0.0;
HiLoLongLong systemTime = 0;
HiLoLongLong samplePosition = 0;
SampleRate sampleRate = 0.0;
TimeInfoFlags flags = static_cast<TimeInfoFlags>(0);
Padding1 reserved[12] = {0};
};
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(pop)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
static_assert(sizeof(TimeInfo) == (SizeOfDouble + SizeOfLongLong + SizeOfLongLong + SizeOfDouble + SizeOfLong + 12));
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(push, 4)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
struct Time {
PaddingLong reserved[4] = {0};
TimeInfo timeInfo;
TimeCode timeCode;
};
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(pop)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
static_assert(sizeof(Time) == (4 * SizeOfLong + sizeof(TimeInfo) + sizeof(TimeCode)));
enum class MessageSelector : Long {
SelectorSupported = 1,
EngineVersion = 2,
ResetRequest = 3,
BufferSizeChange = 4,
ResyncRequest = 5,
LatenciesChanged = 6,
SupportsTimeInfo = 7,
SupportsTimeCode = 8,
MMCCommand = 9,
SupportsInputMonitor = 10,
SupportsInputGain = 11,
SupportsInputMeter = 12,
SupportsOutputGain = 13,
SupportsOutputMeter = 14,
Overload = 15,
};
static_assert(sizeof(MessageSelector) == SizeOfLong);
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(push, 4)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#if ASIO_SYSTEM_WINDOWS && (ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG)
#pragma push_macro("cdecl")
#ifdef cdecl
#undef cdecl
#endif
#endif // ASIO_SYSTEM_WINDOWS && (ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG)
struct Callbacks {
void(ASIO_CALL * bufferSwitch ASIO_ATTR_CALL)(Long doubleBufferIndex, Bool directProcess) noexcept = nullptr;
void(ASIO_CALL * sampleRateDidChange ASIO_ATTR_CALL)(SampleRate sRate) noexcept = nullptr;
Long(ASIO_CALL * asioMessage ASIO_ATTR_CALL)(MessageSelector selector, Long value, void const * message, Double const * opt) noexcept = nullptr;
Time const *(ASIO_CALL * bufferSwitchTimeInfo ASIO_ATTR_CALL)(Time const * params, Long doubleBufferIndex, Bool directProcess) noexcept = nullptr;
};
#if ASIO_SYSTEM_WINDOWS && (ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG)
#pragma pop_macro("cdecl")
#endif // ASIO_SYSTEM_WINDOWS && (ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG)
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(pop)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
static_assert(sizeof(Callbacks) == (4 * sizeof(void (*)(void))));
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(push, 4)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
struct ClockSource {
Long index = 0;
Long associatedChannel = 0;
Long associatedGroup = 0;
Bool isCurrentSource = false;
CharBuf<32> name = nullptr;
};
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(pop)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
static_assert(sizeof(ClockSource) == (SizeOfLong + SizeOfLong + SizeOfLong + SizeOfBool + 32));
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(push, 4)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
struct ChannelInfo {
Long channel = 0;
Bool isInput = false;
Bool isActive = false;
Long channelGroup = 0;
SampleType type = static_cast<SampleType>(0);
CharBuf<32> name = nullptr;
};
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(pop)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
static_assert(sizeof(ChannelInfo) == (SizeOfLong + SizeOfBool + SizeOfBool + SizeOfLong + sizeof(SampleType) + 32));
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(push, 4)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
struct BufferInfo {
Bool isInput = false;
Long channelNum = 0;
void * buffers[2] = {nullptr, nullptr};
};
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(pop)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
static_assert(sizeof(BufferInfo) == (SizeOfBool + SizeOfLong + 2 * sizeof(void *)));
enum class FutureSelector : Long {
EnableTimeCodeRead = 1,
DisableTimeCodeRead = 2,
SetInputMonitor = 3,
Transport = 4,
SetInputGain = 5,
GetInputMeter = 6,
SetOutputGain = 7,
GetOutputMeter = 8,
CanInputMonitor = 9,
CanTimeInfo = 10,
CanTimeCode = 11,
CanTransport = 12,
CanInputGain = 13,
CanInputMeter = 14,
CanOutputGain = 15,
CanOutputMeter = 16,
OptionalOne = 17,
SetIoFormat = 0x23111961,
GetIoFormat = 0x23111983,
CanDoIoFormat = 0x23112004,
CanReportOverload = 0x24042012,
GetInternalBufferSamples = 0x25042012,
};
static_assert(sizeof(FutureSelector) == SizeOfLong);
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(push, 4)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
struct InputMonitor {
Long input = 0;
Long output = 0;
Long gain = 0;
Bool state = false;
Long pan = 0;
};
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(pop)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
static_assert(sizeof(InputMonitor) == (SizeOfLong + SizeOfLong + SizeOfLong + SizeOfBool + SizeOfLong));
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(push, 4)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
struct ChannelControls {
Long channel = 0;
Bool isInput = false;
Long gain = 0;
Long meter = 0;
Padding1 future[32] = {0};
};
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(pop)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
static_assert(sizeof(ChannelControls) == (SizeOfLong + SizeOfBool + SizeOfLong + SizeOfLong + 32));
enum class TransportCommand : Long {
Start = 1,
Stop = 2,
Locate = 3,
PunchIn = 4,
PunchOut = 5,
ArmOn = 6,
ArmOff = 7,
MonitorOn = 8,
MonitorOff = 9,
Arm = 10,
Monitor = 11,
};
static_assert(sizeof(TransportCommand) == SizeOfLong);
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(push, 4)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
struct TransportParameters {
TransportCommand command = static_cast<TransportCommand>(0);
HiLoLongLong samplePosition = 0;
Long track = 0;
Byte trackSwitches[64] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Padding1 future[64] = {0};
};
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(pop)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
static_assert(sizeof(TransportParameters) == (sizeof(TransportCommand) + SizeOfLongLong + SizeOfLong + 64 + 64));
enum class IoFormatType : Long {
Invalid = -1,
PCM = 0,
DSD = 1,
};
static_assert(sizeof(IoFormatType) == SizeOfLong);
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(push, 4)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
struct IoFormat {
IoFormatType FormatType = static_cast<IoFormatType>(0);
Padding1 future[512 - sizeof(IoFormatType)] = {0};
};
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(pop)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
static_assert(sizeof(IoFormat) == 512);
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(push, 4)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
struct InternalBufferInfo {
Long inputSamples = 0;
Long outputSamples = 0;
};
#if ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
#pragma pack(pop)
#endif // ASIO_SYSTEM_WINDOWS && ASIO_HAVE_PRAGMA_PACK
static_assert(sizeof(InternalBufferInfo) == (SizeOfLong + SizeOfLong));
typedef ASIO_INTERFACE ISystemDriver ISystemDriver;
using DriverName = CharBuf<32>;
using ErrorMessage = CharBuf<124>;
#if ASIO_SYSTEM_WINDOWS && (ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG)
#pragma push_macro("thiscall")
#ifdef thiscall
#undef thiscall
#endif
#endif // ASIO_SYSTEM_WINDOWS && (ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG)
ASIO_INTERFACE ISystemDriver : public IUnknown {
[[nodiscard]] virtual ResultBool ASIO_DRIVERCALL init ASIO_ATTR_DRIVERCALL(SysHandle sysHandle) = 0;
virtual void ASIO_DRIVERCALL getDriverName ASIO_ATTR_DRIVERCALL(DriverName * name) = 0;
[[nodiscard]] virtual Long ASIO_DRIVERCALL getDriverVersion ASIO_ATTR_DRIVERCALL() = 0;
virtual void ASIO_DRIVERCALL getErrorMessage ASIO_ATTR_DRIVERCALL(ErrorMessage * string) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL start ASIO_ATTR_DRIVERCALL() = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL stop ASIO_ATTR_DRIVERCALL() = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL getChannels ASIO_ATTR_DRIVERCALL(Long * numInputChannels, Long * numOutputChannels) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL getLatencies ASIO_ATTR_DRIVERCALL(Long * inputLatency, Long * outputLatency) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL getBufferSize ASIO_ATTR_DRIVERCALL(Long * minSize, Long * maxSize, Long * preferredSize, Long * granularity) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL canSampleRate ASIO_ATTR_DRIVERCALL(SampleRate sampleRate) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL getSampleRate ASIO_ATTR_DRIVERCALL(SampleRate * sampleRate) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL setSampleRate ASIO_ATTR_DRIVERCALL(SampleRate sampleRate) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL getClockSources ASIO_ATTR_DRIVERCALL(ClockSource * clocks, Long * numSources) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL setClockSource ASIO_ATTR_DRIVERCALL(Long reference) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL getSamplePosition ASIO_ATTR_DRIVERCALL(HiLoLongLong * samplePosition, HiLoLongLong * timeStamp) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL getChannelInfo ASIO_ATTR_DRIVERCALL(ChannelInfo * info) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL createBuffers ASIO_ATTR_DRIVERCALL(BufferInfo * bufferInfos, Long numChannels, Long bufferSize, Callbacks const * callbacks) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL disposeBuffers ASIO_ATTR_DRIVERCALL() = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL controlPanel ASIO_ATTR_DRIVERCALL() = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL future ASIO_ATTR_DRIVERCALL(FutureSelector selector, void * opt) = 0;
[[nodiscard]] virtual ErrorCode ASIO_DRIVERCALL outputReady ASIO_ATTR_DRIVERCALL() = 0;
};
#if ASIO_SYSTEM_WINDOWS && (ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG)
#pragma pop_macro("thiscall")
#endif // ASIO_SYSTEM_WINDOWS && (ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG)
class IDriver {
protected:
IDriver() = default;
public:
virtual ~IDriver() noexcept(false) { }
public:
virtual void getDriverName(DriverName * name) = 0;
[[nodiscard]] virtual Long getDriverVersion() = 0;
virtual void getErrorMessage(ErrorMessage * string) = 0;
[[nodiscard]] virtual ErrorCode start() = 0;
[[nodiscard]] virtual ErrorCode stop() = 0;
[[nodiscard]] virtual ErrorCode getChannels(Long * numInputChannels, Long * numOutputChannels) = 0;
[[nodiscard]] virtual ErrorCode getLatencies(Long * inputLatency, Long * outputLatency) = 0;
[[nodiscard]] virtual ErrorCode getBufferSize(Long * minSize, Long * maxSize, Long * preferredSize, Long * granularity) = 0;
[[nodiscard]] virtual ErrorCode canSampleRate(SampleRate sampleRate) = 0;
[[nodiscard]] virtual ErrorCode getSampleRate(SampleRate * sampleRate) = 0;
[[nodiscard]] virtual ErrorCode setSampleRate(SampleRate sampleRate) = 0;
[[nodiscard]] virtual ErrorCode getClockSources(ClockSource * clocks, Long * numSources) = 0;
[[nodiscard]] virtual ErrorCode setClockSource(Long reference) = 0;
[[nodiscard]] virtual ErrorCode getSamplePosition(HiLoLongLong * samplePosition, HiLoLongLong * timeStamp) = 0;
[[nodiscard]] virtual ErrorCode getChannelInfo(ChannelInfo * info) = 0;
[[nodiscard]] virtual ErrorCode createBuffers(BufferInfo * bufferInfos, Long numChannels, Long bufferSize, Callbacks const * callbacks) = 0;
[[nodiscard]] virtual ErrorCode disposeBuffers() = 0;
[[nodiscard]] virtual ErrorCode controlPanel() = 0;
[[nodiscard]] virtual ErrorCode future(FutureSelector selector, void * opt) = 0;
[[nodiscard]] virtual ErrorCode outputReady() = 0;
};
} // namespace ASIO_VERSION_NAMESPACE
} // namespace Core
} // namespace ASIO
#endif // ASIO_ASIOCORE_HPP

View file

@ -0,0 +1,960 @@
#ifndef ASIO_ASIOMODERN_HPP
#define ASIO_ASIOMODERN_HPP
#include "ASIOVersion.hpp"
#include "ASIOConfig.hpp"
#include "ASIOCore.hpp"
#include <array>
#include <exception>
#include <mutex>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <cassert>
#include <cstddef>
#include <cstdint>
namespace ASIO {
inline namespace Modern {
inline namespace ASIO_VERSION_NAMESPACE {
class Error
: public std::runtime_error {
private:
ErrorCode m_Code;
private:
static constexpr std::string_view Message(ErrorCode ec) noexcept {
std::string_view message = "";
switch (ec) {
case ErrorCode::OK:
message = "OK";
break;
case ErrorCode::SUCCESS:
message = "SUCCESS";
break;
case ErrorCode::NotPresent:
message = "NotPresent";
break;
case ErrorCode::HWMalfunction:
message = "HWMalfunction";
break;
case ErrorCode::InvalidParameter:
message = "InvalidParameter";
break;
case ErrorCode::InvalidMode:
message = "InvalidMode";
break;
case ErrorCode::SPNotAdvancing:
message = "SPNotAdvancing";
break;
case ErrorCode::NoClock:
message = "NoClock";
break;
case ErrorCode::NoMemory:
message = "NoMemory";
break;
default:
message = "";
break;
}
return message;
}
public:
Error(ErrorCode ec)
: std::runtime_error(std::string("ASIO Error ") + std::string(Message(ec)))
, m_Code(ec) {
return;
}
ErrorCode Code() const noexcept {
return m_Code;
}
};
struct CallbacksWithContext {
void (*bufferSwitch)(void * context, Long doubleBufferIndex, Bool directProcess) noexcept = nullptr;
void (*sampleRateDidChange)(void * context, SampleRate sRate) noexcept = nullptr;
Long (*asioMessage)(void * context, MessageSelector selector, const Long value, const void * message, const Double * opt) noexcept = nullptr;
const Time * (*bufferSwitchTimeInfo)(void * context, const Time * params, Long doubleBufferIndex, Bool directProcess) noexcept = nullptr;
};
struct CallbacksWrapperState {
CallbacksWithContext callbacks;
void * context = nullptr;
};
#if ASIO_SYSTEM_WINDOWS && (ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG)
#pragma push_macro("cdecl")
#ifdef cdecl
#undef cdecl
#endif
#endif // ASIO_SYSTEM_WINDOWS && (ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG)
template <typename Tarray, Tarray * A, std::size_t I>
class CallbacksWrapper {
public:
static constexpr Callbacks init() noexcept {
Callbacks result = {&CallbackBufferSwitch, &CallbackSampleRateDidChange, &CallbackAsioMessage, &CallbackBufferSwitchTimeInfo};
return result;
}
public:
static void ASIO_CALL CallbackBufferSwitch ASIO_ATTR_CALL(Long doubleBufferIndex, Bool directProcess) noexcept {
return (*A)[I].callbacks.bufferSwitch((*A)[I].context, doubleBufferIndex, directProcess);
}
static void ASIO_CALL CallbackSampleRateDidChange ASIO_ATTR_CALL(SampleRate sRate) noexcept {
return (*A)[I].callbacks.sampleRateDidChange((*A)[I].context, sRate);
}
static Long ASIO_CALL CallbackAsioMessage ASIO_ATTR_CALL(MessageSelector selector, Long value, const void * message, const Double * opt) noexcept {
return (*A)[I].callbacks.asioMessage((*A)[I].context, selector, value, message, opt);
}
static const Time * ASIO_CALL CallbackBufferSwitchTimeInfo ASIO_ATTR_CALL(const Time * params, Long doubleBufferIndex, Bool directProcess) noexcept {
return (*A)[I].callbacks.bufferSwitchTimeInfo((*A)[I].context, params, doubleBufferIndex, directProcess);
}
};
#if ASIO_SYSTEM_WINDOWS && (ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG)
#pragma pop_macro("cdecl")
#endif // ASIO_SYSTEM_WINDOWS && (ASIO_COMPILER_GCC || ASIO_COMPILER_CLANG)
namespace detail {
template <typename T, std::size_t N, typename Tx>
constexpr std::array<T, N> init_array(const Tx & x) {
std::array<T, N> result{};
for (std::size_t i = 0; i < N; ++i) {
result[i] = x;
}
return result;
}
} // namespace detail
template <std::uint64_t AppID1, std::uint64_t AppID2, std::size_t MaxInstances>
class AsioCallbacksMultiplexerGlobalState {
private:
template <typename Tarray, Tarray * a, std::size_t... Is>
static constexpr auto construct_callbacks_array(std::index_sequence<Is...>) noexcept -> std::array<Callbacks, sizeof...(Is)> {
return {CallbacksWrapper<Tarray, a, Is>::init()...};
}
private:
static inline std::mutex s_AllocationMutex;
static inline std::array<bool, MaxInstances> s_Allocation = detail::init_array<bool, MaxInstances>(false);
static inline std::array<CallbacksWrapperState, MaxInstances> s_AsioCallbackWrapperStates = detail::init_array<CallbacksWrapperState, MaxInstances>(CallbacksWrapperState{
{nullptr, nullptr, nullptr, nullptr},
nullptr
});
static constexpr inline std::array<Callbacks, MaxInstances> s_AsioCallbacks = construct_callbacks_array<std::array<CallbacksWrapperState, MaxInstances>, &s_AsioCallbackWrapperStates>(std::make_index_sequence<MaxInstances>());
private:
static std::size_t Alloc() {
std::lock_guard<std::mutex> guard(s_AllocationMutex);
for (std::size_t i = 0; i < MaxInstances; ++i) {
if (!s_Allocation[i]) {
s_Allocation[i] = true;
return i;
}
}
throw Error(ErrorCode::NoMemory);
}
static void Free(std::size_t index) noexcept {
std::lock_guard<std::mutex> guard(s_AllocationMutex);
assert(s_Allocation[index]);
s_Allocation[index] = false;
}
public:
static std::pair<std::size_t, Callbacks> Multiplex(void * context, CallbacksWithContext callbacks) {
std::size_t cookie = Alloc();
s_AsioCallbackWrapperStates[cookie] = {callbacks, context};
return std::make_pair(cookie, s_AsioCallbacks[cookie]);
}
static void Unmultiplex(std::pair<std::size_t, Callbacks> state) noexcept {
Free(state.first);
}
};
class IMultiplexedCallbacks {
protected:
IMultiplexedCallbacks() = default;
public:
IMultiplexedCallbacks(const IMultiplexedCallbacks &) = delete;
IMultiplexedCallbacks & operator=(const IMultiplexedCallbacks &) = delete;
public:
virtual ~IMultiplexedCallbacks() = default;
public:
virtual operator const Callbacks *() const noexcept = 0;
virtual operator const Callbacks &() const noexcept = 0;
virtual operator Callbacks *() noexcept = 0;
virtual operator Callbacks &() noexcept = 0;
};
template <std::uint64_t AppID1, std::uint64_t AppID2, std::size_t MaxInstances>
class MultiplexedCallbacks
: public IMultiplexedCallbacks {
public:
using GlobalState = AsioCallbacksMultiplexerGlobalState<AppID1, AppID2, MaxInstances>;
using State = std::unique_ptr<IMultiplexedCallbacks>;
private:
std::pair<std::size_t, Callbacks> m_State;
public:
MultiplexedCallbacks(void * context, CallbacksWithContext callbacks)
: m_State(GlobalState::Multiplex(context, callbacks)) {
if (!callbacks.bufferSwitch) {
m_State.second.bufferSwitch = nullptr;
}
if (!callbacks.sampleRateDidChange) {
m_State.second.sampleRateDidChange = nullptr;
}
if (!callbacks.asioMessage) {
m_State.second.asioMessage = nullptr;
}
if (!callbacks.bufferSwitchTimeInfo) {
m_State.second.bufferSwitchTimeInfo = nullptr;
}
}
MultiplexedCallbacks(const MultiplexedCallbacks &) = delete;
MultiplexedCallbacks & operator=(const MultiplexedCallbacks &) = delete;
~MultiplexedCallbacks() final {
GlobalState::Unmultiplex(m_State);
}
public:
operator const Callbacks *() const noexcept final {
return &m_State.second;
}
operator const Callbacks &() const noexcept final {
return m_State.second;
}
operator Callbacks *() noexcept final {
return &m_State.second;
}
operator Callbacks &() noexcept final {
return m_State.second;
}
public:
static std::unique_ptr<MultiplexedCallbacks> make(void * context, CallbacksWithContext callbacks) {
return std::make_unique<MultiplexedCallbacks>(context, callbacks);
}
static std::unique_ptr<MultiplexedCallbacks> null() {
return std::unique_ptr<MultiplexedCallbacks>();
}
};
struct Channels {
Long Input = 0;
Long Output = 0;
};
struct Latencies {
Long Input = 0;
Long Output = 0;
};
struct BufferSizes {
Long Min = 0;
Long Max = 0;
Long Preferred = 0;
Long Granularity = 0;
};
struct SamplePosition {
Samples samplePosition = 0;
TimeStamp systemTime = 0;
};
struct BufferIndex {
std::uint8_t Index : 1;
constexpr BufferIndex() noexcept
: Index(0) {
}
constexpr BufferIndex(Long doubleBufferIndex) noexcept
: Index(static_cast<std::uint8_t>(static_cast<ULong>(doubleBufferIndex) & 1u)) {
}
constexpr BufferIndex(std::size_t bufferIndex) noexcept
: Index(static_cast<std::uint8_t>(bufferIndex & 1u)) {
}
constexpr operator std::size_t() const noexcept {
return Index;
}
};
class Driver {
public:
class ICallbackHandler {
protected:
ICallbackHandler() = default;
public:
ICallbackHandler(const ICallbackHandler &) = delete;
ICallbackHandler & operator=(const ICallbackHandler &) = delete;
virtual ~ICallbackHandler() = default;
public:
virtual Long CallbackMessage(Driver & driver, MessageSelector selector, Long value, const void * message, const Double * opt) noexcept = 0;
virtual void CallbackSampleRateDidChange(Driver & driver, SampleRate sRate) noexcept = 0;
virtual void CallbackBufferSwitch(Driver & driver, Long doubleBufferIndex, Bool directProcess) noexcept = 0;
virtual const Time * CallbackBufferSwitchTimeInfo(Driver & driver, const Time * params, Long doubleBufferIndex, Bool directProcess) noexcept = 0;
};
class CallbackHandler
: public ICallbackHandler {
/*
void MessageResetRequest() noexcept override;
bool MessageBufferSizeChange(ASIO::Long newSize) noexcept override;
bool MessageResyncRequest() noexcept override;
void MessageLatenciesChanged() noexcept override;
ASIO::Long MessageMMCCommand(ASIO::Long value, const void * message, const ASIO::Double * opt) noexcept override;
void MessageOverload() noexcept override;
ASIO::Long MessageUnknown(ASIO::MessageSelector selector, ASIO::Long value, const void * message, const ASIO::Double * opt) noexcept override;
void RealtimeSampleRateDidChange(ASIO::SampleRate sRate) noexcept override;
void RealtimeRequestDeferredProcessing(bool value) noexcept override;
void RealtimeTimeInfo(ASIO::Time time) noexcept override;
void RealtimeBufferSwitch(ASIO::BufferIndex bufferIndex) noexcept override;
*/
public:
CallbackHandler() = default;
CallbackHandler(const CallbackHandler &) = delete;
CallbackHandler & operator=(const CallbackHandler &) = delete;
virtual ~CallbackHandler() = default;
public:
bool MessageSelectorSupported(MessageSelector selector) const noexcept {
bool result = false;
switch (selector) {
case MessageSelector::SelectorSupported:
result = true;
break;
case MessageSelector::EngineVersion:
result = true;
break;
case MessageSelector::ResetRequest:
result = true;
break;
case MessageSelector::BufferSizeChange:
result = true;
break;
case MessageSelector::ResyncRequest:
result = true;
break;
case MessageSelector::LatenciesChanged:
result = true;
break;
case MessageSelector::SupportsTimeInfo:
result = true;
break;
case MessageSelector::SupportsTimeCode:
result = true;
break;
case MessageSelector::MMCCommand:
result = true;
break;
case MessageSelector::SupportsInputMonitor:
result = true;
break;
case MessageSelector::SupportsInputGain:
result = true;
break;
case MessageSelector::SupportsInputMeter:
result = true;
break;
case MessageSelector::SupportsOutputGain:
result = true;
break;
case MessageSelector::SupportsOutputMeter:
result = true;
break;
case MessageSelector::Overload:
result = true;
break;
}
return result;
}
Long MessageEngineVersion() const noexcept {
return 2;
}
virtual void MessageResetRequest() noexcept = 0;
virtual bool MessageBufferSizeChange(Long newSize) noexcept {
static_cast<void>(newSize);
return false;
}
virtual bool MessageResyncRequest() noexcept {
return false;
}
virtual void MessageLatenciesChanged() noexcept {
return;
}
bool MessageSupportsTimeInfo() const noexcept {
return true;
}
bool MessageSupportsTimeCode() const noexcept {
return true;
}
virtual Long MessageMMCCommand(Long value, const void * message, const Double * opt) noexcept {
static_cast<void>(value);
static_cast<void>(message);
static_cast<void>(opt);
return 0;
}
bool MessageSupportsInputMonitor() const noexcept {
return true;
}
bool MessageSupportsInputGain() const noexcept {
return true;
}
bool MessageSupportsInputMeter() const noexcept {
return true;
}
bool MessageSupportsOutputGain() const noexcept {
return true;
}
bool MessageSupportsOutputMeter() const noexcept {
return true;
}
virtual void MessageOverload() noexcept {
return;
}
virtual Long MessageUnknown(MessageSelector selector, Long value, const void * message, const Double * opt) noexcept {
static_cast<void>(selector);
static_cast<void>(value);
static_cast<void>(message);
static_cast<void>(opt);
return 0;
}
virtual void RealtimeSampleRateDidChange(SampleRate sRate) noexcept {
static_cast<void>(sRate);
}
virtual void RealtimeRequestDeferredProcessing(bool deferred) noexcept {
static_cast<void>(deferred);
}
virtual void RealtimeTimeInfo(Time time) noexcept {
static_cast<void>(time);
}
virtual void RealtimeBufferSwitch(ASIO::BufferIndex bufferIndex) noexcept = 0;
public:
Long CallbackMessage(Driver & driver, MessageSelector selector, Long value, const void * message, const Double * opt) noexcept final {
static_cast<void>(driver);
Long result = 0;
switch (selector) {
case MessageSelector::SelectorSupported:
result = MessageSelectorSupported(static_cast<MessageSelector>(value)) ? 1 : 0;
break;
case MessageSelector::EngineVersion:
result = MessageEngineVersion();
break;
case MessageSelector::ResetRequest:
MessageResetRequest();
result = 1;
break;
case MessageSelector::BufferSizeChange:
result = MessageBufferSizeChange(value) ? 1 : 0;
break;
case MessageSelector::ResyncRequest:
result = MessageResyncRequest() ? 1 : 0;
break;
case MessageSelector::LatenciesChanged:
MessageLatenciesChanged();
result = 1;
break;
case MessageSelector::SupportsTimeInfo:
result = MessageSupportsTimeInfo() ? 1 : 0;
break;
case MessageSelector::SupportsTimeCode:
result = MessageSupportsTimeCode() ? 1 : 0;
break;
case MessageSelector::MMCCommand:
result = MessageMMCCommand(value, message, opt);
break;
case MessageSelector::SupportsInputMonitor:
result = MessageSupportsInputMonitor() ? 1 : 0;
break;
case MessageSelector::SupportsInputGain:
result = MessageSupportsInputGain() ? 1 : 0;
break;
case MessageSelector::SupportsInputMeter:
result = MessageSupportsInputMeter() ? 1 : 0;
break;
case MessageSelector::SupportsOutputGain:
result = MessageSupportsOutputGain() ? 1 : 0;
break;
case MessageSelector::SupportsOutputMeter:
result = MessageSupportsOutputMeter() ? 1 : 0;
break;
case MessageSelector::Overload:
MessageOverload();
result = 1;
break;
default:
result = MessageUnknown(selector, value, message, opt);
break;
}
return result;
}
void CallbackSampleRateDidChange(Driver & driver, SampleRate sRate) noexcept final {
static_cast<void>(driver);
RealtimeSampleRateDidChange(sRate);
}
void CallbackBufferSwitch(Driver & driver, Long doubleBufferIndex, Bool directProcess) noexcept final {
CallbackBufferSwitchTimeInfo(driver, nullptr, doubleBufferIndex, directProcess);
}
const Time * CallbackBufferSwitchTimeInfo(Driver & driver, const Time * params, Long doubleBufferIndex, Bool directProcess) noexcept final {
Time time;
if (params) {
time = *params;
} else {
try {
HiLoLongLong samplePosition = 0;
HiLoLongLong systemTime = 0;
if (driver.realDriver().getSamplePosition(&samplePosition, &systemTime) == ErrorCode::OK) {
time.timeInfo.flags |= TimeInfoFlagSamplePositionValid | TimeInfoFlagSystemTimeValid;
time.timeInfo.samplePosition = samplePosition;
time.timeInfo.systemTime = systemTime;
time.timeInfo.speed = 1.0;
SampleRate sampleRate = 0.0;
if (driver.realDriver().getSampleRate(&sampleRate) == ErrorCode::OK) {
if (sampleRate >= 0.0) {
time.timeInfo.flags |= TimeInfoFlagSampleRateValid;
time.timeInfo.sampleRate = sampleRate;
}
}
}
} catch (...) {
// nothing
}
}
RealtimeRequestDeferredProcessing(!directProcess);
RealtimeTimeInfo(time);
RealtimeBufferSwitch(doubleBufferIndex);
return params;
}
};
private:
std::unique_ptr<IDriver> m_Driver;
ICallbackHandler * m_CallbackHandler = nullptr;
std::unique_ptr<IMultiplexedCallbacks> m_Callbacks;
private:
const IDriver & realDriver() const noexcept {
return *m_Driver;
}
IDriver & realDriver() noexcept {
return *m_Driver;
}
public:
explicit Driver(std::unique_ptr<IDriver> driver)
: m_Driver(std::move(driver)) {
return;
}
Driver(const Driver &) = delete;
Driver & operator=(const Driver &) = delete;
~Driver() {
return;
}
private:
[[nodiscard]] static ErrorCode CheckResultOutOfMemory(ErrorCode ec) {
if (ec == ErrorCode::NoMemory) {
throw std::bad_alloc();
}
return ec;
}
static void CheckResult(ErrorCode expected, ErrorCode ec) {
ec = CheckResultOutOfMemory(ec);
if (ec != expected) {
throw Error(ec);
}
}
static void CheckResultNoOutOfMemory(ErrorCode expected, ErrorCode ec) {
if (ec != expected) {
throw Error(ec);
}
}
static void CheckOK(ErrorCode ec) {
CheckResult(ErrorCode::OK, ec);
}
static void CheckSUCCESS(ErrorCode ec) {
CheckResult(ErrorCode::SUCCESS, ec);
}
static void CheckOKNoOutOfMemory(ErrorCode ec) {
CheckResultNoOutOfMemory(ErrorCode::OK, ec);
}
static void CheckSUCCESSNoOutOfMemory(ErrorCode ec) {
CheckResultNoOutOfMemory(ErrorCode::SUCCESS, ec);
}
private:
static Driver * ThisFromVoid(void * context) noexcept {
return reinterpret_cast<Driver *>(context);
}
void * MyContext() noexcept {
return this;
}
static constexpr CallbacksWithContext MyCallbacks() noexcept {
CallbacksWithContext result = {&CallbackBufferSwitch, &CallbackSampleRateDidChange, &CallbackAsioMessage, &CallbackBufferSwitchTimeInfo};
return result;
}
private:
static void CallbackBufferSwitch(void * context, Long doubleBufferIndex, Bool directProcess) noexcept {
assert(context);
assert(ThisFromVoid(context)->m_CallbackHandler);
return ThisFromVoid(context)->m_CallbackHandler->CallbackBufferSwitch(*ThisFromVoid(context), doubleBufferIndex, directProcess);
}
static void CallbackSampleRateDidChange(void * context, SampleRate sRate) noexcept {
assert(context);
assert(ThisFromVoid(context)->m_CallbackHandler);
return ThisFromVoid(context)->m_CallbackHandler->CallbackSampleRateDidChange(*ThisFromVoid(context), sRate);
}
static Long CallbackAsioMessage(void * context, MessageSelector selector, Long value, const void * message, const Double * opt) noexcept {
assert(context);
assert(ThisFromVoid(context)->m_CallbackHandler);
return ThisFromVoid(context)->m_CallbackHandler->CallbackMessage(*ThisFromVoid(context), selector, value, message, opt);
}
static const Time * CallbackBufferSwitchTimeInfo(void * context, const Time * params, Long doubleBufferIndex, Bool directProcess) noexcept {
assert(context);
assert(ThisFromVoid(context)->m_CallbackHandler);
return ThisFromVoid(context)->m_CallbackHandler->CallbackBufferSwitchTimeInfo(*ThisFromVoid(context), params, doubleBufferIndex, directProcess);
}
public:
std::string getDriverName() const {
DriverName name = "";
m_Driver->getDriverName(&name);
return name;
}
[[nodiscard]] Long getDriverVersion() const {
return m_Driver->getDriverVersion();
}
std::string getErrorMessage() const {
ErrorMessage string = "";
m_Driver->getErrorMessage(&string);
return string;
}
void start() {
CheckOK(m_Driver->start());
}
void stop() {
CheckOK(m_Driver->stop());
}
Channels getChannels() const {
Channels result;
CheckOK(m_Driver->getChannels(&result.Input, &result.Output));
return result;
}
Latencies getLatencies() const {
Latencies result;
CheckOK(m_Driver->getLatencies(&result.Input, &result.Output));
return result;
}
BufferSizes getBufferSizes() const {
BufferSizes result;
CheckOK(m_Driver->getBufferSize(&result.Min, &result.Max, &result.Preferred, &result.Granularity));
return result;
}
bool canSampleRate(SampleRate sampleRate) const {
ErrorCode ec = m_Driver->canSampleRate(sampleRate);
if ((ec != ErrorCode::OK) && (ec != ErrorCode::NoClock)) {
CheckOK(ec);
}
return (ec == ErrorCode::OK);
}
SampleRate getSampleRate() const {
SampleRate sampleRate = 0.0;
ErrorCode ec = m_Driver->getSampleRate(&sampleRate);
if ((ec != ErrorCode::OK) && (ec != ErrorCode::NoClock)) {
CheckOK(ec);
}
return sampleRate;
}
void setSampleRate(SampleRate sampleRate) {
CheckOK(m_Driver->setSampleRate(sampleRate));
}
std::vector<ClockSource> getClockSources() const {
std::vector<ClockSource> clocks(1);
Long numSources = 1;
CheckOK(m_Driver->getClockSources(clocks.data(), &numSources));
if (numSources > 1) {
clocks.resize(numSources);
CheckOK(m_Driver->getClockSources(clocks.data(), &numSources));
}
return clocks;
}
void setClockSource(Long reference) {
CheckOK(m_Driver->setClockSource(reference));
}
SamplePosition getSamplePosition() const {
HiLoLongLong samplePosition = 0;
HiLoLongLong systemTime = 0;
CheckOK(m_Driver->getSamplePosition(&samplePosition, &systemTime));
SamplePosition result;
result.samplePosition = samplePosition;
result.systemTime = systemTime;
return result;
}
ChannelInfo getChannelInfo(Long channel, Bool input) const {
ChannelInfo info;
info.channel = channel;
info.isInput = input;
CheckOK(m_Driver->getChannelInfo(&info));
return info;
}
template <std::uint64_t AppID1, std::uint64_t AppID2, std::size_t MaxInstances = 256>
void createBuffers(std::vector<BufferInfo> & bufferInfos, Long bufferSize, ICallbackHandler & handler) {
assert(!m_CallbackHandler);
assert(!m_Callbacks);
m_CallbackHandler = &handler;
m_Callbacks = MultiplexedCallbacks<AppID1, AppID2, MaxInstances>::make(MyContext(), MyCallbacks());
try {
CheckOKNoOutOfMemory(m_Driver->createBuffers(bufferInfos.data(), static_cast<Long>(bufferInfos.size()), bufferSize, *m_Callbacks));
} catch (...) {
m_Callbacks = nullptr;
m_CallbackHandler = nullptr;
throw;
}
}
void disposeBuffers() {
assert(m_CallbackHandler);
assert(m_Callbacks);
try {
CheckOK(m_Driver->disposeBuffers());
} catch (...) {
m_Callbacks = nullptr;
m_CallbackHandler = nullptr;
throw;
}
m_Callbacks = nullptr;
m_CallbackHandler = nullptr;
}
bool controlPanel() {
ErrorCode ec = m_Driver->controlPanel();
if ((ec != ErrorCode::OK) && (ec != ErrorCode::NotPresent)) {
CheckOK(ec);
}
return (ec == ErrorCode::OK);
}
[[deprecated]] [[nodiscard]] ErrorCode future(FutureSelector selector, void * opt) {
return CheckResultOutOfMemory(m_Driver->future(selector, opt));
}
void enableTimeCodeRead() {
CheckSUCCESS(m_Driver->future(FutureSelector::EnableTimeCodeRead, nullptr));
}
void disableTimeCodeRead() {
CheckSUCCESS(m_Driver->future(FutureSelector::DisableTimeCodeRead, nullptr));
}
void setInputMonitor(InputMonitor & inputMonitor) {
CheckSUCCESS(m_Driver->future(FutureSelector::SetInputMonitor, &inputMonitor));
}
void transport(TransportParameters & transportParameters) {
CheckSUCCESS(m_Driver->future(FutureSelector::Transport, &transportParameters));
}
void setInputGain(Long channel, Bool input, Long gain) {
ChannelControls channelControls;
channelControls.channel = channel;
channelControls.isInput = input;
channelControls.gain = gain;
CheckSUCCESS(m_Driver->future(FutureSelector::SetInputGain, &channelControls));
}
Long getInputMeter(Long channel, Bool input) const {
ChannelControls channelControls;
channelControls.channel = channel;
channelControls.isInput = input;
CheckSUCCESS(m_Driver->future(FutureSelector::GetInputMeter, &channelControls));
return channelControls.meter;
}
void setOutputGain(Long channel, Bool input, Long gain) {
ChannelControls channelControls;
channelControls.channel = channel;
channelControls.isInput = input;
channelControls.gain = gain;
CheckSUCCESS(m_Driver->future(FutureSelector::SetOutputGain, &channelControls));
}
Long getOutputMeter(Long channel, Bool input) const {
ChannelControls channelControls;
channelControls.channel = channel;
channelControls.isInput = input;
CheckSUCCESS(m_Driver->future(FutureSelector::GetOutputMeter, &channelControls));
return channelControls.meter;
}
bool canInputMonitor() const {
ErrorCode ec = CheckResultOutOfMemory(m_Driver->future(FutureSelector::CanInputMonitor, nullptr));
return (ec == ErrorCode::SUCCESS);
}
bool canTimeInfo() const {
ErrorCode ec = CheckResultOutOfMemory(m_Driver->future(FutureSelector::CanTimeInfo, nullptr));
return (ec == ErrorCode::SUCCESS);
}
bool canTimeCode() const {
ErrorCode ec = CheckResultOutOfMemory(m_Driver->future(FutureSelector::CanTimeCode, nullptr));
return (ec == ErrorCode::SUCCESS);
}
bool canTransport() const {
ErrorCode ec = CheckResultOutOfMemory(m_Driver->future(FutureSelector::CanTransport, nullptr));
return (ec == ErrorCode::SUCCESS);
}
bool canInputGain() const {
ErrorCode ec = CheckResultOutOfMemory(m_Driver->future(FutureSelector::CanInputGain, nullptr));
return (ec == ErrorCode::SUCCESS);
}
bool canInputMeter() const {
ErrorCode ec = CheckResultOutOfMemory(m_Driver->future(FutureSelector::CanInputMeter, nullptr));
return (ec == ErrorCode::SUCCESS);
}
bool canOutputGain() const {
ErrorCode ec = CheckResultOutOfMemory(m_Driver->future(FutureSelector::CanOutputGain, nullptr));
return (ec == ErrorCode::SUCCESS);
}
bool canOutputMeter() const {
ErrorCode ec = CheckResultOutOfMemory(m_Driver->future(FutureSelector::CanOutputMeter, nullptr));
return (ec == ErrorCode::SUCCESS);
}
[[nodiscard]] ErrorCode optionalOne(void * param) {
return CheckResultOutOfMemory(m_Driver->future(FutureSelector::OptionalOne, param));
}
void setIoFormat(IoFormatType type) {
IoFormat ioFormat;
ioFormat.FormatType = type;
CheckSUCCESS(m_Driver->future(FutureSelector::SetIoFormat, &ioFormat));
}
IoFormatType getIoFormat() const {
IoFormat ioFormat;
CheckSUCCESS(m_Driver->future(FutureSelector::GetIoFormat, &ioFormat));
return ioFormat.FormatType;
}
bool canDoIoFormat(IoFormatType type) {
IoFormat ioFormat;
ioFormat.FormatType = type;
ErrorCode ec = CheckResultOutOfMemory(m_Driver->future(FutureSelector::CanDoIoFormat, &ioFormat));
return (ec == ErrorCode::SUCCESS);
}
bool canReportOverload() const {
ErrorCode ec = CheckResultOutOfMemory(m_Driver->future(FutureSelector::CanReportOverload, nullptr));
return (ec == ErrorCode::SUCCESS);
}
InternalBufferInfo getInternalBufferSamples() const {
InternalBufferInfo internalBufferInfo;
ErrorCode ec = CheckResultOutOfMemory(m_Driver->future(FutureSelector::CanReportOverload, &internalBufferInfo));
if (ec != ErrorCode::SUCCESS) {
return InternalBufferInfo();
}
return internalBufferInfo;
}
bool canOutputReady() const {
ErrorCode ec = m_Driver->outputReady();
if ((ec != ErrorCode::OK) && (ec != ErrorCode::NotPresent)) {
CheckOK(ec);
}
return (ec == ErrorCode::OK);
}
void outputReady() {
CheckOK(m_Driver->outputReady());
}
};
} // namespace ASIO_VERSION_NAMESPACE
} // namespace Modern
} // namespace ASIO
#endif // ASIO_ASIOMODERN_HPP

View file

@ -0,0 +1,511 @@
#ifndef ASIO_ASIOSYSTEMWINDOWS_HPP
#define ASIO_ASIOSYSTEMWINDOWS_HPP
#include "ASIOVersion.hpp"
#include "ASIOConfig.hpp"
#include "ASIOCore.hpp"
#include <exception>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
#include <cassert>
#if ASIO_SYSTEM_WINDOWS
#include <windows.h>
#if !defined(NTDDI_VERSION)
#error "NTDDI_VERSION undefined"
#endif
#if !defined(_WIN32_WINNT)
#error "_WIN32_WINNT undefined"
#endif
#include <avrt.h>
#endif // ASIO_SYSTEM_WINDOWS
#if ASIO_SYSTEM_WINDOWS
#if ASIO_HAVE_PRAGMA_COMMENT_LIB
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "avrt.lib")
#endif // ASIO_HAVE_PRAGMA_COMMENT_LIB
#endif // ASIO_SYSTEM_WINDOWS
namespace ASIO {
#if ASIO_SYSTEM_WINDOWS
namespace Windows {
inline namespace ASIO_VERSION_NAMESPACE {
static_assert(NTDDI_VERSION >= NTDDI_WIN7);
static_assert(_WIN32_WINNT >= _WIN32_WINNT_WIN7);
#if defined(UNICODE)
inline namespace Unicode {
#else
inline namespace Ansi {
#endif
struct DriverInfo {
std::basic_string<TCHAR> Key;
std::basic_string<TCHAR> Id;
CLSID Clsid{};
std::basic_string<TCHAR> Name;
std::basic_string<TCHAR> Description;
std::basic_string<TCHAR> DisplayName() const {
if (Description.empty()) {
return Key;
}
return Description;
}
};
class HKey {
private:
HKEY m_Key = NULL;
public:
HKey() = default;
HKey(const HKey &) = delete;
HKey & operator=(const HKey &) = delete;
~HKey() {
if (m_Key) {
RegCloseKey(m_Key);
}
}
operator HKEY &() {
return m_Key;
}
operator HKEY *() {
return &m_Key;
}
};
inline LRESULT CheckLRESULTOutOfMemory(LRESULT lr) {
if ((lr == ERROR_NOT_ENOUGH_MEMORY) || (lr == ERROR_OUTOFMEMORY)) {
throw std::bad_alloc();
}
return lr;
}
inline HRESULT CheckHRESULTOutOfMemory(HRESULT hr) {
if (hr == E_OUTOFMEMORY) {
throw std::bad_alloc();
}
return hr;
}
inline std::vector<DriverInfo> EnumerateDrivers() {
std::vector<DriverInfo> drivers;
HKey hkAsioEnum;
if (CheckLRESULTOutOfMemory(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\ASIO"), 0, KEY_READ, hkAsioEnum)) != ERROR_SUCCESS) {
return drivers;
}
DWORD numSubKeys = 0;
DWORD maxSubKeyLen = 0;
if (CheckLRESULTOutOfMemory(RegQueryInfoKey(hkAsioEnum, NULL, NULL, NULL, &numSubKeys, &maxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL)) != ERROR_SUCCESS) {
return drivers;
}
for (DWORD i = 0; i < numSubKeys; ++i) {
std::vector<TCHAR> bufKey(static_cast<std::size_t>(maxSubKeyLen) + 1);
DWORD lenKey = static_cast<DWORD>(bufKey.size());
if (CheckLRESULTOutOfMemory(RegEnumKeyEx(hkAsioEnum, i, bufKey.data(), &lenKey, NULL, NULL, NULL, NULL)) != ERROR_SUCCESS) {
continue;
}
std::basic_string<TCHAR> key(bufKey.data(), bufKey.data() + lenKey);
HKey hkDriver;
if (CheckLRESULTOutOfMemory(RegOpenKeyEx(hkAsioEnum, key.c_str(), 0, KEY_READ, hkDriver)) != ERROR_SUCCESS) {
continue;
}
DWORD maxValueLen = 0;
if (CheckLRESULTOutOfMemory(RegQueryInfoKey(hkDriver, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &maxValueLen, NULL, NULL)) != ERROR_SUCCESS) {
continue;
}
std::vector<TCHAR> bufClsid(static_cast<std::size_t>(maxValueLen) + 1);
DWORD lenClsid = static_cast<DWORD>(bufClsid.size()) * sizeof(TCHAR);
DWORD typeClsid = REG_SZ;
if (CheckLRESULTOutOfMemory(RegQueryValueEx(hkDriver, TEXT("CLSID"), NULL, &typeClsid, reinterpret_cast<LPBYTE>(bufClsid.data()), &lenClsid)) != ERROR_SUCCESS) {
continue;
}
std::basic_string<TCHAR> strClsid = std::basic_string<TCHAR>(bufClsid.data(), bufClsid.data() + (lenClsid / sizeof(TCHAR))).c_str();
std::vector<OLECHAR> oleClsid(strClsid.c_str(), strClsid.c_str() + strClsid.length() + 1);
CLSID clsid = CLSID();
if (CheckHRESULTOutOfMemory(CLSIDFromString(oleClsid.data(), &clsid)) != NOERROR) {
continue;
}
std::vector<TCHAR> bufName(static_cast<std::size_t>(maxValueLen) + 1);
DWORD lenName = static_cast<DWORD>(bufName.size()) * sizeof(TCHAR);
DWORD typeName = REG_SZ;
std::basic_string<TCHAR> name;
if (CheckLRESULTOutOfMemory(RegQueryValueEx(hkDriver, TEXT(""), NULL, &typeName, reinterpret_cast<LPBYTE>(bufName.data()), &lenName)) == ERROR_SUCCESS) {
name = std::basic_string<TCHAR>(bufName.data(), bufName.data() + (lenName / sizeof(TCHAR))).c_str();
}
std::vector<TCHAR> bufDesc(static_cast<std::size_t>(maxValueLen) + 1);
DWORD lenDesc = static_cast<DWORD>(bufDesc.size()) * sizeof(TCHAR);
DWORD typeDesc = REG_SZ;
std::basic_string<TCHAR> desc;
if (CheckLRESULTOutOfMemory(RegQueryValueEx(hkDriver, TEXT("Description"), NULL, &typeDesc, reinterpret_cast<LPBYTE>(bufDesc.data()), &lenDesc)) == ERROR_SUCCESS) {
desc = std::basic_string<TCHAR>(bufDesc.data(), bufDesc.data() + (lenDesc / sizeof(TCHAR))).c_str();
}
DriverInfo info;
info.Key = key;
info.Id = strClsid;
info.Clsid = clsid;
info.Name = name;
info.Description = desc;
drivers.push_back(std::move(info));
}
return drivers;
}
[[nodiscard]] inline ISystemDriver * OpenDriver(CLSID clsid) {
ISystemDriver * driver = nullptr;
if (CheckHRESULTOutOfMemory(CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, clsid, reinterpret_cast<void **>(&driver))) != S_OK) {
return nullptr;
}
return driver;
}
inline ULONG CloseDriver(ISystemDriver * driver) {
return driver->Release();
}
struct DriverLoadFailed
: public std::runtime_error {
DriverLoadFailed()
: std::runtime_error("ASIO Driver load failed.") {
return;
}
};
struct DriverInitFailed
: public std::runtime_error {
DriverInitFailed()
: std::runtime_error("ASIO Driver init failed.") {
return;
}
};
class Driver
: public IDriver {
private:
ISystemDriver * m_Driver = nullptr;
public:
explicit Driver(CLSID clsid, HWND wnd) {
m_Driver = openDriver(clsid);
if (!m_Driver) {
throw DriverLoadFailed();
}
if (!initDriver(wnd)) {
closeDriver(m_Driver);
throw DriverInitFailed();
}
}
Driver(const Driver &) = delete;
Driver & operator=(const Driver &) = delete;
~Driver() override {
closeDriver(m_Driver);
}
private:
ISystemDriver * openDriver(CLSID clsid) {
return OpenDriver(clsid);
}
ULONG closeDriver(ISystemDriver * driver) {
return driver->Release();
}
private:
Bool initDriver(HWND sysHandle) {
return static_cast<Bool>(m_Driver->init(reinterpret_cast<SysHandle>(sysHandle)));
}
public:
void getDriverName(DriverName * name) final {
return m_Driver->getDriverName(name);
}
[[nodiscard]] Long getDriverVersion() final {
return m_Driver->getDriverVersion();
}
void getErrorMessage(ErrorMessage * string) final {
return m_Driver->getErrorMessage(string);
}
[[nodiscard]] ErrorCode start() final {
return m_Driver->start();
}
[[nodiscard]] ErrorCode stop() final {
return m_Driver->stop();
}
[[nodiscard]] ErrorCode getChannels(Long * numInputChannels, Long * numOutputChannels) final {
return m_Driver->getChannels(numInputChannels, numOutputChannels);
}
[[nodiscard]] ErrorCode getLatencies(Long * inputLatency, Long * outputLatency) final {
return m_Driver->getLatencies(inputLatency, outputLatency);
}
[[nodiscard]] ErrorCode getBufferSize(Long * minSize, Long * maxSize, Long * preferredSize, Long * granularity) final {
return m_Driver->getBufferSize(minSize, maxSize, preferredSize, granularity);
}
[[nodiscard]] ErrorCode canSampleRate(SampleRate sampleRate) final {
return m_Driver->canSampleRate(sampleRate);
}
[[nodiscard]] ErrorCode getSampleRate(SampleRate * sampleRate) final {
return m_Driver->getSampleRate(sampleRate);
}
[[nodiscard]] ErrorCode setSampleRate(SampleRate sampleRate) final {
return m_Driver->setSampleRate(sampleRate);
}
[[nodiscard]] ErrorCode getClockSources(ClockSource * clocks, Long * numSources) final {
return m_Driver->getClockSources(clocks, numSources);
}
[[nodiscard]] ErrorCode setClockSource(Long reference) final {
return m_Driver->setClockSource(reference);
}
[[nodiscard]] ErrorCode getSamplePosition(HiLoLongLong * samplePosition, HiLoLongLong * timeStamp) final {
return m_Driver->getSamplePosition(samplePosition, timeStamp);
}
[[nodiscard]] ErrorCode getChannelInfo(ChannelInfo * info) final {
return m_Driver->getChannelInfo(info);
}
[[nodiscard]] ErrorCode createBuffers(BufferInfo * bufferInfos, Long numChannels, Long bufferSize, Callbacks const * callbacks) final {
return m_Driver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks);
}
[[nodiscard]] ErrorCode disposeBuffers() final {
return m_Driver->disposeBuffers();
}
[[nodiscard]] ErrorCode controlPanel() final {
return m_Driver->controlPanel();
}
[[nodiscard]] ErrorCode future(FutureSelector selector, void * opt) final {
return m_Driver->future(selector, opt);
}
[[nodiscard]] ErrorCode outputReady() final {
return m_Driver->outputReady();
}
};
class IBufferSwitchDispatcher {
public:
virtual ~IBufferSwitchDispatcher() = default;
public:
virtual void Dispatch(std::size_t bufferIndex) = 0;
};
class BufferSwitchDispatcherBase
: public IBufferSwitchDispatcher {
private:
HANDLE m_hBufferSwitch[2] = {NULL, NULL};
HANDLE m_hStarted = NULL;
HANDLE m_hStopRequest = NULL;
HANDLE m_hThread = NULL;
public:
BufferSwitchDispatcherBase() {
m_hBufferSwitch[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_hBufferSwitch[0] == NULL) {
goto error;
}
m_hBufferSwitch[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_hBufferSwitch[1] == NULL) {
goto error;
}
m_hStarted = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hStarted == NULL) {
goto error;
}
m_hStopRequest = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hStopRequest == NULL) {
goto error;
}
m_hThread = CreateThread(NULL, 0, &ThreadProc, this, 0, NULL);
if (m_hThread == NULL) {
goto error;
}
if (WaitForSingleObject(m_hStarted, INFINITE) != WAIT_OBJECT_0) {
if (SetEvent(m_hStopRequest) != TRUE) {
goto error;
}
if (WaitForSingleObject(m_hThread, INFINITE) != WAIT_OBJECT_0) {
goto error;
}
goto error;
}
return;
error:
if (m_hThread != NULL) {
CloseHandle(m_hThread);
}
if (m_hStopRequest != NULL) {
CloseHandle(m_hStopRequest);
}
if (m_hStarted != NULL) {
CloseHandle(m_hStarted);
}
if (m_hBufferSwitch[1] != NULL) {
CloseHandle(m_hBufferSwitch[1]);
}
if (m_hBufferSwitch[0] != NULL) {
CloseHandle(m_hBufferSwitch[0]);
}
throw std::bad_alloc();
}
~BufferSwitchDispatcherBase() override {
SetEvent(m_hStopRequest);
WaitForSingleObject(m_hThread, INFINITE);
CloseHandle(m_hThread);
CloseHandle(m_hStopRequest);
CloseHandle(m_hStarted);
CloseHandle(m_hBufferSwitch[1]);
CloseHandle(m_hBufferSwitch[0]);
}
BufferSwitchDispatcherBase(const BufferSwitchDispatcherBase &) noexcept = delete;
BufferSwitchDispatcherBase & operator=(const BufferSwitchDispatcherBase &) noexcept = delete;
private:
static DWORD WINAPI ThreadProc(LPVOID lpParameter) noexcept {
if (!lpParameter) {
return 1;
}
return static_cast<BufferSwitchDispatcherBase *>(lpParameter)->ThreadMain() ? 0 : 1;
}
[[nodiscard]] bool ThreadMain() noexcept {
DWORD task_idx = 0;
HANDLE hTask = AvSetMmThreadCharacteristics(TEXT("Pro Audio"), &task_idx);
SetEvent(m_hStarted);
bool result = ThreadLoop();
if (hTask) {
AvRevertMmThreadCharacteristics(hTask);
}
hTask = NULL;
task_idx = 0;
return result;
}
[[nodiscard]] bool ThreadLoop() noexcept {
bool stop = false;
while (!stop) {
HANDLE events[3] = {m_hBufferSwitch[0], m_hBufferSwitch[1], m_hStopRequest};
switch (WaitForMultipleObjects(3, events, FALSE, INFINITE)) {
case WAIT_OBJECT_0 + 0:
CallFunc(0);
break;
case WAIT_OBJECT_0 + 1:
CallFunc(1);
break;
case WAIT_OBJECT_0 + 2:
stop = true;
break;
default:
return false;
break;
}
}
return true;
}
protected:
virtual void CallFunc(std::size_t bufferIndex) = 0;
public:
void Dispatch(std::size_t bufferIndex) final {
if (SetEvent(m_hBufferSwitch[bufferIndex & 1u]) != TRUE) {
throw std::bad_alloc();
}
}
};
template <typename Tfunc>
class BufferSwitchDispatcher
: public BufferSwitchDispatcherBase {
private:
Tfunc m_func;
public:
BufferSwitchDispatcher(Tfunc func)
: m_func(func) {
return;
}
protected:
void CallFunc(std::size_t bufferIndex) final {
m_func(bufferIndex);
}
};
template <typename Tfunc>
inline std::unique_ptr<IBufferSwitchDispatcher> CreateBufferSwitchDispatcher(Tfunc func) {
return std::make_unique<BufferSwitchDispatcher<Tfunc>>(func);
}
#if defined(UNICODE)
} // namespace Unicode
#else
} // namespace Ansi
#endif
} // namespace ASIO_VERSION_NAMESPACE
} // namespace Windows
#endif // ASIO_SYSTEM_WINDOWS
} // namespace ASIO
#endif // ASIO_ASIOSYSTEMWINDOWS_HPP

View file

@ -0,0 +1,283 @@
#ifndef ASIO_ASIOSYSTEMWINDOWSSEH_HPP
#define ASIO_ASIOSYSTEMWINDOWSSEH_HPP
#include "ASIOVersion.hpp"
#include "ASIOConfig.hpp"
#include "ASIOCore.hpp"
#include "ASIOSystemWindows.hpp"
#include <memory>
#include <string_view>
#include <cassert>
#if ASIO_SYSTEM_WINDOWS
#include <windows.h>
#if !defined(NTDDI_VERSION)
#error "NTDDI_VERSION undefined"
#endif
#if !defined(_WIN32_WINNT)
#error "_WIN32_WINNT undefined"
#endif
#endif // ASIO_SYSTEM_WINDOWS
namespace ASIO {
#if ASIO_SYSTEM_WINDOWS
namespace Windows {
inline namespace ASIO_VERSION_NAMESPACE {
static_assert(NTDDI_VERSION >= NTDDI_WIN7);
static_assert(_WIN32_WINNT >= _WIN32_WINNT_WIN7);
#if defined(UNICODE)
inline namespace Unicode {
#else
inline namespace Ansi {
#endif
namespace SEH {
struct DriverCrash {
private:
DWORD m_Code;
std::string_view m_Func;
public:
explicit constexpr DriverCrash(DWORD code, std::string_view func) noexcept
: m_Code(code)
, m_Func(func) {
return;
}
public:
constexpr DWORD code() const noexcept {
return m_Code;
}
constexpr std::string_view func() const noexcept {
return m_Func;
}
};
class IState {
protected:
IState() noexcept = default;
public:
IState(const IState &) = delete;
IState & operator=(const IState &) = delete;
public:
virtual ~IState() = default;
};
class ITranslator {
protected:
ITranslator() noexcept = default;
public:
ITranslator(const ITranslator &) = delete;
ITranslator & operator=(const ITranslator &) = delete;
public:
virtual ~ITranslator() = default;
public:
[[nodiscard]] virtual LONG TranslatorFilter(std::unique_ptr<IState> & state, DWORD code, LPEXCEPTION_POINTERS records, std::string_view func) const noexcept = 0;
[[noreturn]] virtual void TranslatorHandler(std::unique_ptr<IState> & state, DWORD code, std::string_view func) const = 0;
};
class DefaultTranslator
: public ITranslator {
public:
virtual ~DefaultTranslator() = default;
public:
[[nodiscard]] LONG TranslatorFilter(std::unique_ptr<IState> & /* state */, DWORD /* code */, LPEXCEPTION_POINTERS /* records */, std::string_view /* func */) const noexcept final {
return EXCEPTION_EXECUTE_HANDLER;
}
[[noreturn]] void TranslatorHandler(std::unique_ptr<IState> & /* state */, DWORD code, std::string_view func) const final {
throw DriverCrash(code, func);
}
};
class Driver
: public IDriver {
private:
ISystemDriver * m_Driver = nullptr;
std::unique_ptr<ITranslator> m_Translator = nullptr;
private:
template <typename Tfn>
static auto TranslateSEtry(std::unique_ptr<ITranslator> & translator, std::unique_ptr<IState> & state, Tfn fn, std::string_view func) -> decltype(fn()) {
__try
{
return fn();
} __except (translator->TranslatorFilter(state, GetExceptionCode(), GetExceptionInformation(), func))
{
translator->TranslatorHandler(state, GetExceptionCode(), func);
}
throw DriverCrash(0, func);
}
template <typename Tfn>
auto TranslateSE(Tfn fn, std::string_view func) -> decltype(fn()) {
assert(m_Translator);
std::unique_ptr<IState> state;
return TranslateSEtry(m_Translator, state, fn, func);
}
template <typename Tfn>
auto CallDriver(Tfn fn, std::string_view func) -> decltype(fn()) {
return TranslateSE(fn, func);
}
public:
explicit Driver(CLSID clsid, HWND wnd, std::unique_ptr<ITranslator> translator = std::make_unique<DefaultTranslator>())
: m_Translator(std::move(translator)) {
m_Driver = openDriver(clsid);
if (!m_Driver) {
throw DriverLoadFailed();
}
if (!initDriver(wnd)) {
closeDriver(m_Driver);
throw DriverInitFailed();
}
}
Driver(const Driver &) = delete;
Driver & operator=(const Driver &) = delete;
~Driver() noexcept(false) override {
closeDriver(m_Driver);
}
private:
ISystemDriver * openDriver(CLSID clsid) {
return CallDriver([&]() { return OpenDriver(clsid); }, __func__);
}
ULONG closeDriver(ISystemDriver * driver) {
return CallDriver([&]() { return CloseDriver(driver); }, __func__);
}
private:
Bool initDriver(HWND sysHandle) {
return static_cast<Bool>(CallDriver([&]() { return m_Driver->init(reinterpret_cast<SysHandle>(sysHandle)); }, __func__));
}
public:
void getDriverName(DriverName * name) final {
return CallDriver([&]() { return m_Driver->getDriverName(name); }, __func__);
}
[[nodiscard]] Long getDriverVersion() final {
return CallDriver([&]() { return m_Driver->getDriverVersion(); }, __func__);
}
void getErrorMessage(ErrorMessage * string) final {
return CallDriver([&]() { return m_Driver->getErrorMessage(string); }, __func__);
}
[[nodiscard]] ErrorCode start() final {
return CallDriver([&]() { return m_Driver->start(); }, __func__);
}
[[nodiscard]] ErrorCode stop() final {
return CallDriver([&]() { return m_Driver->stop(); }, __func__);
}
[[nodiscard]] ErrorCode getChannels(Long * numInputChannels, Long * numOutputChannels) final {
return CallDriver([&]() { return m_Driver->getChannels(numInputChannels, numOutputChannels); }, __func__);
}
[[nodiscard]] ErrorCode getLatencies(Long * inputLatency, Long * outputLatency) final {
return CallDriver([&]() { return m_Driver->getLatencies(inputLatency, outputLatency); }, __func__);
}
[[nodiscard]] ErrorCode getBufferSize(Long * minSize, Long * maxSize, Long * preferredSize, Long * granularity) final {
return CallDriver([&]() { return m_Driver->getBufferSize(minSize, maxSize, preferredSize, granularity); }, __func__);
}
[[nodiscard]] ErrorCode canSampleRate(SampleRate sampleRate) final {
return CallDriver([&]() { return m_Driver->canSampleRate(sampleRate); }, __func__);
}
[[nodiscard]] ErrorCode getSampleRate(SampleRate * sampleRate) final {
return CallDriver([&]() { return m_Driver->getSampleRate(sampleRate); }, __func__);
}
[[nodiscard]] ErrorCode setSampleRate(SampleRate sampleRate) final {
return CallDriver([&]() { return m_Driver->setSampleRate(sampleRate); }, __func__);
}
[[nodiscard]] ErrorCode getClockSources(ClockSource * clocks, Long * numSources) final {
return CallDriver([&]() { return m_Driver->getClockSources(clocks, numSources); }, __func__);
}
[[nodiscard]] ErrorCode setClockSource(Long reference) final {
return CallDriver([&]() { return m_Driver->setClockSource(reference); }, __func__);
}
[[nodiscard]] ErrorCode getSamplePosition(HiLoLongLong * samplePosition, HiLoLongLong * timeStamp) final {
return CallDriver([&]() { return m_Driver->getSamplePosition(samplePosition, timeStamp); }, __func__);
}
[[nodiscard]] ErrorCode getChannelInfo(ChannelInfo * info) final {
return CallDriver([&]() { return m_Driver->getChannelInfo(info); }, __func__);
}
[[nodiscard]] ErrorCode createBuffers(BufferInfo * bufferInfos, Long numChannels, Long bufferSize, Callbacks const * callbacks) final {
return CallDriver([&]() { return m_Driver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks); }, __func__);
}
[[nodiscard]] ErrorCode disposeBuffers() final {
return CallDriver([&]() { return m_Driver->disposeBuffers(); }, __func__);
}
[[nodiscard]] ErrorCode controlPanel() final {
return CallDriver([&]() { return m_Driver->controlPanel(); }, __func__);
}
[[nodiscard]] ErrorCode future(FutureSelector selector, void * opt) final {
return CallDriver([&]() { return m_Driver->future(selector, opt); }, __func__);
}
[[nodiscard]] ErrorCode outputReady() final {
return CallDriver([&]() { return m_Driver->outputReady(); }, __func__);
}
};
} // namespace SEH
#if defined(UNICODE)
} // namespace Unicode
#else
} // namespace Ansi
#endif
} // namespace ASIO_VERSION_NAMESPACE
} // namespace Windows
#endif // ASIO_SYSTEM_WINDOWS
} // namespace ASIO
#endif // ASIO_ASIOSYSTEMWINDOWS_HPP

View file

@ -0,0 +1,127 @@
#ifndef ASIO_ASIOVERIFY_ABI_HPP
#define ASIO_ASIOVERIFY_ABI_HPP
#include "ASIOVersion.hpp"
#include "ASIOConfig.hpp"
#include "ASIOCore.hpp"
#if __has_include(<iasiodrv.h>)
#define ASIO_ABI_VERIFIED 1
#include <iasiodrv.h>
#else
#define ASIO_ABI_VERIFIED 0
ASIO_WARNING("Warning: iasiodrv.h not found. ASIO ABI is not verified.")
#endif
namespace ASIO {
#if ASIO_ABI_VERIFIED
inline namespace VerifyABI {
inline namespace ASIO_VERSION_NAMESPACE {
static_assert(sizeof(ASIO::SysHandle) == sizeof(void *));
static_assert(sizeof(ASIO::Byte) == sizeof(char));
static_assert(sizeof(ASIO::Long) == sizeof(long));
static_assert(sizeof(ASIO::ULong) == sizeof(unsigned long));
static_assert(sizeof(ASIO::ULongLong) == sizeof(unsigned long long int));
static_assert(sizeof(ASIO::Double) == sizeof(double));
static_assert(sizeof(ASIO::Char) == sizeof(char));
static_assert(sizeof(ASIO::Padding1) == sizeof(char));
static_assert(sizeof(ASIO::PaddingLong) == sizeof(long));
static_assert(sizeof(ASIO::Bool) == sizeof(long));
static_assert(sizeof(ASIO::HiLoLongLong) == sizeof(long long int));
static_assert(sizeof(ASIO::ResultBool) == sizeof(long));
static_assert(sizeof(ASIO::CharBuf<1>) == sizeof(char[1]));
static_assert(sizeof(ASIO::Samples) == sizeof(::ASIOSamples));
static_assert(sizeof(ASIO::TimeStamp) == sizeof(::ASIOTimeStamp));
static_assert(sizeof(ASIO::SampleRate) == sizeof(::ASIOSampleRate));
static_assert(sizeof(ASIO::SampleType) == sizeof(::ASIOSampleType));
static_assert(sizeof(ASIO::ErrorCode) == sizeof(::ASIOError));
static_assert(sizeof(ASIO::TimeCodeFlags) == sizeof(::ASIOTimeCodeFlags));
static_assert(sizeof(ASIO::TimeCode) == sizeof(::ASIOTimeCode));
static_assert(sizeof(ASIO::TimeInfoFlags) == sizeof(::AsioTimeInfoFlags));
static_assert(sizeof(ASIO::TimeInfo) == sizeof(::AsioTimeInfo));
static_assert(sizeof(ASIO::Time) == sizeof(::ASIOTime));
static_assert(sizeof(ASIO::MessageSelector) == sizeof(long));
static_assert(sizeof(ASIO::Callbacks) == sizeof(::ASIOCallbacks));
static_assert(sizeof(ASIO::ClockSource) == sizeof(::ASIOClockSource));
static_assert(sizeof(ASIO::ChannelInfo) == sizeof(::ASIOChannelInfo));
static_assert(sizeof(ASIO::BufferInfo) == sizeof(::ASIOBufferInfo));
static_assert(sizeof(ASIO::FutureSelector) == sizeof(long));
static_assert(sizeof(ASIO::InputMonitor) == sizeof(::ASIOInputMonitor));
static_assert(sizeof(ASIO::ChannelControls) == sizeof(::ASIOChannelControls));
static_assert(sizeof(ASIO::TransportCommand) == sizeof(long));
static_assert(sizeof(ASIO::TransportParameters) == sizeof(::ASIOTransportParameters));
static_assert(sizeof(ASIO::IoFormatType) == sizeof(::ASIOIoFormatType));
static_assert(sizeof(ASIO::IoFormat) == sizeof(::ASIOIoFormat));
static_assert(sizeof(ASIO::InternalBufferInfo) == sizeof(::ASIOInternalBufferInfo));
static_assert(sizeof(ASIO::ISystemDriver) == sizeof(::IASIO));
static_assert(alignof(ASIO::SysHandle) == alignof(void *));
static_assert(alignof(ASIO::Byte) == alignof(char));
static_assert(alignof(ASIO::Long) == alignof(long));
static_assert(alignof(ASIO::ULong) == alignof(unsigned long));
static_assert(alignof(ASIO::ULongLong) == alignof(unsigned long long int));
static_assert(alignof(ASIO::Double) == alignof(double));
static_assert(alignof(ASIO::Char) == alignof(char));
static_assert(alignof(ASIO::Padding1) == alignof(char));
static_assert(alignof(ASIO::PaddingLong) == alignof(long));
static_assert(alignof(ASIO::Bool) == alignof(long));
static_assert((NATIVE_INT64 && (alignof(ASIO::HiLoLongLong) == alignof(long long int))) || (!NATIVE_INT64 && (alignof(ASIO::HiLoLongLong) == alignof(unsigned long[2]))));
static_assert(alignof(ASIO::ResultBool) == alignof(long));
static_assert(alignof(ASIO::CharBuf<1>) == alignof(char[1]));
static_assert(alignof(ASIO::Samples) == alignof(::ASIOSamples));
static_assert(alignof(ASIO::TimeStamp) == alignof(::ASIOTimeStamp));
static_assert(alignof(ASIO::SampleRate) == alignof(::ASIOSampleRate));
static_assert(alignof(ASIO::SampleType) == alignof(::ASIOSampleType));
static_assert(alignof(ASIO::ErrorCode) == alignof(::ASIOError));
static_assert(alignof(ASIO::TimeCodeFlags) == alignof(::ASIOTimeCodeFlags));
static_assert(alignof(ASIO::TimeCode) == alignof(::ASIOTimeCode));
static_assert(alignof(ASIO::TimeInfoFlags) == alignof(::AsioTimeInfoFlags));
static_assert(alignof(ASIO::TimeInfo) == alignof(::AsioTimeInfo));
static_assert(alignof(ASIO::Time) == alignof(::ASIOTime));
static_assert(alignof(ASIO::MessageSelector) == alignof(long));
static_assert(alignof(ASIO::Callbacks) == alignof(::ASIOCallbacks));
static_assert(alignof(ASIO::ClockSource) == alignof(::ASIOClockSource));
static_assert(alignof(ASIO::ChannelInfo) == alignof(::ASIOChannelInfo));
static_assert(alignof(ASIO::BufferInfo) == alignof(::ASIOBufferInfo));
static_assert(alignof(ASIO::FutureSelector) == alignof(long));
static_assert(alignof(ASIO::InputMonitor) == alignof(::ASIOInputMonitor));
static_assert(alignof(ASIO::ChannelControls) == alignof(::ASIOChannelControls));
static_assert(alignof(ASIO::TransportCommand) == alignof(long));
static_assert(alignof(ASIO::TransportParameters) == alignof(::ASIOTransportParameters));
static_assert(alignof(ASIO::IoFormatType) == alignof(::ASIOIoFormatType));
static_assert(alignof(ASIO::IoFormat) == alignof(::ASIOIoFormat));
static_assert(alignof(ASIO::InternalBufferInfo) == alignof(::ASIOInternalBufferInfo));
static_assert(alignof(ASIO::ISystemDriver) == alignof(::IASIO));
} // namespace ASIO_VERSION_NAMESPACE
} // namespace VerifyABI
#endif // ASIO_ABI_VERIFIED
} // namespace ASIO
#endif // ASIO_ASIOVERIFY_ABI_HPP

View file

@ -0,0 +1,132 @@
#ifndef ASIO_ASIOVERSION_HPP
#define ASIO_ASIOVERSION_HPP
namespace ASIO {
#define ASIO_VERSION_MAJOR 2
#define ASIO_VERSION_MINOR 3
#define ASIO_VERSION_PATCH 3
#define ASIO_VERSION_BUILD 20190614
#define ASIO_MODERNSDK_VERSION_MAJOR 0
#define ASIO_MODERNSDK_VERSION_MINOR 12
#define ASIO_MODERNSDK_VERSION_PATCH 5
#define ASIO_MODERNSDK_VERSION_BUILD 0
#define ASIO_VERSION_BUILD_NAMESPACE_IMPL(a, b, c, d) v##a##_##b##_##c
#define ASIO_VERSION_BUILD_NAMESPACE(a, b, c, d) ASIO_VERSION_BUILD_NAMESPACE_IMPL(a, b, c, d)
#define ASIO_VERSION_NAMESPACE ASIO_VERSION_BUILD_NAMESPACE(ASIO_MODERNSDK_VERSION_MAJOR, ASIO_MODERNSDK_VERSION_MINOR, ASIO_MODERNSDK_VERSION_PATCH, ASIO_MODERNSDK_VERSION_BUILD)
inline namespace Version {
inline namespace ASIO_VERSION_NAMESPACE {
struct SemanticVersion {
unsigned long long Major = 0;
unsigned long long Minor = 0;
unsigned long long Patch = 0;
constexpr std::tuple<unsigned long long, unsigned long long, unsigned long long> as_tuple() const noexcept {
return std::make_tuple(Major, Minor, Patch);
}
};
constexpr bool operator==(SemanticVersion a, SemanticVersion b) noexcept {
return a.as_tuple() == b.as_tuple();
}
constexpr bool operator!=(SemanticVersion a, SemanticVersion b) noexcept {
return a.as_tuple() != b.as_tuple();
}
constexpr bool operator<(SemanticVersion a, SemanticVersion b) noexcept {
return a.as_tuple() < b.as_tuple();
}
constexpr bool operator>(SemanticVersion a, SemanticVersion b) noexcept {
return a.as_tuple() > b.as_tuple();
}
constexpr bool operator<=(SemanticVersion a, SemanticVersion b) noexcept {
return a.as_tuple() <= b.as_tuple();
}
constexpr bool operator>=(SemanticVersion a, SemanticVersion b) noexcept {
return a.as_tuple() >= b.as_tuple();
}
struct VersionInfo {
SemanticVersion SemVer;
unsigned long long Build = 0;
constexpr std::tuple<std::tuple<unsigned long long, unsigned long long, unsigned long long>, unsigned long long> as_tuple() const noexcept {
return std::make_tuple(SemVer.as_tuple(), Build);
}
template <typename Tostream>
friend Tostream & operator<<(Tostream & os, VersionInfo vi) {
if (vi.Build > 0) {
os << vi.SemVer.Major << "." << vi.SemVer.Minor << "." << vi.SemVer.Patch << "+build." << vi.Build;
} else {
os << vi.SemVer.Major << "." << vi.SemVer.Minor << "." << vi.SemVer.Patch;
}
return os;
}
};
constexpr bool operator==(VersionInfo a, VersionInfo b) noexcept {
return a.as_tuple() == b.as_tuple();
}
constexpr bool operator!=(VersionInfo a, VersionInfo b) noexcept {
return a.as_tuple() != b.as_tuple();
}
constexpr bool operator<(VersionInfo a, VersionInfo b) noexcept {
return a.as_tuple() < b.as_tuple();
}
constexpr bool operator>(VersionInfo a, VersionInfo b) noexcept {
return a.as_tuple() > b.as_tuple();
}
constexpr bool operator<=(VersionInfo a, VersionInfo b) noexcept {
return a.as_tuple() <= b.as_tuple();
}
constexpr bool operator>=(VersionInfo a, VersionInfo b) noexcept {
return a.as_tuple() >= b.as_tuple();
}
constexpr inline VersionInfo Version = {
{ASIO_VERSION_MAJOR, ASIO_VERSION_MINOR, ASIO_VERSION_PATCH},
ASIO_VERSION_BUILD
};
constexpr inline VersionInfo ModernSDKVersion = {
{ASIO_MODERNSDK_VERSION_MAJOR, ASIO_MODERNSDK_VERSION_MINOR, ASIO_MODERNSDK_VERSION_PATCH},
ASIO_MODERNSDK_VERSION_BUILD
};
} // namespace ASIO_VERSION_NAMESPACE
} // namespace Version
} // namespace ASIO
#endif // ASIO_ASIOVERSION_HPP

View file

@ -0,0 +1,48 @@
#ifndef ASIO_ASIOSTDCXX20BIT_HPP
#define ASIO_ASIOSTDCXX20BIT_HPP
#include "ASIOVersion.hpp"
#include "ASIOConfig.hpp"
#if (__cplusplus > 202000L)
#include <bit>
namespace ASIO {
namespace stdcxx20 {
using std::bit_cast;
using std::endian;
} // namespace stdcxx20
} // namespace ASIO
#else // !C++20
#include <type_traits>
#include <cstring>
namespace ASIO {
namespace stdcxx20 {
template <class To, class From>
typename std::enable_if<(sizeof(To) == sizeof(From)) && std::is_trivially_copyable<From>::value && std::is_trivial<To>::value, To>::type inline bit_cast(const From & src) noexcept {
To dst;
std::memcpy(&dst, &src, sizeof(To));
return dst;
}
enum class endian {
#if ASIO_SYSTEM_WINDOWS
little = 0,
big = 1,
native = little,
#elif ASIO_COMPILER_CLANG || ASIO_COMPILER_GCC
little = __ORDER_LITTLE_ENDIAN__,
big = __ORDER_BIG_ENDIAN__,
native = __BYTE_ORDER__,
#endif
};
} // namespace stdcxx20
} // namespace ASIO
#endif // C++20
#endif // ASIO_ASIOSTDCXX20BIT_HPP