|
@@ -139,26 +139,67 @@ template<typename T, typename T0> |
|
|
class converter : public stream<T> |
|
|
class converter : public stream<T> |
|
|
{ |
|
|
{ |
|
|
public: |
|
|
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 |
|
|
virtual size_t get(T *buf, size_t frames) override |
|
|
{ |
|
|
{ |
|
|
if constexpr(std::is_same_v<T0, T>) |
|
|
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) |
|
|
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: |
|
|
protected: |
|
|
std::shared_ptr<stream<T0>> s0; |
|
|
|
|
|
|
|
|
std::shared_ptr<stream<T>> m_in; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
template<typename T> |
|
|
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> |
|
|
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> |
|
|
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> |
|
|
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) |
|
|
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 |
|
|
} // namespace lol::audio |