[+] Aurora Engine wrappers

[*] Unfuck legacy build pipeline dependency, now compiles under our buildchain
[-] Partially strip legacy logger
[-] Removed TRACE that doesn't compile with our logger
[*] Use Aurora Runtime for IO when possible
[TODO] Wrap Aurora Runtime streams
This commit is contained in:
Reece 2021-02-14 12:07:26 +00:00 committed by Reece
parent 7fb6d64ca8
commit 9ddf5419f0
19 changed files with 132 additions and 1052 deletions

View File

@ -49,7 +49,6 @@ namespace {
class filter_exception final : public al::base_exception {
public:
[[gnu::format(printf, 3, 4)]]
filter_exception(ALenum code, const char *msg, ...) : base_exception{code}
{
std::va_list args;

View File

@ -350,7 +350,7 @@ struct ALCdevice : public al::intrusive_ref<ALCdevice> {
void renderSamples(void *outBuffer, const ALuint numSamples, const size_t frameStep);
/* Caller must lock the device state, and the mixer must not be running. */
[[gnu::format(printf,2,3)]] void handleDisconnect(const char *msg, ...);
void handleDisconnect(const char *msg, ...);
DEF_NEWDEL(ALCdevice)
};

View File

@ -25,13 +25,7 @@
#include <cstdlib>
#include <cctype>
#include <cstring>
#ifdef _WIN32
#include <windows.h>
#include <shlobj.h>
#endif
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif
#include <algorithm>
#include <cstdio>
@ -280,162 +274,25 @@ void LoadConfigFromFile(std::istream &f)
} // namespace
#ifdef _WIN32
void ReadALConfig()
{
WCHAR buffer[MAX_PATH];
if(SHGetSpecialFolderPathW(nullptr, buffer, CSIDL_APPDATA, FALSE) != FALSE)
{
std::string filepath{wstr_to_utf8(buffer)};
filepath += "\\alsoft.ini";
AuString configBuffer;
TRACE("Loading config %s...\n", filepath.c_str());
al::ifstream f{filepath};
if(f.is_open())
LoadConfigFromFile(f);
AuString pathA;
Aurora::FS::GetSystemDomain("OpenAL", pathA);
pathA += "configuration.ini";
if (!Aurora::FS::ReadString(pathA, configBuffer))
{
if (!Aurora::FS::ReadString("openal.ini", configBuffer))
{
return;
}
}
std::string ppath{GetProcBinary().path};
if(!ppath.empty())
{
ppath += "\\alsoft.ini";
TRACE("Loading config %s...\n", ppath.c_str());
al::ifstream f{ppath};
if(f.is_open())
LoadConfigFromFile(f);
}
if(auto confpath = al::getenv(L"ALSOFT_CONF"))
{
TRACE("Loading config %s...\n", wstr_to_utf8(confpath->c_str()).c_str());
al::ifstream f{*confpath};
if(f.is_open())
LoadConfigFromFile(f);
}
LoadConfigFromFile(std::istringstream(configBuffer));
}
#else
void ReadALConfig()
{
const char *str{"/etc/openal/alsoft.conf"};
TRACE("Loading config %s...\n", str);
al::ifstream f{str};
if(f.is_open())
LoadConfigFromFile(f);
f.close();
std::string confpaths{al::getenv("XDG_CONFIG_DIRS").value_or("/etc/xdg")};
/* Go through the list in reverse, since "the order of base directories
* denotes their importance; the first directory listed is the most
* important". Ergo, we need to load the settings from the later dirs
* first so that the settings in the earlier dirs override them.
*/
std::string fname;
while(!confpaths.empty())
{
auto next = confpaths.find_last_of(':');
if(next < confpaths.length())
{
fname = confpaths.substr(next+1);
confpaths.erase(next);
}
else
{
fname = confpaths;
confpaths.clear();
}
if(fname.empty() || fname.front() != '/')
WARN("Ignoring XDG config dir: %s\n", fname.c_str());
else
{
if(fname.back() != '/') fname += "/alsoft.conf";
else fname += "alsoft.conf";
TRACE("Loading config %s...\n", fname.c_str());
f = al::ifstream{fname};
if(f.is_open())
LoadConfigFromFile(f);
}
fname.clear();
}
#ifdef __APPLE__
CFBundleRef mainBundle = CFBundleGetMainBundle();
if(mainBundle)
{
unsigned char fileName[PATH_MAX];
CFURLRef configURL;
if((configURL=CFBundleCopyResourceURL(mainBundle, CFSTR(".alsoftrc"), CFSTR(""), nullptr)) &&
CFURLGetFileSystemRepresentation(configURL, true, fileName, sizeof(fileName)))
{
f = al::ifstream{reinterpret_cast<char*>(fileName)};
if(f.is_open())
LoadConfigFromFile(f);
}
}
#endif
if(auto homedir = al::getenv("HOME"))
{
fname = *homedir;
if(fname.back() != '/') fname += "/.alsoftrc";
else fname += ".alsoftrc";
TRACE("Loading config %s...\n", fname.c_str());
f = al::ifstream{fname};
if(f.is_open())
LoadConfigFromFile(f);
}
if(auto configdir = al::getenv("XDG_CONFIG_HOME"))
{
fname = *configdir;
if(fname.back() != '/') fname += "/alsoft.conf";
else fname += "alsoft.conf";
}
else
{
fname.clear();
if(auto homedir = al::getenv("HOME"))
{
fname = *homedir;
if(fname.back() != '/') fname += "/.config/alsoft.conf";
else fname += ".config/alsoft.conf";
}
}
if(!fname.empty())
{
TRACE("Loading config %s...\n", fname.c_str());
f = al::ifstream{fname};
if(f.is_open())
LoadConfigFromFile(f);
}
std::string ppath{GetProcBinary().path};
if(!ppath.empty())
{
if(ppath.back() != '/') ppath += "/alsoft.conf";
else ppath += "alsoft.conf";
TRACE("Loading config %s...\n", ppath.c_str());
f = al::ifstream{ppath};
if(f.is_open())
LoadConfigFromFile(f);
}
if(auto confname = al::getenv("ALSOFT_CONF"))
{
TRACE("Loading config %s...\n", confname->c_str());
f = al::ifstream{*confname};
if(f.is_open())
LoadConfigFromFile(f);
}
}
#endif
const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def)
{

View File

@ -221,7 +221,7 @@ struct ALCcontext : public al::intrusive_ref<ALCcontext> {
/** Resumes update processing after being deferred. */
void processUpdates();
[[gnu::format(printf,3,4)]] void setError(ALenum errorCode, const char *msg, ...);
void setError(ALenum errorCode, const char *msg, ...);
DEF_NEWDEL(ALCcontext)
};

View File

@ -95,7 +95,6 @@ namespace al {
class backend_exception final : public base_exception {
public:
[[gnu::format(printf, 3, 4)]]
backend_exception(ALCenum code, const char *msg, ...) : base_exception{code}
{
std::va_list args;

View File

@ -161,7 +161,7 @@ BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR*, voi
HRESULT hr{StringFromCLSID(*guid, &guidstr)};
if(SUCCEEDED(hr))
{
TRACE("Got device \"%s\", GUID \"%ls\"\n", newentry.name.c_str(), guidstr);
//TRACE("Got device \"%s\", GUID \"%ls\"\n", newentry.name.c_str(), guidstr);
CoTaskMemFree(guidstr);
}

View File

@ -1,9 +1 @@
#ifndef AL_COMPAT_H
#define AL_COMPAT_H
#include <string>
struct PathNamePair { std::string path, fname; };
const PathNamePair &GetProcBinary(void);
#endif /* AL_COMPAT_H */

View File

@ -129,7 +129,6 @@ union EffectProps {
class effect_exception final : public al::base_exception {
public:
[[gnu::format(printf, 3, 4)]]
effect_exception(ALenum code, const char *msg, ...);
};

View File

@ -40,46 +40,6 @@
#include "vector.h"
#ifdef _WIN32
#include <shlobj.h>
const PathNamePair &GetProcBinary()
{
static PathNamePair ret;
if(!ret.fname.empty() || !ret.path.empty())
return ret;
auto fullpath = al::vector<WCHAR>(256);
DWORD len;
while((len=GetModuleFileNameW(nullptr, fullpath.data(), static_cast<DWORD>(fullpath.size()))) == fullpath.size())
fullpath.resize(fullpath.size() << 1);
if(len == 0)
{
ERR("Failed to get process name: error %lu\n", GetLastError());
return ret;
}
fullpath.resize(len);
if(fullpath.back() != 0)
fullpath.push_back(0);
auto sep = std::find(fullpath.rbegin()+1, fullpath.rend(), '\\');
sep = std::find(fullpath.rbegin()+1, sep, '/');
if(sep != fullpath.rend())
{
*sep = 0;
ret.fname = wstr_to_utf8(&*sep + 1);
ret.path = wstr_to_utf8(fullpath.data());
}
else
ret.fname = wstr_to_utf8(fullpath.data());
TRACE("Got binary: %s, %s\n", ret.path.c_str(), ret.fname.c_str());
return ret;
}
void al_print(LogLevel level, FILE *logfile, const char *fmt, ...)
{
al::vector<char> dynmsg;
@ -99,413 +59,11 @@ void al_print(LogLevel level, FILE *logfile, const char *fmt, ...)
va_end(args2);
va_end(args);
std::wstring wstr{utf8_to_wstr(str)};
if(gLogLevel >= level)
{
fputws(wstr.c_str(), logfile);
fflush(logfile);
}
OutputDebugStringW(wstr.c_str());
Aurora::Console::Logging::LogGame(str);
}
namespace {
void DirectorySearch(const char *path, const char *ext, al::vector<std::string> *const results)
{
std::string pathstr{path};
pathstr += "\\*";
pathstr += ext;
TRACE("Searching %s\n", pathstr.c_str());
std::wstring wpath{utf8_to_wstr(pathstr.c_str())};
WIN32_FIND_DATAW fdata;
HANDLE hdl{FindFirstFileW(wpath.c_str(), &fdata)};
if(hdl == INVALID_HANDLE_VALUE) return;
const auto base = results->size();
do {
results->emplace_back();
std::string &str = results->back();
str = path;
str += '\\';
str += wstr_to_utf8(fdata.cFileName);
} while(FindNextFileW(hdl, &fdata));
FindClose(hdl);
const al::span<std::string> newlist{results->data()+base, results->size()-base};
std::sort(newlist.begin(), newlist.end());
for(const auto &name : newlist)
TRACE(" got %s\n", name.c_str());
}
} // namespace
al::vector<std::string> SearchDataFiles(const char *ext, const char *subdir)
{
auto is_slash = [](int c) noexcept -> int { return (c == '\\' || c == '/'); };
static std::mutex search_lock;
std::lock_guard<std::mutex> _{search_lock};
/* If the path is absolute, use it directly. */
al::vector<std::string> results;
if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2]))
{
std::string path{subdir};
std::replace(path.begin(), path.end(), '/', '\\');
DirectorySearch(path.c_str(), ext, &results);
return results;
}
if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\')
{
DirectorySearch(subdir, ext, &results);
return results;
}
std::string path;
/* Search the app-local directory. */
if(auto localpath = al::getenv(L"ALSOFT_LOCAL_PATH"))
{
path = wstr_to_utf8(localpath->c_str());
if(is_slash(path.back()))
path.pop_back();
}
else if(WCHAR *cwdbuf{_wgetcwd(nullptr, 0)})
{
path = wstr_to_utf8(cwdbuf);
if(is_slash(path.back()))
path.pop_back();
free(cwdbuf);
}
else
path = ".";
std::replace(path.begin(), path.end(), '/', '\\');
DirectorySearch(path.c_str(), ext, &results);
/* Search the local and global data dirs. */
static const int ids[2]{ CSIDL_APPDATA, CSIDL_COMMON_APPDATA };
for(int id : ids)
{
WCHAR buffer[MAX_PATH];
if(SHGetSpecialFolderPathW(nullptr, buffer, id, FALSE) == FALSE)
continue;
path = wstr_to_utf8(buffer);
if(!is_slash(path.back()))
path += '\\';
path += subdir;
std::replace(path.begin(), path.end(), '/', '\\');
DirectorySearch(path.c_str(), ext, &results);
}
return results;
}
void SetRTPriority(void)
{
if(RTPrioLevel > 0)
{
if(!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
ERR("Failed to set priority level for thread\n");
}
}
#else
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
#ifdef __FreeBSD__
#include <sys/sysctl.h>
#endif
#ifdef __HAIKU__
#include <FindDirectory.h>
#endif
#ifdef __ANDROID__
#include <android/log.h>
#endif
#ifdef HAVE_PROC_PIDPATH
#include <libproc.h>
#endif
#if defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__)
#include <pthread.h>
#include <sched.h>
#endif
const PathNamePair &GetProcBinary()
{
static PathNamePair ret;
if(!ret.fname.empty() || !ret.path.empty())
return ret;
al::vector<char> pathname;
#ifdef __FreeBSD__
size_t pathlen;
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
if(sysctl(mib, 4, nullptr, &pathlen, nullptr, 0) == -1)
WARN("Failed to sysctl kern.proc.pathname: %s\n", strerror(errno));
else
{
pathname.resize(pathlen + 1);
sysctl(mib, 4, pathname.data(), &pathlen, nullptr, 0);
pathname.resize(pathlen);
}
#endif
#ifdef HAVE_PROC_PIDPATH
if(pathname.empty())
{
char procpath[PROC_PIDPATHINFO_MAXSIZE]{};
const pid_t pid{getpid()};
if(proc_pidpath(pid, procpath, sizeof(procpath)) < 1)
ERR("proc_pidpath(%d, ...) failed: %s\n", pid, strerror(errno));
else
pathname.insert(pathname.end(), procpath, procpath+strlen(procpath));
}
#endif
#ifdef __HAIKU__
char procpath[PATH_MAX];
if(find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, procpath, sizeof(procpath)) == B_OK)
{
pathname.insert(pathname.end(), procpath, procpath+strlen(procpath));
}
#endif
if(pathname.empty())
{
static const char SelfLinkNames[][32]{
"/proc/self/exe",
"/proc/self/file",
"/proc/curproc/exe",
"/proc/curproc/file"
};
pathname.resize(256);
const char *selfname{};
ssize_t len{};
for(const char *name : SelfLinkNames)
{
selfname = name;
len = readlink(selfname, pathname.data(), pathname.size());
if(len >= 0 || errno != ENOENT) break;
}
while(len > 0 && static_cast<size_t>(len) == pathname.size())
{
pathname.resize(pathname.size() << 1);
len = readlink(selfname, pathname.data(), pathname.size());
}
if(len <= 0)
{
WARN("Failed to readlink %s: %s\n", selfname, strerror(errno));
return ret;
}
pathname.resize(static_cast<size_t>(len));
}
while(!pathname.empty() && pathname.back() == 0)
pathname.pop_back();
auto sep = std::find(pathname.crbegin(), pathname.crend(), '/');
if(sep != pathname.crend())
{
ret.path = std::string(pathname.cbegin(), sep.base()-1);
ret.fname = std::string(sep.base(), pathname.cend());
}
else
ret.fname = std::string(pathname.cbegin(), pathname.cend());
TRACE("Got binary: %s, %s\n", ret.path.c_str(), ret.fname.c_str());
return ret;
}
void al_print(LogLevel level, FILE *logfile, const char *fmt, ...)
{
al::vector<char> dynmsg;
char stcmsg[256];
char *str{stcmsg};
va_list args, args2;
va_start(args, fmt);
va_copy(args2, args);
int msglen{std::vsnprintf(str, sizeof(stcmsg), fmt, args)};
if UNLIKELY(msglen >= 0 && static_cast<size_t>(msglen) >= sizeof(stcmsg))
{
dynmsg.resize(static_cast<size_t>(msglen) + 1u);
str = dynmsg.data();
msglen = std::vsnprintf(str, dynmsg.size(), fmt, args2);
}
va_end(args2);
va_end(args);
if(gLogLevel >= level)
{
fputs(str, logfile);
fflush(logfile);
}
#ifdef __ANDROID__
auto android_severity = [](LogLevel l) noexcept
{
switch(l)
{
case LogLevel::Trace: return ANDROID_LOG_DEBUG;
case LogLevel::Warning: return ANDROID_LOG_WARN;
case LogLevel::Error: return ANDROID_LOG_ERROR;
/* Should not happen. */
case LogLevel::Disable:
break;
}
return ANDROID_LOG_ERROR;
};
__android_log_print(android_severity(level), "openal", "%s", str);
#endif
}
namespace {
void DirectorySearch(const char *path, const char *ext, al::vector<std::string> *const results)
{
TRACE("Searching %s for *%s\n", path, ext);
DIR *dir{opendir(path)};
if(!dir) return;
const auto base = results->size();
const size_t extlen{strlen(ext)};
while(struct dirent *dirent{readdir(dir)})
{
if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
continue;
const size_t len{strlen(dirent->d_name)};
if(len <= extlen) continue;
if(al::strcasecmp(dirent->d_name+len-extlen, ext) != 0)
continue;
results->emplace_back();
std::string &str = results->back();
str = path;
if(str.back() != '/')
str.push_back('/');
str += dirent->d_name;
}
closedir(dir);
const al::span<std::string> newlist{results->data()+base, results->size()-base};
std::sort(newlist.begin(), newlist.end());
for(const auto &name : newlist)
TRACE(" got %s\n", name.c_str());
}
} // namespace
al::vector<std::string> SearchDataFiles(const char *ext, const char *subdir)
{
static std::mutex search_lock;
std::lock_guard<std::mutex> _{search_lock};
al::vector<std::string> results;
if(subdir[0] == '/')
{
DirectorySearch(subdir, ext, &results);
return results;
}
/* Search the app-local directory. */
if(auto localpath = al::getenv("ALSOFT_LOCAL_PATH"))
DirectorySearch(localpath->c_str(), ext, &results);
else
{
al::vector<char> cwdbuf(256);
while(!getcwd(cwdbuf.data(), cwdbuf.size()))
{
if(errno != ERANGE)
{
cwdbuf.clear();
break;
}
cwdbuf.resize(cwdbuf.size() << 1);
}
if(cwdbuf.empty())
DirectorySearch(".", ext, &results);
else
{
DirectorySearch(cwdbuf.data(), ext, &results);
cwdbuf.clear();
}
}
// Search local data dir
if(auto datapath = al::getenv("XDG_DATA_HOME"))
{
std::string &path = *datapath;
if(path.back() != '/')
path += '/';
path += subdir;
DirectorySearch(path.c_str(), ext, &results);
}
else if(auto homepath = al::getenv("HOME"))
{
std::string &path = *homepath;
if(path.back() == '/')
path.pop_back();
path += "/.local/share/";
path += subdir;
DirectorySearch(path.c_str(), ext, &results);
}
// Search global data dirs
std::string datadirs{al::getenv("XDG_DATA_DIRS").value_or("/usr/local/share/:/usr/share/")};
size_t curpos{0u};
while(curpos < datadirs.size())
{
size_t nextpos{datadirs.find(':', curpos)};
std::string path{(nextpos != std::string::npos) ?
datadirs.substr(curpos, nextpos++ - curpos) : datadirs.substr(curpos)};
curpos = nextpos;
if(path.empty()) continue;
if(path.back() != '/')
path += '/';
path += subdir;
DirectorySearch(path.c_str(), ext, &results);
}
return results;
}
void SetRTPriority()
{
#if defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__)
if(RTPrioLevel > 0)
{
struct sched_param param{};
/* Use the minimum real-time priority possible for now (on Linux this
* should be 1 for SCHED_RR).
*/
param.sched_priority = sched_get_priority_min(SCHED_RR);
int err;
#ifdef SCHED_RESET_ON_FORK
err = pthread_setschedparam(pthread_self(), SCHED_RR|SCHED_RESET_ON_FORK, &param);
if(err == EINVAL)
#endif
err = pthread_setschedparam(pthread_self(), SCHED_RR, &param);
if(err != 0)
ERR("Failed to set real-time priority for thread: %s (%d)\n", std::strerror(err), err);
}
#else
/* Real-time priority not available */
if(RTPrioLevel > 0)
ERR("Cannot set priority level for thread\n");
#endif
}
#endif
}

View File

@ -1121,94 +1121,7 @@ bool checkName(const std::string &name)
return std::find_if(enum_names.cbegin(), enum_names.cend(), match_name) != enum_names.cend();
}
void AddFileEntry(const std::string &filename)
{
/* Check if this file has already been enumerated. */
auto enum_iter = std::find_if(EnumeratedHrtfs.cbegin(), EnumeratedHrtfs.cend(),
[&filename](const HrtfEntry &entry) -> bool
{ return entry.mFilename == filename; });
if(enum_iter != EnumeratedHrtfs.cend())
{
TRACE("Skipping duplicate file entry %s\n", filename.c_str());
return;
}
/* TODO: Get a human-readable name from the HRTF data (possibly coming in a
* format update). */
size_t namepos = filename.find_last_of('/')+1;
if(!namepos) namepos = filename.find_last_of('\\')+1;
size_t extpos{filename.find_last_of('.')};
if(extpos <= namepos) extpos = std::string::npos;
const std::string basename{(extpos == std::string::npos) ?
filename.substr(namepos) : filename.substr(namepos, extpos-namepos)};
std::string newname{basename};
int count{1};
while(checkName(newname))
{
newname = basename;
newname += " #";
newname += std::to_string(++count);
}
EnumeratedHrtfs.emplace_back(HrtfEntry{newname, filename});
const HrtfEntry &entry = EnumeratedHrtfs.back();
TRACE("Adding file entry \"%s\"\n", entry.mFilename.c_str());
}
/* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer
* for input instead of opening the given filename.
*/
void AddBuiltInEntry(const std::string &dispname, ALuint residx)
{
const std::string filename{'!'+std::to_string(residx)+'_'+dispname};
auto enum_iter = std::find_if(EnumeratedHrtfs.cbegin(), EnumeratedHrtfs.cend(),
[&filename](const HrtfEntry &entry) -> bool
{ return entry.mFilename == filename; });
if(enum_iter != EnumeratedHrtfs.cend())
{
TRACE("Skipping duplicate file entry %s\n", filename.c_str());
return;
}
/* TODO: Get a human-readable name from the HRTF data (possibly coming in a
* format update). */
std::string newname{dispname};
int count{1};
while(checkName(newname))
{
newname = dispname;
newname += " #";
newname += std::to_string(++count);
}
EnumeratedHrtfs.emplace_back(HrtfEntry{newname, filename});
const HrtfEntry &entry = EnumeratedHrtfs.back();
TRACE("Adding built-in entry \"%s\"\n", entry.mFilename.c_str());
}
#define IDR_DEFAULT_HRTF_MHR 1
#ifndef ALSOFT_EMBED_HRTF_DATA
al::span<const char> GetResource(int /*name*/)
{ return {}; }
#else
#include "hrtf_default.h"
al::span<const char> GetResource(int name)
{
if(name == IDR_DEFAULT_HRTF_MHR)
return {reinterpret_cast<const char*>(hrtf_default), sizeof(hrtf_default)};
return {};
}
#endif
} // namespace
@ -1218,50 +1131,23 @@ al::vector<std::string> EnumerateHrtf(const char *devname)
std::lock_guard<std::mutex> _{EnumeratedHrtfLock};
EnumeratedHrtfs.clear();
bool usedefaults{true};
if(auto pathopt = ConfigValueStr(devname, nullptr, "hrtf-paths"))
{
const char *pathlist{pathopt->c_str()};
while(pathlist && *pathlist)
AuString pathA;
Aurora::FS::GetSystemDomain("OpenAL", pathA);
AuList<AuString> files;
Aurora::FS::FilesInDirectory(pathA, files);
for (const auto& file : files)
{
const char *next, *end;
if (!EndsWith(file, ".mhr")) continue;
auto shortName = file.substr(0, file.size() - 4);
while(isspace(*pathlist) || *pathlist == ',')
pathlist++;
if(*pathlist == '\0')
continue;
next = strchr(pathlist, ',');
if(next)
end = next++;
else
{
end = pathlist + strlen(pathlist);
usedefaults = false;
}
while(end != pathlist && isspace(*(end-1)))
--end;
if(end != pathlist)
{
const std::string pname{pathlist, end};
for(const auto &fname : SearchDataFiles(".mhr", pname.c_str()))
AddFileEntry(fname);
}
pathlist = next;
EnumeratedHrtfs.emplace_back(HrtfEntry{ shortName, pathA + file });
}
}
if(usedefaults)
{
for(const auto &fname : SearchDataFiles(".mhr", "openal/hrtf"))
AddFileEntry(fname);
if(!GetResource(IDR_DEFAULT_HRTF_MHR).empty())
AddBuiltInEntry("Built-In HRTF", IDR_DEFAULT_HRTF_MHR);
}
al::vector<std::string> list;
list.reserve(EnumeratedHrtfs.size());
for(auto &entry : EnumeratedHrtfs)
@ -1307,18 +1193,7 @@ HrtfStorePtr GetLoadedHrtf(const std::string &name, const char *devname, const A
std::unique_ptr<std::istream> stream;
int residx{};
char ch{};
if(sscanf(fname.c_str(), "!%d%c", &residx, &ch) == 2 && ch == '_')
{
TRACE("Loading %s...\n", fname.c_str());
al::span<const char> res{GetResource(residx)};
if(res.empty())
{
ERR("Could not get resource %u, %s\n", residx, name.c_str());
return nullptr;
}
stream = std::make_unique<idstream>(res.begin(), res.end());
}
else
{
TRACE("Loading %s...\n", fname.c_str());
auto fstr = std::make_unique<al::ifstream>(fname.c_str(), std::ios::binary);

View File

@ -1,5 +1,4 @@
#ifndef LOGGING_H
#define LOGGING_H
#pragma once
#include <stdio.h>
@ -16,32 +15,12 @@ extern LogLevel gLogLevel;
extern FILE *gLogFile;
void al_print(LogLevel level, FILE *logfile, const char *fmt, ...);
#if !defined(_WIN32) && !defined(__ANDROID__)
#define TRACE(...) do { \
if UNLIKELY(gLogLevel >= LogLevel::Trace) \
fprintf(gLogFile, "[ALSOFT] (II) " __VA_ARGS__); \
} while(0)
#define WARN(...) do { \
if UNLIKELY(gLogLevel >= LogLevel::Warning) \
fprintf(gLogFile, "[ALSOFT] (WW) " __VA_ARGS__); \
} while(0)
#define ERR(...) do { \
if UNLIKELY(gLogLevel >= LogLevel::Error) \
fprintf(gLogFile, "[ALSOFT] (EE) " __VA_ARGS__); \
} while(0)
#if defined(DEBUG)
#define TRACE(...) Aurora::Console::Logging::LogDbg("[ALSOFT] (II) " __VA_ARGS__)
#else
[[gnu::format(printf,3,4)]] void al_print(LogLevel level, FILE *logfile, const char *fmt, ...);
#define TRACE(...) al_print(LogLevel::Trace, gLogFile, "[ALSOFT] (II) " __VA_ARGS__)
#define WARN(...) al_print(LogLevel::Warning, gLogFile, "[ALSOFT] (WW) " __VA_ARGS__)
#define ERR(...) al_print(LogLevel::Error, gLogFile, "[ALSOFT] (EE) " __VA_ARGS__)
#define TRACE(...)
#endif
#endif /* LOGGING_H */
#define WARN(...) Aurora::Console::Logging::LogWarn("[ALSOFT] (WW) " __VA_ARGS__)
#define ERR(...) Aurora::Console::Logging::LogWarn("[ALSOFT] (EE) " __VA_ARGS__)

View File

@ -1,64 +1,21 @@
/**
* Aurora Engine allocation wrapper reimplementation for OpenAL
* Copyright (C) Reece Wilson 2021
* License: MIT
*/
#include "config.h"
#include "almalloc.h"
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <memory>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
void *al_malloc(size_t alignment, size_t size)
{
assert((alignment & (alignment-1)) == 0);
alignment = std::max(alignment, alignof(std::max_align_t));
#if defined(HAVE_STD_ALIGNED_ALLOC)
size = (size+(alignment-1))&~(alignment-1);
return std::aligned_alloc(alignment, size);
#elif defined(HAVE_POSIX_MEMALIGN)
void *ret{};
if(posix_memalign(&ret, alignment, size) == 0)
return ret;
return nullptr;
#elif defined(HAVE__ALIGNED_MALLOC)
return _aligned_malloc(size, alignment);
#else
size_t total_size{size + alignment-1 + sizeof(void*)};
void *base{std::malloc(total_size)};
if(base != nullptr)
{
void *aligned_ptr{static_cast<char*>(base) + sizeof(void*)};
total_size -= sizeof(void*);
std::align(alignment, size, aligned_ptr, total_size);
*(static_cast<void**>(aligned_ptr)-1) = base;
base = aligned_ptr;
}
return base;
#endif
return Aurora::Memory::SAlloc<void*>(size, alignment);
}
void *al_calloc(size_t alignment, size_t size)
{
void *ret{al_malloc(alignment, size)};
if(ret) std::memset(ret, 0, size);
return ret;
return Aurora::Memory::ZAlloc<void*>(size, alignment);
}
void al_free(void *ptr) noexcept
{
#if defined(HAVE_STD_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN)
std::free(ptr);
#elif defined(HAVE__ALIGNED_MALLOC)
_aligned_free(ptr);
#else
if(ptr != nullptr)
std::free(*(static_cast<void**>(ptr) - 1));
#endif
}
Aurora::Memory::Free(ptr);
}

View File

@ -13,8 +13,8 @@
#include "pragmadefs.h"
[[gnu::alloc_align(1), gnu::alloc_size(2)]] void *al_malloc(size_t alignment, size_t size);
[[gnu::alloc_align(1), gnu::alloc_size(2)]] void *al_calloc(size_t alignment, size_t size);
void *al_malloc(size_t alignment, size_t size);
void *al_calloc(size_t alignment, size_t size);
void al_free(void *ptr) noexcept;
@ -88,7 +88,7 @@ struct allocator {
template<typename U, std::size_t N>
constexpr allocator(const allocator<U,N>&) noexcept { }
[[gnu::assume_aligned(alignment), gnu::alloc_size(2)]] T *allocate(std::size_t n)
T *allocate(std::size_t n)
{
if(n > std::numeric_limits<std::size_t>::max()/sizeof(T)) throw std::bad_alloc();
if(auto p = static_cast<T*>(al_malloc(alignment, n*sizeof(T)))) return p;
@ -102,7 +102,7 @@ template<typename T, std::size_t N, typename U, std::size_t M>
bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept { return false; }
template<size_t alignment, typename T>
[[gnu::assume_aligned(alignment)]] inline T* assume_aligned(T *ptr) noexcept { return ptr; }
inline T* assume_aligned(T *ptr) noexcept { return ptr; }
/* At least VS 2015 complains that 'ptr' is unused when the given type's
* destructor is trivial (a no-op). So disable that warning for this call.

View File

@ -1,176 +1,42 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
* Aurora Engine semaphore wrapper reimplementation for OpenAL
* Copyright (C) Reece Wilson 2021
* License: MIT
*/
#include "config.h"
#include "opthelpers.h"
#include "threads.h"
#include <system_error>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <limits>
void althrd_setname(const char *name)
{
#if defined(_MSC_VER)
#define MS_VC_EXCEPTION 0x406D1388
#pragma pack(push,8)
struct {
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} info;
#pragma pack(pop)
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = ~DWORD{0};
info.dwFlags = 0;
// NO OP
}
__try {
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
namespace al
{
semaphore::semaphore(unsigned int initial)
{
_semaphore = Aurora::Threading::SemaphoreNew(initial);
}
__except(EXCEPTION_CONTINUE_EXECUTION) {
semaphore::~semaphore()
{
Aurora::Threading::SemaphoreDestroy(_semaphore);
}
#undef MS_VC_EXCEPTION
#else
(void)name;
#endif
}
namespace al {
void semaphore::post()
{
_semaphore->Unlock(1);
}
semaphore::semaphore(unsigned int initial)
{
if(initial > static_cast<unsigned int>(std::numeric_limits<int>::max()))
throw std::system_error(std::make_error_code(std::errc::value_too_large));
mSem = CreateSemaphore(nullptr, initial, std::numeric_limits<int>::max(), nullptr);
if(mSem == nullptr)
throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again));
}
void semaphore::wait() noexcept
{
_semaphore->Lock();
}
semaphore::~semaphore()
{ CloseHandle(mSem); }
void semaphore::post()
{
if UNLIKELY(!ReleaseSemaphore(static_cast<HANDLE>(mSem), 1, nullptr))
throw std::system_error(std::make_error_code(std::errc::value_too_large));
}
void semaphore::wait() noexcept
{ WaitForSingleObject(static_cast<HANDLE>(mSem), INFINITE); }
bool semaphore::try_wait() noexcept
{ return WaitForSingleObject(static_cast<HANDLE>(mSem), 0) == WAIT_OBJECT_0; }
} // namespace al
#else
#if defined(HAVE_PTHREAD_SETNAME_NP) || defined(HAVE_PTHREAD_SET_NAME_NP)
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
void althrd_setname(const char *name)
{
#if defined(HAVE_PTHREAD_SET_NAME_NP)
pthread_set_name_np(pthread_self(), name);
#elif defined(PTHREAD_SETNAME_NP_ONE_PARAM)
pthread_setname_np(name);
#elif defined(PTHREAD_SETNAME_NP_THREE_PARAMS)
pthread_setname_np(pthread_self(), "%s", (void*)name);
#else
pthread_setname_np(pthread_self(), name);
#endif
}
#else
void althrd_setname(const char*) { }
#endif
#ifdef __APPLE__
namespace al {
semaphore::semaphore(unsigned int initial)
{
mSem = dispatch_semaphore_create(initial);
if(!mSem)
throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again));
}
semaphore::~semaphore()
{ dispatch_release(mSem); }
void semaphore::post()
{ dispatch_semaphore_signal(mSem); }
void semaphore::wait() noexcept
{ dispatch_semaphore_wait(mSem, DISPATCH_TIME_FOREVER); }
bool semaphore::try_wait() noexcept
{ return dispatch_semaphore_wait(mSem, DISPATCH_TIME_NOW) == 0; }
} // namespace al
#else /* !__APPLE__ */
#include <cerrno>
namespace al {
semaphore::semaphore(unsigned int initial)
{
if(sem_init(&mSem, 0, initial) != 0)
throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again));
}
semaphore::~semaphore()
{ sem_destroy(&mSem); }
void semaphore::post()
{
if(sem_post(&mSem) != 0)
throw std::system_error(std::make_error_code(std::errc::value_too_large));
}
void semaphore::wait() noexcept
{
while(sem_wait(&mSem) == -1 && errno == EINTR) {
bool semaphore::try_wait() noexcept
{
return _semaphore->TryLock();
}
}
bool semaphore::try_wait() noexcept
{ return sem_trywait(&mSem) == 0; }
} // namespace al
#endif /* __APPLE__ */
#endif /* _WIN32 */

View File

@ -1,48 +1,28 @@
#ifndef AL_THREADS_H
#define AL_THREADS_H
#if defined(__GNUC__) && defined(__i386__)
/* force_align_arg_pointer is required for proper function arguments aligning
* when SSE code is used. Some systems (Windows, QNX) do not guarantee our
* thread functions will be properly aligned on the stack, even though GCC may
* generate code with the assumption that it is. */
#define FORCE_ALIGN __attribute__((force_align_arg_pointer))
#else
#define FORCE_ALIGN
#endif
#if defined(__APPLE__)
#include <dispatch/dispatch.h>
#elif !defined(_WIN32)
#include <semaphore.h>
#endif
/**
* OpenAL semaphore wrapper reimplementation for the Aurora Engine
* Copyright (C) Reece Wilson 2021
* License: MIT
*/
#pragma once
void althrd_setname(const char *name);
namespace al {
namespace al
{
class semaphore
{
public:
semaphore(unsigned int initial = 0);
semaphore(const semaphore&) = delete;
~semaphore();
class semaphore {
#ifdef _WIN32
using native_type = void*;
#elif defined(__APPLE__)
using native_type = dispatch_semaphore_t;
#else
using native_type = sem_t;
#endif
native_type mSem;
semaphore& operator=(const semaphore&) = delete;
public:
semaphore(unsigned int initial=0);
semaphore(const semaphore&) = delete;
~semaphore();
void post();
void wait() noexcept;
bool try_wait() noexcept;
semaphore& operator=(const semaphore&) = delete;
void post();
void wait() noexcept;
bool try_wait() noexcept;
};
} // namespace al
#endif /* AL_THREADS_H */
private:
Aurora::Threading::ISemaphore* _semaphore;
};
}

7
config/config.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#define RESTRICT
#define FORCE_ALIGN
#include <AuroraCommon.hpp>
#include <Aurora/Kernel.hpp>

4
config/version.h Normal file
View File

@ -0,0 +1,4 @@
#define ALSOFT_VERSION "1"
#define ALSOFT_VERSION_NUM "0"
#define ALSOFT_GIT_BRANCH "1"
#define ALSOFT_GIT_COMMIT_HASH "AURORA ENGINE"

View File

@ -6,19 +6,23 @@ extern "C" {
#endif
#ifndef AL_API
#if defined(AL_LIBTYPE_STATIC)
#define AL_API
#elif defined(_WIN32)
#define AL_API __declspec(dllimport)
#else
#define AL_API extern
#endif
#if defined(AL_LIBTYPE_STATIC)
#define AL_API
#elif defined(_WIN32)
#if defined(AURORA_OPENAL)
#define AL_API __declspec(dllexport)
#else
#define AL_API __declspec(dllimport)
#endif
#else
#define AL_API extern
#endif
#endif
#if defined(_WIN32)
#define AL_APIENTRY __cdecl
#define AL_APIENTRY __cdecl
#else
#define AL_APIENTRY
#define AL_APIENTRY
#endif

View File

@ -6,13 +6,17 @@ extern "C" {
#endif
#ifndef ALC_API
#if defined(AL_LIBTYPE_STATIC)
#define ALC_API
#elif defined(_WIN32)
#define ALC_API __declspec(dllimport)
#else
#define ALC_API extern
#endif
#if defined(AL_LIBTYPE_STATIC)
#define ALC_API
#elif defined(_WIN32)
#if defined(AURORA_OPENAL)
#define ALC_API __declspec(dllexport)
#else
#define ALC_API __declspec(dllimport)
#endif
#else
#define ALC_API extern
#endif
#endif
#if defined(_WIN32)