aboutsummaryrefslogtreecommitdiffstats
path: root/alc/backends/wasapi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'alc/backends/wasapi.cpp')
-rw-r--r--alc/backends/wasapi.cpp81
1 files changed, 67 insertions, 14 deletions
diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp
index ebd095fd..4494317a 100644
--- a/alc/backends/wasapi.cpp
+++ b/alc/backends/wasapi.cpp
@@ -115,11 +115,6 @@ using ReferenceTime = std::chrono::duration<REFERENCE_TIME,std::ratio<1,10000000
inline constexpr ReferenceTime operator "" _reftime(unsigned long long int n) noexcept
{ return ReferenceTime{static_cast<REFERENCE_TIME>(n)}; }
-#ifndef _MSC_VER
-constexpr AudioObjectType operator|(AudioObjectType lhs, AudioObjectType rhs) noexcept
-{ return static_cast<AudioObjectType>(lhs | al::to_underlying(rhs)); }
-#endif
-
#define MONO SPEAKER_FRONT_CENTER
#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
@@ -148,6 +143,12 @@ constexpr DWORD X61Mask{MaskFromTopBits(X6DOT1)};
constexpr DWORD X71Mask{MaskFromTopBits(X7DOT1)};
constexpr DWORD X714Mask{MaskFromTopBits(X7DOT1DOT4)};
+
+#ifndef _MSC_VER
+constexpr AudioObjectType operator|(AudioObjectType lhs, AudioObjectType rhs) noexcept
+{ return static_cast<AudioObjectType>(lhs | al::to_underlying(rhs)); }
+#endif
+
constexpr AudioObjectType ChannelMask_Mono{AudioObjectType_FrontCenter};
constexpr AudioObjectType ChannelMask_Stereo{AudioObjectType_FrontLeft
| AudioObjectType_FrontRight};
@@ -171,6 +172,7 @@ constexpr AudioObjectType ChannelMask_X714{AudioObjectType_FrontLeft | AudioObje
| AudioObjectType_TopFrontLeft | AudioObjectType_TopFrontRight | AudioObjectType_TopBackLeft
| AudioObjectType_TopBackRight};
+
constexpr char DevNameHead[] = "OpenAL Soft on ";
constexpr size_t DevNameHeadLen{std::size(DevNameHead) - 1};
@@ -182,6 +184,14 @@ template<typename... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
+template<typename T>
+auto as_unsigned(T value) noexcept
+{
+ using UT = std::make_unsigned_t<T>;
+ return static_cast<UT>(value);
+}
+
+
/* Scales the given reftime value, rounding the result. */
template<typename T>
constexpr uint RefTime2Samples(const ReferenceTime &val, T srate) noexcept
@@ -1209,11 +1219,14 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc()
std::vector<ComPtr<ISpatialAudioObject>> channels;
std::vector<float*> buffers;
+ std::vector<float*> resbuffers;
+ std::vector<const void*> tmpbuffers;
/* TODO: Set mPadding appropriately. There doesn't seem to be a way to
- * update it dynamically based on the stream, so it may need to be set to a
- * fixed size.
+ * update it dynamically based on the stream, so a fixed size may be the
+ * best we can do.
*/
+ mPadding.store(mDevice->BufferSize-mDevice->UpdateSize, std::memory_order_release);
while(!mKillNow.load(std::memory_order_relaxed))
{
@@ -1236,12 +1249,11 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc()
{
if(channels.empty()) UNLIKELY
{
- using UT = std::make_unsigned_t<decltype(audio.mStaticMask)>;
- auto flags = static_cast<UT>(al::to_underlying(audio.mStaticMask));
- channels.reserve(static_cast<uint>(al::popcount(flags)));
+ auto flags = as_unsigned(audio.mStaticMask);
+ channels.reserve(as_unsigned(al::popcount(flags)));
while(flags)
{
- auto id = UT{1} << al::countr_zero(flags);
+ auto id = decltype(flags){1} << al::countr_zero(flags);
flags &= ~id;
channels.emplace_back();
@@ -1249,6 +1261,14 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc()
al::out_ptr(channels.back()));
}
buffers.resize(channels.size());
+ if(mResampler)
+ {
+ tmpbuffers.resize(buffers.size());
+ resbuffers.resize(buffers.size());
+ for(size_t i{0};i < tmpbuffers.size();++i)
+ resbuffers[i] = reinterpret_cast<float*>(mResampleBuffer.get()) +
+ mDevice->UpdateSize*i;
+ }
}
/* We have to call to get each channel's buffer individually every
@@ -1263,7 +1283,27 @@ FORCE_ALIGN int WasapiPlayback::mixerSpatialProc()
return reinterpret_cast<float*>(buffer);
});
- mDevice->renderSamples(buffers, framesToDo);
+ if(!mResampler)
+ mDevice->renderSamples(buffers, framesToDo);
+ else
+ {
+ std::lock_guard<std::mutex> _{mMutex};
+ for(UINT32 pos{0};pos < framesToDo;)
+ {
+ if(mBufferFilled == 0)
+ {
+ mDevice->renderSamples(resbuffers, mDevice->UpdateSize);
+ std::copy(resbuffers.cbegin(), resbuffers.cend(), tmpbuffers.begin());
+ mBufferFilled = mDevice->UpdateSize;
+ }
+
+ const uint got{mResampler->convertPlanar(tmpbuffers.data(), &mBufferFilled,
+ reinterpret_cast<void**>(buffers.data()), framesToDo-pos)};
+ for(auto &buf : buffers)
+ buf += got;
+ pos += got;
+ }
+ }
hr = audio.mRender->EndUpdatingAudioObjects();
}
@@ -1745,12 +1785,10 @@ HRESULT WasapiPlayback::resetProxy()
audio.mStaticMask = streamParams.StaticObjectTypeMask;
mFormat = OutputType;
- /* TODO: Support resampling. */
mDevice->FmtType = DevFmtFloat;
mDevice->Flags.reset(DirectEar).set(Virtualization);
if(streamParams.StaticObjectTypeMask == ChannelMask_Stereo)
mDevice->FmtChans = DevFmtStereo;
- mDevice->Frequency = mFormat.Format.nSamplesPerSec;
setDefaultWFXChannelOrder();
@@ -1793,6 +1831,21 @@ HRESULT WasapiPlayback::resetProxy()
mResampler = nullptr;
mResampleBuffer = nullptr;
mBufferFilled = 0;
+ if(mDevice->Frequency != mFormat.Format.nSamplesPerSec)
+ {
+ const auto flags = as_unsigned(streamParams.StaticObjectTypeMask);
+ const auto channelCount = as_unsigned(al::popcount(flags));
+ mResampler = SampleConverter::Create(mDevice->FmtType, mDevice->FmtType,
+ channelCount, mDevice->Frequency, mFormat.Format.nSamplesPerSec,
+ Resampler::FastBSinc24);
+ mResampleBuffer = std::make_unique<char[]>(size_t{mDevice->UpdateSize} * channelCount *
+ mFormat.Format.wBitsPerSample / 8);
+
+ TRACE("Created converter for %s/%s format, dst: %luhz (%u), src: %uhz (%u)\n",
+ DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType),
+ mFormat.Format.nSamplesPerSec, mOrigUpdateSize, mDevice->Frequency,
+ mDevice->UpdateSize);
+ }
return S_OK;
}