From 2209648999196759eceb8a5745f0a66770690da1 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Tue, 10 Jan 2023 03:35:34 +0300 Subject: [PATCH] Audio library refactor: use spans for stream->read --- .../psemek/audio/effect/volume_base.hpp | 2 +- libs/audio/include/psemek/audio/stream.hpp | 4 +++- .../include/psemek/audio/wave/generator.hpp | 9 ++++--- libs/audio/source/duplicate.cpp | 10 ++++---- libs/audio/source/effect/compressor.cpp | 14 +++++------ libs/audio/source/effect/concat.cpp | 7 +++--- libs/audio/source/effect/distortion.cpp | 10 ++++---- libs/audio/source/effect/fade_in.cpp | 18 +++++++------- libs/audio/source/effect/fade_out.cpp | 8 +++---- libs/audio/source/effect/filter.cpp | 12 +++++----- libs/audio/source/effect/loop.cpp | 16 ++++++------- libs/audio/source/effect/pause.cpp | 24 +++++++++---------- libs/audio/source/effect/pitch.cpp | 22 ++++++++--------- libs/audio/source/effect/truncate.cpp | 7 +++--- libs/audio/source/effect/volume.cpp | 16 ++++++------- libs/audio/source/effect/volume_base.cpp | 5 ++-- libs/audio/source/engine.cpp | 2 +- libs/audio/source/mixer.cpp | 24 +++++++------------ libs/audio/source/recorder.cpp | 6 ++--- libs/audio/source/stereo.cpp | 12 +++++----- libs/audio/source/track_mp3.cpp | 16 ++++++------- libs/audio/source/wave/karplus_strong.cpp | 10 ++++---- 22 files changed, 124 insertions(+), 130 deletions(-) diff --git a/libs/audio/include/psemek/audio/effect/volume_base.hpp b/libs/audio/include/psemek/audio/effect/volume_base.hpp index 330b0ff1..85796c1c 100644 --- a/libs/audio/include/psemek/audio/effect/volume_base.hpp +++ b/libs/audio/include/psemek/audio/effect/volume_base.hpp @@ -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 samples); private: std::atomic gain_[2]; diff --git a/libs/audio/include/psemek/audio/stream.hpp b/libs/audio/include/psemek/audio/stream.hpp index 9f41ad8c..5c0c864c 100644 --- a/libs/audio/include/psemek/audio/stream.hpp +++ b/libs/audio/include/psemek/audio/stream.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -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 samples) = 0; // The number of samples already played from this stream virtual std::size_t played() const = 0; diff --git a/libs/audio/include/psemek/audio/wave/generator.hpp b/libs/audio/include/psemek/audio/wave/generator.hpp index dbb70f63..d93692dd 100644 --- a/libs/audio/include/psemek/audio/wave/generator.hpp +++ b/libs/audio/include/psemek/audio/wave/generator.hpp @@ -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 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: diff --git a/libs/audio/source/duplicate.cpp b/libs/audio/source/duplicate.cpp index 0f2d6362..6219e694 100644 --- a/libs/audio/source/duplicate.cpp +++ b/libs/audio/source/duplicate.cpp @@ -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 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(sample_count, buffer.size() - played); - std::copy(buffer.data() + played, buffer.data() + played + count, data); + auto count = std::min(samples.size(), buffer.size() - played); + std::copy(buffer.data() + played, buffer.data() + played + count, samples.begin()); played_.fetch_add(count); return count; } diff --git a/libs/audio/source/effect/compressor.cpp b/libs/audio/source/effect/compressor.cpp index 5d3552bc..0478027f 100644 --- a/libs/audio/source/effect/compressor.cpp +++ b/libs/audio/source/effect/compressor.cpp @@ -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 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 diff --git a/libs/audio/source/effect/concat.cpp b/libs/audio/source/effect/concat.cpp index 75c1709c..4497a2a9 100644 --- a/libs/audio/source/effect/concat.cpp +++ b/libs/audio/source/effect/concat.cpp @@ -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 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; } diff --git a/libs/audio/source/effect/distortion.cpp b/libs/audio/source/effect/distortion.cpp index f8a0be5d..83932d82 100644 --- a/libs/audio/source/effect/distortion.cpp +++ b/libs/audio/source/effect/distortion.cpp @@ -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 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 diff --git a/libs/audio/source/effect/fade_in.cpp b/libs/audio/source/effect/fade_in.cpp index ab964526..777ecd7b 100644 --- a/libs/audio/source/effect/fade_in.cpp +++ b/libs/audio/source/effect/fade_in.cpp @@ -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 samples) override { - auto const result = stream_->read(data, sample_count); - std::fill(data, data + std::min(result, start_.samples()), 0.f); + auto const count = stream_->read(samples); + std::fill(samples.begin(), samples.begin() + std::min(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(std::min(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: diff --git a/libs/audio/source/effect/fade_out.cpp b/libs/audio/source/effect/fade_out.cpp index 5f8be759..335995f8 100644 --- a/libs/audio/source/effect/fade_out.cpp +++ b/libs/audio/source/effect/fade_out.cpp @@ -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 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(length_.samples() - std::min(current_, length_.samples())) / length_.samples(); - data[i + 0] *= m; - data[i + 1] *= m; + samples[i + 0] *= m; + samples[i + 1] *= m; current_ += 2; } diff --git a/libs/audio/source/effect/filter.cpp b/libs/audio/source/effect/filter.cpp index 5ed8d9f4..8d5892e9 100644 --- a/libs/audio/source/effect/filter.cpp +++ b/libs/audio/source/effect/filter.cpp @@ -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 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; diff --git a/libs/audio/source/effect/loop.cpp b/libs/audio/source/effect/loop.cpp index a4f4ccd5..b4e356c9 100644 --- a/libs/audio/source/effect/loop.cpp +++ b/libs/audio/source/effect/loop.cpp @@ -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 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 diff --git a/libs/audio/source/effect/pause.cpp b/libs/audio/source/effect/pause.cpp index 5ac8eba0..402e496a 100644 --- a/libs/audio/source/effect/pause.cpp +++ b/libs/audio/source/effect/pause.cpp @@ -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 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(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(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(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; } } diff --git a/libs/audio/source/effect/pitch.cpp b/libs/audio/source/effect/pitch.cpp index c8d7fde1..c3b2dbdf 100644 --- a/libs/audio/source/effect/pitch.cpp +++ b/libs/audio/source/effect/pitch.cpp @@ -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 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(sample_count, std::ceil(resampler_.ratio() * sample_count / 2.f) * 2); + std::size_t request_size = std::max(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 diff --git a/libs/audio/source/effect/truncate.cpp b/libs/audio/source/effect/truncate.cpp index c9e522b7..2c98aa5e 100644 --- a/libs/audio/source/effect/truncate.cpp +++ b/libs/audio/source/effect/truncate.cpp @@ -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 samples) override { auto played = stream_->played(); - auto result = std::min(length_.samples() - played, sample_count); - result = stream_->read(data, result); - return result; + auto max_count = std::min(length_.samples() - played, samples.size()); + return stream_->read(samples.prefix(max_count)); } std::size_t played() const override diff --git a/libs/audio/source/effect/volume.cpp b/libs/audio/source/effect/volume.cpp index 2beacbc8..edb681c6 100644 --- a/libs/audio/source/effect/volume.cpp +++ b/libs/audio/source/effect/volume.cpp @@ -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 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 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: diff --git a/libs/audio/source/effect/volume_base.cpp b/libs/audio/source/effect/volume_base.cpp index e3cf902e..e050cf79 100644 --- a/libs/audio/source/effect/volume_base.cpp +++ b/libs/audio/source/effect/volume_base.cpp @@ -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 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]; diff --git a/libs/audio/source/engine.cpp b/libs/audio/source/engine.cpp index 91acc037..f8b47060 100644 --- a/libs/audio/source/engine.cpp +++ b/libs/audio/source/engine.cpp @@ -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) diff --git a/libs/audio/source/mixer.cpp b/libs/audio/source/mixer.cpp index ce9e0a40..146dab97 100644 --- a/libs/audio/source/mixer.cpp +++ b/libs/audio/source/mixer.cpp @@ -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 samples) override; std::optional 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 samples) { { std::vector 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(); } } diff --git a/libs/audio/source/recorder.cpp b/libs/audio/source/recorder.cpp index 6300c914..74e76f2b 100644 --- a/libs/audio/source/recorder.cpp +++ b/libs/audio/source/recorder.cpp @@ -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 buffer() const override diff --git a/libs/audio/source/stereo.cpp b/libs/audio/source/stereo.cpp index 32bc9d13..c6671c78 100644 --- a/libs/audio/source/stereo.cpp +++ b/libs/audio/source/stereo.cpp @@ -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 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; } diff --git a/libs/audio/source/track_mp3.cpp b/libs/audio/source/track_mp3.cpp index 832564c5..dc98dc82 100644 --- a/libs/audio/source/track_mp3.cpp +++ b/libs/audio/source/track_mp3.cpp @@ -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 samples) override { auto input = reinterpret_cast(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 diff --git a/libs/audio/source/wave/karplus_strong.cpp b/libs/audio/source/wave/karplus_strong.cpp index 31dd683e..26641cff 100644 --- a/libs/audio/source/wave/karplus_strong.cpp +++ b/libs/audio/source/wave/karplus_strong.cpp @@ -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 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