#include "config.h" #include "base.h" #include #include #include #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #include #include "albit.h" #include "core/logging.h" #include "aloptional.h" #endif #include "atomic.h" #include "core/devformat.h" bool BackendBase::reset() { throw al::backend_exception{al::backend_error::DeviceError, "Invalid BackendBase call"}; } void BackendBase::captureSamples(al::byte*, uint) { } uint BackendBase::availableSamples() { return 0; } ClockLatency BackendBase::getClockLatency() { ClockLatency ret; uint refcount; do { refcount = mDevice->waitForMix(); ret.ClockTime = GetDeviceClockTime(mDevice); std::atomic_thread_fence(std::memory_order_acquire); } while(refcount != ReadRef(mDevice->MixCount)); /* NOTE: The device will generally have about all but one periods filled at * any given time during playback. Without a more accurate measurement from * the output, this is an okay approximation. */ ret.Latency = std::max(std::chrono::seconds{mDevice->BufferSize-mDevice->UpdateSize}, std::chrono::seconds::zero()); ret.Latency /= mDevice->Frequency; return ret; } void BackendBase::setDefaultWFXChannelOrder() { mDevice->RealOut.ChannelIndex.fill(INVALID_CHANNEL_INDEX); switch(mDevice->FmtChans) { case DevFmtMono: mDevice->RealOut.ChannelIndex[FrontCenter] = 0; break; case DevFmtStereo: mDevice->RealOut.ChannelIndex[FrontLeft] = 0; mDevice->RealOut.ChannelIndex[FrontRight] = 1; break; case DevFmtQuad: mDevice->RealOut.ChannelIndex[FrontLeft] = 0; mDevice->RealOut.ChannelIndex[FrontRight] = 1; mDevice->RealOut.ChannelIndex[BackLeft] = 2; mDevice->RealOut.ChannelIndex[BackRight] = 3; break; case DevFmtX51: mDevice->RealOut.ChannelIndex[FrontLeft] = 0; mDevice->RealOut.ChannelIndex[FrontRight] = 1; mDevice->RealOut.ChannelIndex[FrontCenter] = 2; mDevice->RealOut.ChannelIndex[LFE] = 3; mDevice->RealOut.ChannelIndex[SideLeft] = 4; mDevice->RealOut.ChannelIndex[SideRight] = 5; break; case DevFmtX61: mDevice->RealOut.ChannelIndex[FrontLeft] = 0; mDevice->RealOut.ChannelIndex[FrontRight] = 1; mDevice->RealOut.ChannelIndex[FrontCenter] = 2; mDevice->RealOut.ChannelIndex[LFE] = 3; mDevice->RealOut.ChannelIndex[BackCenter] = 4; mDevice->RealOut.ChannelIndex[SideLeft] = 5; mDevice->RealOut.ChannelIndex[SideRight] = 6; break; case DevFmtX71: mDevice->RealOut.ChannelIndex[FrontLeft] = 0; mDevice->RealOut.ChannelIndex[FrontRight] = 1; mDevice->RealOut.ChannelIndex[FrontCenter] = 2; mDevice->RealOut.ChannelIndex[LFE] = 3; mDevice->RealOut.ChannelIndex[BackLeft] = 4; mDevice->RealOut.ChannelIndex[BackRight] = 5; mDevice->RealOut.ChannelIndex[SideLeft] = 6; mDevice->RealOut.ChannelIndex[SideRight] = 7; break; case DevFmtAmbi3D: break; } } void BackendBase::setDefaultChannelOrder() { mDevice->RealOut.ChannelIndex.fill(INVALID_CHANNEL_INDEX); switch(mDevice->FmtChans) { case DevFmtX51: mDevice->RealOut.ChannelIndex[FrontLeft] = 0; mDevice->RealOut.ChannelIndex[FrontRight] = 1; mDevice->RealOut.ChannelIndex[SideLeft] = 2; mDevice->RealOut.ChannelIndex[SideRight] = 3; mDevice->RealOut.ChannelIndex[FrontCenter] = 4; mDevice->RealOut.ChannelIndex[LFE] = 5; return; case DevFmtX71: mDevice->RealOut.ChannelIndex[FrontLeft] = 0; mDevice->RealOut.ChannelIndex[FrontRight] = 1; mDevice->RealOut.ChannelIndex[BackLeft] = 2; mDevice->RealOut.ChannelIndex[BackRight] = 3; mDevice->RealOut.ChannelIndex[FrontCenter] = 4; mDevice->RealOut.ChannelIndex[LFE] = 5; mDevice->RealOut.ChannelIndex[SideLeft] = 6; mDevice->RealOut.ChannelIndex[SideRight] = 7; return; /* Same as WFX order */ case DevFmtMono: case DevFmtStereo: case DevFmtQuad: case DevFmtX61: case DevFmtAmbi3D: setDefaultWFXChannelOrder(); break; } } #ifdef _WIN32 void BackendBase::setChannelOrderFromWFXMask(uint chanmask) { static constexpr uint x51{SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT}; static constexpr uint x51rear{SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT}; /* Swap a 5.1 mask using the back channels for one with the sides. */ if(chanmask == x51rear) chanmask = x51; auto get_channel = [](const DWORD chanbit) noexcept -> al::optional { switch(chanbit) { case SPEAKER_FRONT_LEFT: return al::make_optional(FrontLeft); case SPEAKER_FRONT_RIGHT: return al::make_optional(FrontRight); case SPEAKER_FRONT_CENTER: return al::make_optional(FrontCenter); case SPEAKER_LOW_FREQUENCY: return al::make_optional(LFE); case SPEAKER_BACK_LEFT: return al::make_optional(BackLeft); case SPEAKER_BACK_RIGHT: return al::make_optional(BackRight); case SPEAKER_FRONT_LEFT_OF_CENTER: break; case SPEAKER_FRONT_RIGHT_OF_CENTER: break; case SPEAKER_BACK_CENTER: return al::make_optional(BackCenter); case SPEAKER_SIDE_LEFT: return al::make_optional(SideLeft); case SPEAKER_SIDE_RIGHT: return al::make_optional(SideRight); case SPEAKER_TOP_CENTER: return al::make_optional(TopCenter); case SPEAKER_TOP_FRONT_LEFT: return al::make_optional(TopFrontLeft); case SPEAKER_TOP_FRONT_CENTER: return al::make_optional(TopFrontCenter); case SPEAKER_TOP_FRONT_RIGHT: return al::make_optional(TopFrontRight); case SPEAKER_TOP_BACK_LEFT: return al::make_optional(TopBackLeft); case SPEAKER_TOP_BACK_CENTER: return al::make_optional(TopBackCenter); case SPEAKER_TOP_BACK_RIGHT: return al::make_optional(TopBackRight); } WARN("Unhandled WFX channel bit 0x%lx\n", chanbit); return al::nullopt; }; const uint numchans{mDevice->channelsFromFmt()}; uint idx{0}; while(chanmask) { const int bit{al::countr_zero(chanmask)}; const uint mask{1u << bit}; chanmask &= ~mask; if(auto label = get_channel(mask)) { mDevice->RealOut.ChannelIndex[*label] = idx; if(++idx == numchans) break; } } } #endif