Browse Source

audio: implement linear interpolation resampling

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

+ 42
- 9
include/lol/private/audio/stream.h View File

@@ -34,9 +34,11 @@ public:


virtual size_t get(T* buf, size_t frames) = 0; 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; virtual ~stream() = default;


@@ -89,7 +91,7 @@ public:


virtual size_t get(T *buf, size_t frames) override 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<T> tmp(frames * this->channels()); std::vector<T> tmp(frames * this->channels());
for (auto s : m_streamers) for (auto s : m_streamers)
@@ -158,21 +160,52 @@ class resampler : public stream<T>
public: public:
resampler(std::shared_ptr<stream<T>> s, int frequency) resampler(std::shared_ptr<stream<T>> s, int frequency)
: stream<T>(s->channels(), frequency), : stream<T>(s->channels(), frequency),
s(s)
m_in(s),
m_pos(0)
{} {}


virtual size_t get(T *buf, size_t frames) override 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<T>(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; return frames;
} }


protected: protected:
std::shared_ptr<stream<T>> s;
std::shared_ptr<stream<T>> m_in;

std::vector<T> m_cache;

double m_pos;
}; };


template<typename T> template<typename T>


Loading…
Cancel
Save