Skip to content

Commit

Permalink
Simplify (de)interleaving samples
Browse files Browse the repository at this point in the history
If these iterators are ever bounds-checked at runtime, this should help avoid
extraneous checks without running iterators past the end after the handling the
final sample.
  • Loading branch information
kcat committed Mar 1, 2025
1 parent 52d7797 commit fd74b3d
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 21 deletions.
33 changes: 18 additions & 15 deletions alc/alu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2146,23 +2146,26 @@ void Write(const al::span<const FloatBufferLine> InBuffer, void *OutBuffer, cons
/* Some Clang versions don't like calling subspan on an rvalue here. */
const auto output_ = al::span{static_cast<T*>(OutBuffer), (Offset+SamplesToDo)*FrameStep};
const auto output = output_.subspan(Offset*FrameStep);
size_t c{0};
for(const FloatBufferLine &inbuf : InBuffer)

/* If there's extra channels in the interleaved output buffer to skip,
* clear the whole output buffer. This is simpler to ensure the extra
* channels are silent than trying to clear just the extra channels.
*/
if(FrameStep > InBuffer.size())
std::fill(output.begin(), output.end(), SampleConv<T>(0.0f));

auto outbase = output.begin();
for(const auto &srcbuf : InBuffer)
{
auto out = output.begin();
auto conv_sample = [FrameStep,c,&out](const float s) noexcept
const auto src = al::span{srcbuf}.first(SamplesToDo);
auto out = outbase++;

*out = SampleConv<T>(src.front());
std::for_each(src.begin()+1, src.end(), [FrameStep,&out](const float s) noexcept
{
out[c] = SampleConv<T>(s);
out += ptrdiff_t(FrameStep);
};
std::for_each_n(inbuf.cbegin(), SamplesToDo, conv_sample);
++c;
}
if(const size_t extra{FrameStep - c})
{
const auto silence = SampleConv<T>(0.0f);
for(size_t i{0};i < SamplesToDo;++i)
std::fill_n(&output[i*FrameStep + c], extra, silence);
*out = SampleConv<T>(s);
});
}
}

Expand All @@ -2179,7 +2182,7 @@ void Write(const al::span<const FloatBufferLine> InBuffer, al::span<void*> OutBu
/* Some Clang versions don't like calling subspan on an rvalue here. */
const auto dst_ = al::span{static_cast<T*>(dstbuf), Offset+SamplesToDo};
const auto dst = dst_.subspan(Offset);
std::transform(src.cbegin(), src.end(), dst.begin(), SampleConv<T>);
std::transform(src.begin(), src.end(), dst.begin(), SampleConv<T>);
++srcbuf;
}
}
Expand Down
11 changes: 5 additions & 6 deletions core/voice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,18 +276,17 @@ inline void LoadSamples(const al::span<float> dstSamples, const al::span<const s
{
using TypeTraits = al::FmtTypeTraits<Type>;
using SampleType = typename TypeTraits::Type;
static constexpr size_t sampleSize{sizeof(SampleType)};
assert(srcChan < srcStep);
auto converter = TypeTraits{};

al::span<const SampleType> src{reinterpret_cast<const SampleType*>(srcData.data()),
srcData.size()/sampleSize};
auto ssrc = src.cbegin() + ptrdiff_t(srcOffset*srcStep);
std::generate(dstSamples.begin(), dstSamples.end(), [&ssrc,srcChan,srcStep,converter]
srcData.size()/sizeof(SampleType)};
auto ssrc = src.cbegin() + ptrdiff_t(srcOffset*srcStep + srcChan);
dstSamples.front() = converter(*ssrc);
std::generate(dstSamples.begin()+1, dstSamples.end(), [&ssrc,srcStep,converter]
{
auto ret = converter(ssrc[srcChan]);
ssrc += ptrdiff_t(srcStep);
return ret;
return converter(*ssrc);
});
}

Expand Down

0 comments on commit fd74b3d

Please sign in to comment.