Browse Source

audio: create a mapper streaming object for channel remapping

wip/image-kernel
Sam Hocevar 9 months ago
parent
commit
f7767240d0
1 changed files with 62 additions and 15 deletions
  1. +62
    -15
      include/lol/private/audio/stream.h

+ 62
- 15
include/lol/private/audio/stream.h View File

@@ -139,26 +139,67 @@ template<typename T, typename T0>
class converter : public stream<T>
{
public:
converter(std::shared_ptr<stream<T0>> s, size_t channels)
: stream<T>(channels, s->frequency()),
s0(s)
converter(std::shared_ptr<stream<T0>> s)
: stream<T>(s->channels(), s->frequency()),
m_in(s)
{}

virtual size_t get(T *buf, size_t frames) override
{
if constexpr(std::is_same_v<T0, T>)
if (this->channels() == s0->channels())
return s0->get(buf, frames);
return m_in->get(buf, frames);

size_t samples = frames * this->channels();

std::vector<T0> tmp(samples);
m_in->get(tmp.data(), frames);
for (size_t n = 0; n < samples; ++n)
buf[n] = convert_sample<T0, T>(tmp[n]);

return frames;
}

protected:
std::shared_ptr<stream<T0>> m_in;
};

template<typename T>
class mapper : public stream<T>
{
public:
mapper(std::shared_ptr<stream<T>> s, size_t channels)
: stream<T>(channels, s->frequency()),
m_in(s)
{}

virtual size_t get(T *buf, size_t frames) override
{
if (this->channels() == m_in->channels())
return m_in->get(buf, frames);

std::vector<T> tmp(frames * m_in->channels());
m_in->get(tmp.data(), frames);

// FIXME: we need to build a better matrix than this, also maybe the mapper
// constructor needs an option to preserve energy or not?
std::vector<T> matrix(m_in->channels() * this->channels(), T(1));

std::vector<T0> tmp(frames * s0->channels());
s0->get(tmp.data(), frames);
for (size_t f = 0; f < frames; ++f)
{
buf[f * this->channels()] = convert_sample<T0, T>(tmp[f * s0->channels()]);
for (size_t ch = 1; ch < this->channels(); ++ch)
for (size_t out_ch = 0; out_ch < this->channels(); ++out_ch)
{
size_t ch0 = std::max(size_t(0), s0->channels() - (this->channels() - ch));
buf[f * this->channels() + ch] = convert_sample<T0, T>(tmp[f * s0->channels() + ch0]);
T sample(0);
for (size_t in_ch = 0; in_ch < m_in->channels(); ++in_ch)
sample += tmp[f * m_in->channels() + in_ch] * matrix[out_ch * m_in->channels() + in_ch];

if constexpr (std::is_same_v<T, float>)
buf[f * this->channels() + out_ch] = std::min(1.0f, std::max(-1.0f, sample));
else if constexpr (std::is_same_v<T, int16_t>)
buf[f * this->channels() + out_ch] = std::min(int16_t(32767), std::max(int16_t(-32768), sample));
else if constexpr (std::is_same_v<T, uint16_t>)
buf[f * this->channels() + out_ch] = std::min(uint16_t(65535), std::max(uint16_t(0), sample));
else
buf[f * this->channels() + out_ch] = sample;
}
}

@@ -166,7 +207,7 @@ public:
}

protected:
std::shared_ptr<stream<T0>> s0;
std::shared_ptr<stream<T>> m_in;
};

template<typename T>
@@ -236,9 +277,15 @@ static inline auto make_generator(F f, size_t channels, int frequency)
}

template<typename T, typename S0, typename T0 = S0::sample_type>
static inline auto make_converter(std::shared_ptr<S0> s, size_t channels)
static inline auto make_converter(std::shared_ptr<S0> s)
{
return std::make_shared<converter<T, T0>>(std::shared_ptr<stream<T0>>(s));
}

template<typename S, typename T = S::sample_type>
static inline auto make_mapper(std::shared_ptr<S> s, size_t channels)
{
return std::make_shared<converter<T, T0>>(std::shared_ptr<stream<T0>>(s), channels);
return std::make_shared<mapper<T>>(std::shared_ptr<stream<T>>(s), channels);
}

template<typename S, typename T = S::sample_type>
@@ -250,7 +297,7 @@ static inline auto make_resampler(std::shared_ptr<S> s, int frequency)
template<typename T, typename S0, typename T0 = S0::sample_type>
static inline auto make_adapter(std::shared_ptr<S0> s, size_t channels, int frequency)
{
return make_resampler(make_converter<T>(s, channels), frequency);
return make_resampler(make_mapper(make_converter<T>(s), channels), frequency);
}

} // namespace lol::audio

Loading…
Cancel
Save