aboutsummaryrefslogtreecommitdiffstats
path: root/alc/converter.cpp
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2020-10-05 22:30:23 -0700
committerChris Robinson <[email protected]>2020-10-05 22:30:23 -0700
commit7fb6d64ca81d68f74a254c097d511d8863453000 (patch)
tree7393463f07febc1fd0d31c50bc62d18b90774518 /alc/converter.cpp
parente7a44d3b7063553fa54e743a4fac116d130fbe1d (diff)
Be more robust with to-mono channel conversions
Diffstat (limited to 'alc/converter.cpp')
-rw-r--r--alc/converter.cpp25
1 files changed, 17 insertions, 8 deletions
diff --git a/alc/converter.cpp b/alc/converter.cpp
index ead0c2f6..b07e8619 100644
--- a/alc/converter.cpp
+++ b/alc/converter.cpp
@@ -135,14 +135,24 @@ void Mono2Stereo(float *RESTRICT dst, const void *src, const size_t frames) noex
}
template<DevFmtType T>
-void Stereo2Mono(float *RESTRICT dst, const void *src, const size_t frames) noexcept
+void Multi2Mono(ALuint chanmask, const size_t step, const float scale, float *RESTRICT dst,
+ const void *src, const size_t frames) noexcept
{
using SampleType = typename DevFmtTypeTraits<T>::Type;
const SampleType *ssrc = static_cast<const SampleType*>(src);
+ std::fill_n(dst, frames, 0.0f);
+ for(size_t c{0};chanmask;++c)
+ {
+ if LIKELY((chanmask&1))
+ {
+ for(size_t i{0u};i < frames;i++)
+ dst[i] += LoadSample<T>(ssrc[i*step + c]);
+ }
+ chanmask >>= 1;
+ }
for(size_t i{0u};i < frames;i++)
- dst[i] = (LoadSample<T>(ssrc[i*2 + 0])+LoadSample<T>(ssrc[i*2 + 1])) *
- 0.707106781187f;
+ dst[i] *= scale;
}
} // namespace
@@ -328,11 +338,12 @@ ALuint SampleConverter::convert(const void **src, ALuint *srcframes, void *dst,
void ChannelConverter::convert(const void *src, float *dst, ALuint frames) const
{
- if(mSrcChans == DevFmtStereo && mDstChans == DevFmtMono)
+ if(mDstChans == DevFmtMono)
{
+ const float scale{std::sqrt(1.0f / static_cast<float>(POPCNT32(mChanMask)))};
switch(mSrcType)
{
-#define HANDLE_FMT(T) case T: Stereo2Mono<T>(dst, src, frames); break
+#define HANDLE_FMT(T) case T: Multi2Mono<T>(mChanMask, mSrcStep, scale, dst, src, frames); break
HANDLE_FMT(DevFmtByte);
HANDLE_FMT(DevFmtUByte);
HANDLE_FMT(DevFmtShort);
@@ -343,7 +354,7 @@ void ChannelConverter::convert(const void *src, float *dst, ALuint frames) const
#undef HANDLE_FMT
}
}
- else if(mSrcChans == DevFmtMono && mDstChans == DevFmtStereo)
+ else if(mChanMask == 0x1 && mDstChans == DevFmtStereo)
{
switch(mSrcType)
{
@@ -358,6 +369,4 @@ void ChannelConverter::convert(const void *src, float *dst, ALuint frames) const
#undef HANDLE_FMT
}
}
- else
- LoadSamples(dst, src, 1u, mSrcType, frames * ChannelsFromDevFmt(mSrcChans, 0));
}