diff --git a/include/lol/private/audio/stream.h b/include/lol/private/audio/stream.h index 08f0ac9b..73791b9c 100644 --- a/include/lol/private/audio/stream.h +++ b/include/lol/private/audio/stream.h @@ -34,9 +34,11 @@ public: virtual size_t get(T* buf, size_t frames) = 0; - size_t channels() const { return m_channels; } + inline size_t channels() const { return m_channels; } - int frequency() const { return m_frequency; } + inline int frequency() const { return m_frequency; } + + inline size_t frame_size() const { return channels() * sizeof(T); } virtual ~stream() = default; @@ -89,7 +91,7 @@ public: virtual size_t get(T *buf, size_t frames) override { - memset(buf, 0, frames * this->channels() * sizeof(T)); + memset(buf, 0, frames * this->frame_size()); std::vector tmp(frames * this->channels()); for (auto s : m_streamers) @@ -158,21 +160,52 @@ class resampler : public stream public: resampler(std::shared_ptr> s, int frequency) : stream(s->channels(), frequency), - s(s) + m_in(s), + m_pos(0) {} virtual size_t get(T *buf, size_t frames) override { - if (s->frequency() == this->frequency()) - return s->get(buf, frames); + if (m_in->frequency() == this->frequency()) + return m_in->get(buf, frames); + + double ratio = double(m_in->frequency()) / this->frequency(); + + for (size_t n = 0; n < frames; ++n, m_pos += ratio) + { + // Fill internal buffer if we don’t have enough data + while (m_cache.size() / this->channels() < size_t(m_pos) + 2) + { + // Remove obsolete frames on the left + size_t todelete = std::min(size_t(m_pos), m_cache.size() / this->channels()); + std::vector(m_cache.begin() + todelete * this->channels(), m_cache.end()).swap(m_cache); + m_pos -= todelete; + + // Add new frames to the right + size_t offset = m_cache.size(); + m_cache.resize(offset + frames * this->channels()); + m_in->get(&m_cache[offset], frames); + } + + size_t n0 = size_t(m_pos); + float alpha = float(m_pos - n0); + + for (size_t ch = 0; ch < this->channels(); ++ch) + { + buf[n * this->channels() + ch] = m_cache[n0 * this->channels() + ch] * (1.f - alpha) + + m_cache[(n0 + 1) * this->channels() + ch] * alpha; + } + } - // FIXME: implement resampling! - memset(buf, 0, frames * this->channels() * sizeof(T)); return frames; } protected: - std::shared_ptr> s; + std::shared_ptr> m_in; + + std::vector m_cache; + + double m_pos; }; template