Audio library refactor: use spans for stream->read

This commit is contained in:
Nikita Lisitsa 2023-01-10 03:35:34 +03:00
parent 7376109e96
commit 2209648999
22 changed files with 124 additions and 130 deletions

View file

@ -20,7 +20,7 @@ namespace psemek::audio
float smoothness() const;
float smoothness(float value);
void apply(float * data, std::size_t sample_count);
void apply(util::span<float> samples);
private:
std::atomic<float> gain_[2];

View file

@ -1,5 +1,7 @@
#pragma once
#include <psemek/util/span.hpp>
#include <cstddef>
#include <memory>
#include <optional>
@ -14,7 +16,7 @@ namespace psemek::audio
// Return value less than sample count means end of stream
// Must be called from mixing thread
virtual std::size_t read(float * data, std::size_t sample_count) = 0;
virtual std::size_t read(util::span<float> samples) = 0;
// The number of samples already played from this stream
virtual std::size_t played() const = 0;

View file

@ -26,17 +26,16 @@ namespace psemek::audio
return played_.load();
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
auto end = data + sample_count;
for (auto p = data; p != end;)
for (auto p = samples.begin(); p != samples.end();)
{
float v = func_();
*p++ = v;
*p++ = v;
}
played_.fetch_add(sample_count);
return sample_count;
played_.fetch_add(samples.size());
return samples.size();
}
private:

View file

@ -26,18 +26,18 @@ namespace psemek::audio
return played_.load();
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
auto buffer = recorder_->buffer();
auto played = played_.load();
if (buffer.size() < played + sample_count)
if (buffer.size() < played + samples.size())
{
recorder_->request(sample_count);
recorder_->request(samples.size());
buffer = recorder_->buffer();
}
auto count = std::min<std::size_t>(sample_count, buffer.size() - played);
std::copy(buffer.data() + played, buffer.data() + played + count, data);
auto count = std::min<std::size_t>(samples.size(), buffer.size() - played);
std::copy(buffer.data() + played, buffer.data() + played + count, samples.begin());
played_.fetch_add(count);
return count;
}

View file

@ -27,13 +27,13 @@ namespace psemek::audio
return stream_->length();
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
auto result = stream_->read(data, sample_count);
auto count = stream_->read(samples);
for (std::size_t i = 0; i < result; i += 2)
for (std::size_t i = 0; i < count; i += 2)
{
float v = std::max(std::abs(data[i]), std::abs(data[i + 1]));
float v = std::max(std::abs(samples[i]), std::abs(samples[i + 1]));
float multiplier = (v > envelope_) ? envelope_attack_multiplier_ : envelope_release_multiplier_;
@ -50,11 +50,11 @@ namespace psemek::audio
float gain = std::exp(log_gain);
data[i + 0] *= gain;
data[i + 1] *= gain;
samples[i + 0] *= gain;
samples[i + 1] *= gain;
}
return result;
return count;
}
std::size_t played() const override

View file

@ -32,14 +32,15 @@ namespace psemek::audio
return length_;
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
std::size_t count = 0;
for (; index_ != streams_.size(); ++index_)
{
count += streams_[index_]->read(data + count, sample_count - count);
if (count == sample_count)
count += streams_[index_]->read(samples);
samples.consume(count);
if (samples.empty())
break;
}

View file

@ -32,17 +32,17 @@ namespace psemek::audio
return stream_->length();
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
auto result = stream_->read(data, sample_count);
auto count = stream_->read(samples);
float strength = strength_.load();
for (std::size_t i = 0; i < result; ++i)
for (std::size_t i = 0; i < count; ++i)
{
data[i] = std::tanh(strength * data[i]);
samples[i] = std::tanh(strength * samples[i]);
}
return result;
return count;
}
std::size_t played() const override

View file

@ -28,30 +28,30 @@ namespace psemek::audio
return stream_->played();
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
auto const result = stream_->read(data, sample_count);
std::fill(data, data + std::min<std::size_t>(result, start_.samples()), 0.f);
auto const count = stream_->read(samples);
std::fill(samples.begin(), samples.begin() + std::min<std::size_t>(count, start_.samples()), 0.f);
if (result <= start_.samples())
if (count <= start_.samples())
{
start_ -= result;
start_ -= count;
}
else
{
for (std::size_t i = start_.samples(); i < result; i += 2)
for (std::size_t i = start_.samples(); i < count; i += 2)
{
float m = static_cast<float>(std::min<std::size_t>(current_, length_.samples())) / length_.samples();
data[i + 0] *= m;
data[i + 1] *= m;
samples[i + 0] *= m;
samples[i + 1] *= m;
current_ += 2;
}
start_ = duration{};
}
return result;
return count;
}
private:

View file

@ -29,12 +29,12 @@ namespace psemek::audio
return stream_->played();
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
if (current_ >= length_.samples())
return 0;
auto result = stream_->read(data, sample_count);
auto result = stream_->read(samples);
if (result <= start_.samples())
{
@ -46,8 +46,8 @@ namespace psemek::audio
{
float m = static_cast<float>(length_.samples() - std::min<std::size_t>(current_, length_.samples())) / length_.samples();
data[i + 0] *= m;
data[i + 1] *= m;
samples[i + 0] *= m;
samples[i + 1] *= m;
current_ += 2;
}

View file

@ -20,17 +20,17 @@ namespace psemek::audio
return stream_->length();
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
std::size_t count = stream_->read(data, sample_count);
std::size_t count = stream_->read(samples);
for (std::size_t i = 0; i < count; i += 2)
{
std::swap(prev_[0], data[i + 0]);
std::swap(prev_[1], data[i + 1]);
std::swap(prev_[0], samples[i + 0]);
std::swap(prev_[1], samples[i + 1]);
data[i + 0] = prev_[0] * a0_ + data[i + 0] * a1_;
data[i + 1] = prev_[1] * a0_ + data[i + 1] * a1_;
samples[i + 0] = prev_[0] * a0_ + samples[i + 0] * a1_;
samples[i + 1] = prev_[1] * a0_ + samples[i + 1] * a1_;
}
return count;

View file

@ -23,21 +23,21 @@ namespace psemek::audio
return std::nullopt;
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
std::size_t result = 0;
while (result < sample_count && (!count_ || repeated_ < *count_))
std::size_t count = 0;
while (count < samples.size() && (!count_ || repeated_ < *count_))
{
auto need = sample_count - result;
auto count = stream_->read(data + result, need);
result += count;
if (count < need)
auto need = samples.size() - count;
auto scount = stream_->read({samples.begin() + count, need});
count += scount;
if (scount < need)
{
++repeated_;
stream_ = dup_->stream();
}
}
return result;
return count;
}
std::size_t played() const override

View file

@ -34,42 +34,42 @@ namespace psemek::audio
return stream_->length();
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
bool const paused = paused_.load();
if (paused)
{
auto result = stream_->read(data, std::min(sample_count, level_));
auto count = stream_->read(samples.prefix(std::min(samples.size(), level_)));
for (std::size_t i = 0; i < result; i += 2)
for (std::size_t i = 0; i < count; i += 2)
{
float gain = static_cast<float>(level_) / length_.samples();
data[i + 0] *= gain;
data[i + 1] *= gain;
samples[i + 0] *= gain;
samples[i + 1] *= gain;
level_ -= 2;
}
std::fill(data + result, data + sample_count, 0.f);
return sample_count;
std::fill(samples.begin() + count, samples.end(), 0.f);
return samples.size();
}
else
{
auto result = stream_->read(data, sample_count);
auto count = stream_->read(samples);
auto const max_level = static_cast<std::size_t>(length_.samples());
for (std::size_t i = 0; i < result; i += 2)
for (std::size_t i = 0; i < count; i += 2)
{
float gain = static_cast<float>(level_) / max_level;
data[i + 0] *= gain;
data[i + 1] *= gain;
samples[i + 0] *= gain;
samples[i + 1] *= gain;
if (level_ < max_level)
level_ += 2;
}
return result;
return count;
}
}

View file

@ -46,17 +46,17 @@ namespace psemek::audio
return std::nullopt;
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
std::size_t result = 0;
std::size_t count = 0;
while (result < sample_count)
while (count < samples.size())
{
if (resampler_pos_ < resampler_.result().size())
{
std::size_t size = std::min(sample_count - result, resampler_.result().size() - resampler_pos_);
std::copy(resampler_.result().data() + resampler_pos_, resampler_.result().data() + resampler_pos_ + size, data + result);
result += size;
std::size_t size = std::min(samples.size() - count, resampler_.result().size() - resampler_pos_);
std::copy(resampler_.result().data() + resampler_pos_, resampler_.result().data() + resampler_pos_ + size, samples.begin() + count);
count += size;
resampler_pos_ += size;
played_ += size;
}
@ -64,18 +64,18 @@ namespace psemek::audio
{
resampler_pos_ = 0;
std::size_t request_size = std::max<std::size_t>(sample_count, std::ceil(resampler_.ratio() * sample_count / 2.f) * 2);
std::size_t request_size = std::max<std::size_t>(samples.size(), std::ceil(resampler_.ratio() * samples.size() / 2.f) * 2);
source_buffer_.resize(request_size);
auto count = stream_->read(source_buffer_.data(), request_size);
auto source_count = stream_->read({source_buffer_.data(), request_size});
if (count == 0)
if (source_count == 0)
break;
resampler_.feed({source_buffer_.data(), source_buffer_.data() + count});
resampler_.feed({source_buffer_.data(), source_buffer_.data() + source_count});
}
}
return result;
return count;
}
std::size_t played() const override

View file

@ -19,12 +19,11 @@ namespace psemek::audio
return length_.samples();
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
auto played = stream_->played();
auto result = std::min<std::size_t>(length_.samples() - played, sample_count);
result = stream_->read(data, result);
return result;
auto max_count = std::min<std::size_t>(length_.samples() - played, samples.size());
return stream_->read(samples.prefix(max_count));
}
std::size_t played() const override

View file

@ -31,11 +31,11 @@ namespace psemek::audio
return stream_->played();
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
auto result = stream_->read(data, sample_count);
base_.apply(data, result);
return result;
auto count = stream_->read(samples);
base_.apply(samples.prefix(count));
return count;
}
private:
@ -69,11 +69,11 @@ namespace psemek::audio
return stream_->played();
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
auto result = stream_->read(data, sample_count);
base_.apply(data, result);
return result;
auto count = stream_->read(samples);
base_.apply(samples.prefix(count));
return count;
}
private:

View file

@ -26,13 +26,12 @@ namespace psemek::audio
return multiplier_to_smoothness(old);
}
void volume_base::apply(float * data, std::size_t sample_count)
void volume_base::apply(util::span<float> samples)
{
float gain[2] = {gain_[0].load(), gain_[1].load()};
float smoothness_multiplier = smoothness_multiplier_.load();
auto end = data + sample_count;
for (auto p = data; p < end;)
for (auto p = samples.begin(); p < samples.end();)
{
*p++ *= real_gain_[0];
*p++ *= real_gain_[1];

View file

@ -77,7 +77,7 @@ namespace psemek::audio
std::size_t const size = len / 2;
std::size_t read = 0;
if (output)
read = output->read(self->buffer.data(), size);
read = output->read({self->buffer.data(), size});
std::fill(self->buffer.data() + read, self->buffer.data() + size, 0.f);
for (auto s : self->buffer)

View file

@ -17,7 +17,7 @@ namespace psemek::audio
{
channel_ptr add(stream_ptr stream) override;
std::size_t read(float * data, std::size_t sample_count) override;
std::size_t read(util::span<float> samples) override;
std::optional<std::size_t> length() const override
{
@ -53,7 +53,7 @@ namespace psemek::audio
return result;
}
std::size_t mixer_impl::read(float * data, std::size_t sample_count)
std::size_t mixer_impl::read(util::span<float> samples)
{
{
std::vector<channel_ptr> new_channels;
@ -65,9 +65,9 @@ namespace psemek::audio
channels_.push_back(std::move(ch));
}
std::fill(data, data + sample_count, 0.f);
std::fill(samples.begin(), samples.end(), 0.f);
buffer_.resize(sample_count);
buffer_.resize(samples.size());
for (auto & ch : channels_)
{
@ -75,17 +75,11 @@ namespace psemek::audio
if (!stream)
continue;
auto read = stream->read(buffer_.data(), sample_count);
auto read = stream->read(buffer_);
{
auto begin = buffer_.data();
auto end = begin + read;
auto dst = data;
for (; begin < end; )
*dst++ += *begin++;
}
std::copy(buffer_.data(), buffer_.data() + read, samples.begin());
if (read < sample_count)
if (read < buffer_.size())
{
ch->stop();
continue;
@ -97,9 +91,9 @@ namespace psemek::audio
std::swap(channels_, alive_channels_);
alive_channels_.clear();
played_.fetch_add(sample_count);
played_.fetch_add(samples.size());
return sample_count;
return samples.size();
}
}

View file

@ -40,9 +40,9 @@ namespace psemek::audio
samples_ = {storage_.data(), storage_.data() + samples_.size()};
}
auto result = stream_->read(storage_.data() + samples_.size(), samples);
samples_ = {storage_.data(), storage_.data() + samples_.size() + result};
return result;
auto count = stream_->read({storage_.data() + samples_.size(), samples});
samples_ = {storage_.data(), storage_.data() + samples_.size() + count};
return count;
}
util::span<float const> buffer() const override

View file

@ -34,20 +34,20 @@ namespace psemek::audio
return std::min(left_->played(), right_->played());
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
if (buffer_.size() < sample_count)
buffer_.resize(sample_count);
if (buffer_.size() < samples.size())
buffer_.resize(samples.size());
auto right_result = right_->read(data, sample_count);
auto left_result = left_->read(buffer_.data(), sample_count);
auto right_result = right_->read(samples);
auto left_result = left_->read({buffer_.data(), samples.size()});
auto result = std::min(right_result, left_result);
{
auto begin = buffer_.data();
auto end = buffer_.data() + result;
auto dst = data;
auto dst = samples.data();
for (; begin < end; begin += 2, dst += 2)
*dst = *begin;
}

View file

@ -43,19 +43,19 @@ namespace psemek::audio
return std::nullopt;
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
auto input = reinterpret_cast<std::uint8_t const *>(data_->data.data());
std::size_t result = 0;
while (result < sample_count)
std::size_t count = 0;
while (count < samples.size())
{
if (resampler_pos_ < resampler_.result().size())
{
std::size_t size = std::min(resampler_.result().size() - resampler_pos_, sample_count - result);
std::copy(resampler_.result().data() + resampler_pos_, resampler_.result().data() + resampler_pos_ + size, data + result);
std::size_t size = std::min(resampler_.result().size() - resampler_pos_, samples.size() - count);
std::copy(resampler_.result().data() + resampler_pos_, resampler_.result().data() + resampler_pos_ + size, samples.begin() + count);
resampler_pos_ += size;
result += size;
count += size;
}
else
{
@ -84,9 +84,9 @@ namespace psemek::audio
}
}
played_.fetch_add(result);
played_.fetch_add(count);
return result;
return count;
}
std::size_t played() const override

View file

@ -25,23 +25,23 @@ namespace psemek::audio
return std::nullopt;
}
std::size_t read(float * data, std::size_t sample_count) override
std::size_t read(util::span<float> samples) override
{
std::size_t const size = buffer_.size();
for (std::size_t i = 0; i < sample_count; i += 2)
for (std::size_t i = 0; i < samples.size(); i += 2)
{
buffer_[buffer_pos_ + 0] = (buffer_[buffer_pos_ + 0] + buffer_[(buffer_pos_ + 2) % size + 0]) / 2.f;
buffer_[buffer_pos_ + 1] = (buffer_[buffer_pos_ + 1] + buffer_[(buffer_pos_ + 2) % size + 1]) / 2.f;
data[i + 0] = buffer_[buffer_pos_ + 0];
data[i + 1] = buffer_[buffer_pos_ + 1];
samples[i + 0] = buffer_[buffer_pos_ + 0];
samples[i + 1] = buffer_[buffer_pos_ + 1];
buffer_pos_ += 2;
buffer_pos_ %= size;
}
return sample_count;
return samples.size();
}
std::size_t played() const override