aboutsummaryrefslogtreecommitdiffstats
path: root/alc/backends/wave.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'alc/backends/wave.cpp')
-rw-r--r--alc/backends/wave.cpp239
1 files changed, 122 insertions, 117 deletions
diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp
index 7bcc3436..1b40640c 100644
--- a/alc/backends/wave.cpp
+++ b/alc/backends/wave.cpp
@@ -20,7 +20,7 @@
#include "config.h"
-#include "backends/wave.h"
+#include "wave.h"
#include <algorithm>
#include <atomic>
@@ -33,18 +33,15 @@
#include <functional>
#include <thread>
-#include "AL/al.h"
-
+#include "albit.h"
#include "albyte.h"
-#include "alcmain.h"
-#include "alconfig.h"
-#include "alexcpt.h"
+#include "alc/alconfig.h"
#include "almalloc.h"
#include "alnumeric.h"
-#include "alu.h"
-#include "compat.h"
-#include "endiantest.h"
-#include "logging.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"
@@ -56,50 +53,53 @@ using std::chrono::seconds;
using std::chrono::milliseconds;
using std::chrono::nanoseconds;
-constexpr ALCchar waveDevice[] = "Wave File Writer";
+using ubyte = unsigned char;
+using ushort = unsigned short;
+
+constexpr char waveDevice[] = "Wave File Writer";
-constexpr ALubyte SUBTYPE_PCM[]{
+constexpr ubyte SUBTYPE_PCM[]{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
0x00, 0x38, 0x9b, 0x71
};
-constexpr ALubyte SUBTYPE_FLOAT[]{
+constexpr ubyte SUBTYPE_FLOAT[]{
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
0x00, 0x38, 0x9b, 0x71
};
-constexpr ALubyte SUBTYPE_BFORMAT_PCM[]{
+constexpr ubyte SUBTYPE_BFORMAT_PCM[]{
0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
0xca, 0x00, 0x00, 0x00
};
-constexpr ALubyte SUBTYPE_BFORMAT_FLOAT[]{
+constexpr ubyte SUBTYPE_BFORMAT_FLOAT[]{
0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
0xca, 0x00, 0x00, 0x00
};
-void fwrite16le(ALushort val, FILE *f)
+void fwrite16le(ushort val, FILE *f)
{
- ALubyte data[2]{ static_cast<ALubyte>(val&0xff), static_cast<ALubyte>((val>>8)&0xff) };
+ ubyte data[2]{ static_cast<ubyte>(val&0xff), static_cast<ubyte>((val>>8)&0xff) };
fwrite(data, 1, 2, f);
}
-void fwrite32le(ALuint val, FILE *f)
+void fwrite32le(uint val, FILE *f)
{
- ALubyte data[4]{ static_cast<ALubyte>(val&0xff), static_cast<ALubyte>((val>>8)&0xff),
- static_cast<ALubyte>((val>>16)&0xff), static_cast<ALubyte>((val>>24)&0xff) };
+ 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);
}
struct WaveBackend final : public BackendBase {
- WaveBackend(ALCdevice *device) noexcept : BackendBase{device} { }
+ WaveBackend(DeviceBase *device) noexcept : BackendBase{device} { }
~WaveBackend() override;
int mixerProc();
- void open(const ALCchar *name) override;
+ void open(const char *name) override;
bool reset() override;
- bool start() override;
+ void start() override;
void stop() override;
FILE *mFile{nullptr};
@@ -126,12 +126,13 @@ int WaveBackend::mixerProc()
althrd_setname(MIXER_THREAD_NAME);
- const ALuint frameSize{mDevice->frameSizeFromFmt()};
+ const size_t frameStep{mDevice->channelsFromFmt()};
+ const size_t frameSize{mDevice->frameSizeFromFmt()};
int64_t done{0};
auto start = std::chrono::steady_clock::now();
- while(!mKillNow.load(std::memory_order_acquire) &&
- mDevice->Connected.load(std::memory_order_acquire))
+ while(!mKillNow.load(std::memory_order_acquire)
+ && mDevice->Connected.load(std::memory_order_acquire))
{
auto now = std::chrono::steady_clock::now();
@@ -145,45 +146,35 @@ int WaveBackend::mixerProc()
}
while(avail-done >= mDevice->UpdateSize)
{
- {
- std::lock_guard<WaveBackend> _{*this};
- aluMixData(mDevice, mBuffer.data(), mDevice->UpdateSize);
- }
+ mDevice->renderSamples(mBuffer.data(), mDevice->UpdateSize, frameStep);
done += mDevice->UpdateSize;
- if(!IS_LITTLE_ENDIAN)
+ if(al::endian::native != al::endian::little)
{
- const ALuint bytesize{mDevice->bytesFromFmt()};
+ const uint bytesize{mDevice->bytesFromFmt()};
if(bytesize == 2)
{
- ALushort *samples = reinterpret_cast<ALushort*>(mBuffer.data());
- const size_t len{mBuffer.size() / 2};
- for(size_t i{0};i < len;i++)
- {
- const ALushort samp{samples[i]};
- samples[i] = static_cast<ALushort>((samp>>8) | (samp<<8));
- }
+ const size_t len{mBuffer.size() & ~size_t{1}};
+ for(size_t i{0};i < len;i+=2)
+ std::swap(mBuffer[i], mBuffer[i+1]);
}
else if(bytesize == 4)
{
- ALuint *samples = reinterpret_cast<ALuint*>(mBuffer.data());
- const size_t len{mBuffer.size() / 4};
- for(size_t i{0};i < len;i++)
+ const size_t len{mBuffer.size() & ~size_t{3}};
+ for(size_t i{0};i < len;i+=4)
{
- const ALuint samp{samples[i]};
- samples[i] = (samp>>24) | ((samp>>8)&0x0000ff00) |
- ((samp<<8)&0x00ff0000) | (samp<<24);
+ std::swap(mBuffer[i ], mBuffer[i+3]);
+ std::swap(mBuffer[i+1], mBuffer[i+2]);
}
}
}
- size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile)};
- (void)fs;
- if(ferror(mFile))
+ const size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile)};
+ if(fs < mDevice->UpdateSize || ferror(mFile))
{
ERR("Error writing to file\n");
- aluHandleDisconnect(mDevice, "Failed to write playback samples");
+ mDevice->handleDisconnect("Failed to write playback samples");
break;
}
}
@@ -196,49 +187,54 @@ int WaveBackend::mixerProc()
if(done >= mDevice->Frequency)
{
seconds s{done/mDevice->Frequency};
+ done %= mDevice->Frequency;
start += s;
- done -= mDevice->Frequency*s.count();
}
}
return 0;
}
-void WaveBackend::open(const ALCchar *name)
+void WaveBackend::open(const char *name)
{
- const char *fname{GetConfigValue(nullptr, "wave", "file", "")};
- if(!fname[0]) throw al::backend_exception{ALC_INVALID_VALUE, "No wave output filename"};
+ auto fname = ConfigValueStr(nullptr, "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{ALC_INVALID_VALUE, "Device name \"%s\" not found", name};
+ throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
+ name};
+
+ /* 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);
+ std::wstring wname{utf8_to_wstr(fname->c_str())};
mFile = _wfopen(wname.c_str(), L"wb");
}
#else
- mFile = fopen(fname, "wb");
+ mFile = fopen(fname->c_str(), "wb");
#endif
if(!mFile)
- throw al::backend_exception{ALC_INVALID_VALUE, "Could not open file '%s': %s", fname,
- strerror(errno)};
+ throw al::backend_exception{al::backend_error::DeviceError, "Could not open file '%s': %s",
+ fname->c_str(), strerror(errno)};
mDevice->DeviceName = name;
}
bool WaveBackend::reset()
{
- ALuint channels=0, bytes=0, chanmask=0;
- int isbformat = 0;
+ uint channels{0}, bytes{0}, chanmask{0};
+ bool isbformat{false};
size_t val;
fseek(mFile, 0, SEEK_SET);
clearerr(mFile);
- if(GetConfigValueBool(nullptr, "wave", "bformat", 0))
+ if(GetConfigValueBool(nullptr, "wave", "bformat", false))
{
mDevice->FmtChans = DevFmtAmbi3D;
mDevice->mAmbiOrder = 1;
@@ -246,38 +242,43 @@ bool WaveBackend::reset()
switch(mDevice->FmtType)
{
- case DevFmtByte:
- mDevice->FmtType = DevFmtUByte;
- break;
- case DevFmtUShort:
- mDevice->FmtType = DevFmtShort;
- break;
- case DevFmtUInt:
- mDevice->FmtType = DevFmtInt;
- break;
- case DevFmtUByte:
- case DevFmtShort:
- case DevFmtInt:
- case DevFmtFloat:
- break;
+ case DevFmtByte:
+ mDevice->FmtType = DevFmtUByte;
+ break;
+ case DevFmtUShort:
+ mDevice->FmtType = DevFmtShort;
+ break;
+ case DevFmtUInt:
+ mDevice->FmtType = DevFmtInt;
+ break;
+ case DevFmtUByte:
+ case DevFmtShort:
+ case DevFmtInt:
+ case DevFmtFloat:
+ break;
}
switch(mDevice->FmtChans)
{
- case DevFmtMono: chanmask = 0x04; break;
- case DevFmtStereo: chanmask = 0x01 | 0x02; break;
- case DevFmtQuad: chanmask = 0x01 | 0x02 | 0x10 | 0x20; break;
- case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break;
- case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; 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 DevFmtAmbi3D:
- /* .amb output requires FuMa */
- mDevice->mAmbiOrder = minu(mDevice->mAmbiOrder, 3);
- mDevice->mAmbiLayout = AmbiLayout::FuMa;
- mDevice->mAmbiScale = AmbiNorm::FuMa;
- isbformat = 1;
- chanmask = 0;
- break;
+ case DevFmtMono: chanmask = 0x04; break;
+ case DevFmtStereo: chanmask = 0x01 | 0x02; break;
+ case DevFmtQuad: chanmask = 0x01 | 0x02 | 0x10 | 0x20; break;
+ 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 DevFmtX714:
+ chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400 | 0x1000 | 0x4000
+ | 0x8000 | 0x20000;
+ break;
+ /* NOTE: Same as 7.1. */
+ 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->mAmbiLayout = DevAmbiLayout::FuMa;
+ mDevice->mAmbiScale = DevAmbiScaling::FuMa;
+ isbformat = true;
+ chanmask = 0;
+ break;
}
bytes = mDevice->bytesFromFmt();
channels = mDevice->channelsFromFmt();
@@ -295,19 +296,19 @@ bool WaveBackend::reset()
// 16-bit val, format type id (extensible: 0xFFFE)
fwrite16le(0xFFFE, mFile);
// 16-bit val, channel count
- fwrite16le(static_cast<ALushort>(channels), mFile);
+ fwrite16le(static_cast<ushort>(channels), mFile);
// 32-bit val, frequency
fwrite32le(mDevice->Frequency, mFile);
// 32-bit val, bytes per second
fwrite32le(mDevice->Frequency * channels * bytes, mFile);
// 16-bit val, frame size
- fwrite16le(static_cast<ALushort>(channels * bytes), mFile);
+ fwrite16le(static_cast<ushort>(channels * bytes), mFile);
// 16-bit val, bits per sample
- fwrite16le(static_cast<ALushort>(bytes * 8), mFile);
+ fwrite16le(static_cast<ushort>(bytes * 8), mFile);
// 16-bit val, extra byte count
fwrite16le(22, mFile);
// 16-bit val, valid bits per sample
- fwrite16le(static_cast<ALushort>(bytes * 8), mFile);
+ fwrite16le(static_cast<ushort>(bytes * 8), mFile);
// 32-bit val, channel mask
fwrite32le(chanmask, mFile);
// 16 byte GUID, sub-type format
@@ -326,27 +327,26 @@ bool WaveBackend::reset()
}
mDataStart = ftell(mFile);
- SetDefaultWFXChannelOrder(mDevice);
+ setDefaultWFXChannelOrder();
- const ALuint bufsize{mDevice->frameSizeFromFmt() * mDevice->UpdateSize};
+ const uint bufsize{mDevice->frameSizeFromFmt() * mDevice->UpdateSize};
mBuffer.resize(bufsize);
return true;
}
-bool WaveBackend::start()
+void WaveBackend::start()
{
+ if(mDataStart > 0 && fseek(mFile, 0, SEEK_END) != 0)
+ WARN("Failed to seek on output file\n");
try {
mKillNow.store(false, std::memory_order_release);
mThread = std::thread{std::mem_fn(&WaveBackend::mixerProc), this};
- return true;
}
catch(std::exception& e) {
- ERR("Failed to start mixing thread: %s\n", e.what());
- }
- catch(...) {
+ throw al::backend_exception{al::backend_error::DeviceError,
+ "Failed to start mixing thread: %s", e.what()};
}
- return false;
}
void WaveBackend::stop()
@@ -355,14 +355,17 @@ void WaveBackend::stop()
return;
mThread.join();
- long size{ftell(mFile)};
- if(size > 0)
+ if(mDataStart > 0)
{
- long dataLen{size - mDataStart};
- if(fseek(mFile, mDataStart-4, SEEK_SET) == 0)
- fwrite32le(static_cast<ALuint>(dataLen), mFile); // 'data' header len
- if(fseek(mFile, 4, SEEK_SET) == 0)
- fwrite32le(static_cast<ALuint>(size-8), mFile); // 'WAVE' header len
+ long size{ftell(mFile)};
+ 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
+ }
}
}
@@ -375,20 +378,22 @@ bool WaveBackendFactory::init()
bool WaveBackendFactory::querySupport(BackendType type)
{ return type == BackendType::Playback; }
-void WaveBackendFactory::probe(DevProbe type, std::string *outnames)
+std::string WaveBackendFactory::probe(BackendType type)
{
+ std::string outnames;
switch(type)
{
- case DevProbe::Playback:
- /* Includes null char. */
- outnames->append(waveDevice, sizeof(waveDevice));
- break;
- case DevProbe::Capture:
- break;
+ case BackendType::Playback:
+ /* Includes null char. */
+ outnames.append(waveDevice, sizeof(waveDevice));
+ break;
+ case BackendType::Capture:
+ break;
}
+ return outnames;
}
-BackendPtr WaveBackendFactory::createBackend(ALCdevice *device, BackendType type)
+BackendPtr WaveBackendFactory::createBackend(DeviceBase *device, BackendType type)
{
if(type == BackendType::Playback)
return BackendPtr{new WaveBackend{device}};