mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-12 15:14:35 +00:00
update openal
This commit is contained in:
parent
62f3b93ff9
commit
6721a6b021
287 changed files with 33851 additions and 27325 deletions
|
|
@ -31,24 +31,26 @@
|
|||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <system_error>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "albit.h"
|
||||
#include "albyte.h"
|
||||
#include "alc/alconfig.h"
|
||||
#include "almalloc.h"
|
||||
#include "alnumeric.h"
|
||||
#include "alstring.h"
|
||||
#include "althrd_setname.h"
|
||||
#include "core/device.h"
|
||||
#include "core/helpers.h"
|
||||
#include "core/logging.h"
|
||||
#include "opthelpers.h"
|
||||
#include "strutils.h"
|
||||
#include "threads.h"
|
||||
#include "vector.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
using std::chrono::seconds;
|
||||
using std::chrono::milliseconds;
|
||||
using std::chrono::nanoseconds;
|
||||
|
|
@ -56,38 +58,43 @@ using std::chrono::nanoseconds;
|
|||
using ubyte = unsigned char;
|
||||
using ushort = unsigned short;
|
||||
|
||||
constexpr char waveDevice[] = "Wave File Writer";
|
||||
struct FileDeleter {
|
||||
void operator()(gsl::owner<FILE*> f) { fclose(f); }
|
||||
};
|
||||
using FilePtr = std::unique_ptr<FILE,FileDeleter>;
|
||||
|
||||
constexpr ubyte SUBTYPE_PCM[]{
|
||||
[[nodiscard]] constexpr auto GetDeviceName() noexcept { return "Wave File Writer"sv; }
|
||||
|
||||
constexpr std::array<ubyte,16> SUBTYPE_PCM{{
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
|
||||
0x00, 0x38, 0x9b, 0x71
|
||||
};
|
||||
constexpr ubyte SUBTYPE_FLOAT[]{
|
||||
}};
|
||||
constexpr std::array<ubyte,16> SUBTYPE_FLOAT{{
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
|
||||
0x00, 0x38, 0x9b, 0x71
|
||||
};
|
||||
}};
|
||||
|
||||
constexpr ubyte SUBTYPE_BFORMAT_PCM[]{
|
||||
constexpr std::array<ubyte,16> SUBTYPE_BFORMAT_PCM{{
|
||||
0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
|
||||
0xca, 0x00, 0x00, 0x00
|
||||
};
|
||||
}};
|
||||
|
||||
constexpr ubyte SUBTYPE_BFORMAT_FLOAT[]{
|
||||
constexpr std::array<ubyte,16> SUBTYPE_BFORMAT_FLOAT{{
|
||||
0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
|
||||
0xca, 0x00, 0x00, 0x00
|
||||
};
|
||||
}};
|
||||
|
||||
void fwrite16le(ushort val, FILE *f)
|
||||
{
|
||||
ubyte data[2]{ static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff) };
|
||||
fwrite(data, 1, 2, f);
|
||||
std::array data{static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff)};
|
||||
fwrite(data.data(), 1, data.size(), f);
|
||||
}
|
||||
|
||||
void fwrite32le(uint val, FILE *f)
|
||||
{
|
||||
ubyte data[4]{ static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff),
|
||||
static_cast<ubyte>((val>>16)&0xff), static_cast<ubyte>((val>>24)&0xff) };
|
||||
fwrite(data, 1, 4, f);
|
||||
std::array data{static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff),
|
||||
static_cast<ubyte>((val>>16)&0xff), static_cast<ubyte>((val>>24)&0xff)};
|
||||
fwrite(data.data(), 1, data.size(), f);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -97,34 +104,27 @@ struct WaveBackend final : public BackendBase {
|
|||
|
||||
int mixerProc();
|
||||
|
||||
void open(const char *name) override;
|
||||
void open(std::string_view name) override;
|
||||
bool reset() override;
|
||||
void start() override;
|
||||
void stop() override;
|
||||
|
||||
FILE *mFile{nullptr};
|
||||
FilePtr mFile{nullptr};
|
||||
long mDataStart{-1};
|
||||
|
||||
al::vector<al::byte> mBuffer;
|
||||
std::vector<std::byte> mBuffer;
|
||||
|
||||
std::atomic<bool> mKillNow{true};
|
||||
std::thread mThread;
|
||||
|
||||
DEF_NEWDEL(WaveBackend)
|
||||
};
|
||||
|
||||
WaveBackend::~WaveBackend()
|
||||
{
|
||||
if(mFile)
|
||||
fclose(mFile);
|
||||
mFile = nullptr;
|
||||
}
|
||||
WaveBackend::~WaveBackend() = default;
|
||||
|
||||
int WaveBackend::mixerProc()
|
||||
{
|
||||
const milliseconds restTime{mDevice->UpdateSize*1000/mDevice->Frequency / 2};
|
||||
|
||||
althrd_setname(MIXER_THREAD_NAME);
|
||||
althrd_setname(GetMixerThreadName());
|
||||
|
||||
const size_t frameStep{mDevice->channelsFromFmt()};
|
||||
const size_t frameSize{mDevice->frameSizeFromFmt()};
|
||||
|
|
@ -155,13 +155,13 @@ int WaveBackend::mixerProc()
|
|||
|
||||
if(bytesize == 2)
|
||||
{
|
||||
const size_t len{mBuffer.size() & ~size_t{1}};
|
||||
const size_t len{mBuffer.size() & ~1_uz};
|
||||
for(size_t i{0};i < len;i+=2)
|
||||
std::swap(mBuffer[i], mBuffer[i+1]);
|
||||
}
|
||||
else if(bytesize == 4)
|
||||
{
|
||||
const size_t len{mBuffer.size() & ~size_t{3}};
|
||||
const size_t len{mBuffer.size() & ~3_uz};
|
||||
for(size_t i{0};i < len;i+=4)
|
||||
{
|
||||
std::swap(mBuffer[i ], mBuffer[i+3]);
|
||||
|
|
@ -170,8 +170,8 @@ int WaveBackend::mixerProc()
|
|||
}
|
||||
}
|
||||
|
||||
const size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile)};
|
||||
if(fs < mDevice->UpdateSize || ferror(mFile))
|
||||
const size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile.get())};
|
||||
if(fs < mDevice->UpdateSize || ferror(mFile.get()))
|
||||
{
|
||||
ERR("Error writing to file\n");
|
||||
mDevice->handleDisconnect("Failed to write playback samples");
|
||||
|
|
@ -195,32 +195,32 @@ int WaveBackend::mixerProc()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void WaveBackend::open(const char *name)
|
||||
void WaveBackend::open(std::string_view name)
|
||||
{
|
||||
auto fname = ConfigValueStr(nullptr, "wave", "file");
|
||||
auto fname = ConfigValueStr({}, "wave", "file");
|
||||
if(!fname) throw al::backend_exception{al::backend_error::NoDevice,
|
||||
"No wave output filename"};
|
||||
|
||||
if(!name)
|
||||
name = waveDevice;
|
||||
else if(strcmp(name, waveDevice) != 0)
|
||||
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
|
||||
name};
|
||||
if(name.empty())
|
||||
name = GetDeviceName();
|
||||
else if(name != GetDeviceName())
|
||||
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
|
||||
al::sizei(name), name.data()};
|
||||
|
||||
/* There's only one "device", so if it's already open, we're done. */
|
||||
if(mFile) return;
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
std::wstring wname{utf8_to_wstr(fname->c_str())};
|
||||
mFile = _wfopen(wname.c_str(), L"wb");
|
||||
std::wstring wname{utf8_to_wstr(fname.value())};
|
||||
mFile = FilePtr{_wfopen(wname.c_str(), L"wb")};
|
||||
}
|
||||
#else
|
||||
mFile = fopen(fname->c_str(), "wb");
|
||||
mFile = FilePtr{fopen(fname->c_str(), "wb")};
|
||||
#endif
|
||||
if(!mFile)
|
||||
throw al::backend_exception{al::backend_error::DeviceError, "Could not open file '%s': %s",
|
||||
fname->c_str(), strerror(errno)};
|
||||
fname->c_str(), std::generic_category().message(errno).c_str()};
|
||||
|
||||
mDevice->DeviceName = name;
|
||||
}
|
||||
|
|
@ -229,12 +229,11 @@ bool WaveBackend::reset()
|
|||
{
|
||||
uint channels{0}, bytes{0}, chanmask{0};
|
||||
bool isbformat{false};
|
||||
size_t val;
|
||||
|
||||
fseek(mFile, 0, SEEK_SET);
|
||||
clearerr(mFile);
|
||||
fseek(mFile.get(), 0, SEEK_SET);
|
||||
clearerr(mFile.get());
|
||||
|
||||
if(GetConfigValueBool(nullptr, "wave", "bformat", false))
|
||||
if(GetConfigValueBool({}, "wave", "bformat", false))
|
||||
{
|
||||
mDevice->FmtChans = DevFmtAmbi3D;
|
||||
mDevice->mAmbiOrder = 1;
|
||||
|
|
@ -265,6 +264,9 @@ bool WaveBackend::reset()
|
|||
case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break;
|
||||
case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break;
|
||||
case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break;
|
||||
case DevFmtX7144:
|
||||
mDevice->FmtChans = DevFmtX714;
|
||||
[[fallthrough]];
|
||||
case DevFmtX714:
|
||||
chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400 | 0x1000 | 0x4000
|
||||
| 0x8000 | 0x20000;
|
||||
|
|
@ -273,7 +275,7 @@ bool WaveBackend::reset()
|
|||
case DevFmtX3D71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break;
|
||||
case DevFmtAmbi3D:
|
||||
/* .amb output requires FuMa */
|
||||
mDevice->mAmbiOrder = minu(mDevice->mAmbiOrder, 3);
|
||||
mDevice->mAmbiOrder = std::min(mDevice->mAmbiOrder, 3u);
|
||||
mDevice->mAmbiLayout = DevAmbiLayout::FuMa;
|
||||
mDevice->mAmbiScale = DevAmbiScaling::FuMa;
|
||||
isbformat = true;
|
||||
|
|
@ -283,49 +285,48 @@ bool WaveBackend::reset()
|
|||
bytes = mDevice->bytesFromFmt();
|
||||
channels = mDevice->channelsFromFmt();
|
||||
|
||||
rewind(mFile);
|
||||
rewind(mFile.get());
|
||||
|
||||
fputs("RIFF", mFile);
|
||||
fwrite32le(0xFFFFFFFF, mFile); // 'RIFF' header len; filled in at close
|
||||
fputs("RIFF", mFile.get());
|
||||
fwrite32le(0xFFFFFFFF, mFile.get()); // 'RIFF' header len; filled in at close
|
||||
|
||||
fputs("WAVE", mFile);
|
||||
fputs("WAVE", mFile.get());
|
||||
|
||||
fputs("fmt ", mFile);
|
||||
fwrite32le(40, mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE
|
||||
fputs("fmt ", mFile.get());
|
||||
fwrite32le(40, mFile.get()); // 'fmt ' header len; 40 bytes for EXTENSIBLE
|
||||
|
||||
// 16-bit val, format type id (extensible: 0xFFFE)
|
||||
fwrite16le(0xFFFE, mFile);
|
||||
fwrite16le(0xFFFE, mFile.get());
|
||||
// 16-bit val, channel count
|
||||
fwrite16le(static_cast<ushort>(channels), mFile);
|
||||
fwrite16le(static_cast<ushort>(channels), mFile.get());
|
||||
// 32-bit val, frequency
|
||||
fwrite32le(mDevice->Frequency, mFile);
|
||||
fwrite32le(mDevice->Frequency, mFile.get());
|
||||
// 32-bit val, bytes per second
|
||||
fwrite32le(mDevice->Frequency * channels * bytes, mFile);
|
||||
fwrite32le(mDevice->Frequency * channels * bytes, mFile.get());
|
||||
// 16-bit val, frame size
|
||||
fwrite16le(static_cast<ushort>(channels * bytes), mFile);
|
||||
fwrite16le(static_cast<ushort>(channels * bytes), mFile.get());
|
||||
// 16-bit val, bits per sample
|
||||
fwrite16le(static_cast<ushort>(bytes * 8), mFile);
|
||||
fwrite16le(static_cast<ushort>(bytes * 8), mFile.get());
|
||||
// 16-bit val, extra byte count
|
||||
fwrite16le(22, mFile);
|
||||
fwrite16le(22, mFile.get());
|
||||
// 16-bit val, valid bits per sample
|
||||
fwrite16le(static_cast<ushort>(bytes * 8), mFile);
|
||||
fwrite16le(static_cast<ushort>(bytes * 8), mFile.get());
|
||||
// 32-bit val, channel mask
|
||||
fwrite32le(chanmask, mFile);
|
||||
fwrite32le(chanmask, mFile.get());
|
||||
// 16 byte GUID, sub-type format
|
||||
val = fwrite((mDevice->FmtType == DevFmtFloat) ?
|
||||
(isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) :
|
||||
(isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, mFile);
|
||||
(void)val;
|
||||
std::ignore = fwrite((mDevice->FmtType == DevFmtFloat) ?
|
||||
(isbformat ? SUBTYPE_BFORMAT_FLOAT.data() : SUBTYPE_FLOAT.data()) :
|
||||
(isbformat ? SUBTYPE_BFORMAT_PCM.data() : SUBTYPE_PCM.data()), 1, 16, mFile.get());
|
||||
|
||||
fputs("data", mFile);
|
||||
fwrite32le(0xFFFFFFFF, mFile); // 'data' header len; filled in at close
|
||||
fputs("data", mFile.get());
|
||||
fwrite32le(0xFFFFFFFF, mFile.get()); // 'data' header len; filled in at close
|
||||
|
||||
if(ferror(mFile))
|
||||
if(ferror(mFile.get()))
|
||||
{
|
||||
ERR("Error writing header: %s\n", strerror(errno));
|
||||
ERR("Error writing header: %s\n", std::generic_category().message(errno).c_str());
|
||||
return false;
|
||||
}
|
||||
mDataStart = ftell(mFile);
|
||||
mDataStart = ftell(mFile.get());
|
||||
|
||||
setDefaultWFXChannelOrder();
|
||||
|
||||
|
|
@ -337,7 +338,7 @@ bool WaveBackend::reset()
|
|||
|
||||
void WaveBackend::start()
|
||||
{
|
||||
if(mDataStart > 0 && fseek(mFile, 0, SEEK_END) != 0)
|
||||
if(mDataStart > 0 && fseek(mFile.get(), 0, SEEK_END) != 0)
|
||||
WARN("Failed to seek on output file\n");
|
||||
try {
|
||||
mKillNow.store(false, std::memory_order_release);
|
||||
|
|
@ -357,14 +358,14 @@ void WaveBackend::stop()
|
|||
|
||||
if(mDataStart > 0)
|
||||
{
|
||||
long size{ftell(mFile)};
|
||||
long size{ftell(mFile.get())};
|
||||
if(size > 0)
|
||||
{
|
||||
long dataLen{size - mDataStart};
|
||||
if(fseek(mFile, 4, SEEK_SET) == 0)
|
||||
fwrite32le(static_cast<uint>(size-8), mFile); // 'WAVE' header len
|
||||
if(fseek(mFile, mDataStart-4, SEEK_SET) == 0)
|
||||
fwrite32le(static_cast<uint>(dataLen), mFile); // 'data' header len
|
||||
if(fseek(mFile.get(), 4, SEEK_SET) == 0)
|
||||
fwrite32le(static_cast<uint>(size-8), mFile.get()); // 'WAVE' header len
|
||||
if(fseek(mFile.get(), mDataStart-4, SEEK_SET) == 0)
|
||||
fwrite32le(static_cast<uint>(dataLen), mFile.get()); // 'data' header len
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -378,19 +379,16 @@ bool WaveBackendFactory::init()
|
|||
bool WaveBackendFactory::querySupport(BackendType type)
|
||||
{ return type == BackendType::Playback; }
|
||||
|
||||
std::string WaveBackendFactory::probe(BackendType type)
|
||||
auto WaveBackendFactory::enumerate(BackendType type) -> std::vector<std::string>
|
||||
{
|
||||
std::string outnames;
|
||||
switch(type)
|
||||
{
|
||||
case BackendType::Playback:
|
||||
/* Includes null char. */
|
||||
outnames.append(waveDevice, sizeof(waveDevice));
|
||||
break;
|
||||
return std::vector{std::string{GetDeviceName()}};
|
||||
case BackendType::Capture:
|
||||
break;
|
||||
}
|
||||
return outnames;
|
||||
return {};
|
||||
}
|
||||
|
||||
BackendPtr WaveBackendFactory::createBackend(DeviceBase *device, BackendType type)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue