#include #include #include #include namespace psemek::audio { namespace { struct mixer_impl final : mixer , std::enable_shared_from_this { channel_ptr add(stream_ptr stream) override; std::size_t read(float * data, std::size_t sample_count) override; std::optional length() const override { return std::nullopt; } private: std::vector channels_; std::vector alive_channels_; std::vector buffer_; std::mutex new_channels_mutex_; std::vector new_channels_; }; channel_ptr mixer_impl::add(stream_ptr stream) { auto result = std::make_shared(std::move(stream)); { std::lock_guard lock{new_channels_mutex_}; new_channels_.push_back(result); } return result; } std::size_t mixer_impl::read(float * data, std::size_t sample_count) { { std::vector new_channels; { std::lock_guard lock{new_channels_mutex_}; new_channels = std::move(new_channels_); } for (auto & ch : new_channels) channels_.push_back(std::move(ch)); } std::fill(data, data + sample_count, 0.f); buffer_.resize(sample_count); for (auto & ch : channels_) { auto stream = ch->stream(); if (!stream) continue; auto read = stream->read(buffer_.data(), sample_count); { auto begin = buffer_.data(); auto end = begin + read; auto dst = data; for (; begin < end; ) *dst++ += *begin++; } if (read < sample_count) { ch->stop(); continue; } alive_channels_.push_back(std::move(ch)); } std::swap(channels_, alive_channels_); alive_channels_.clear(); return sample_count; } } mixer_ptr make_mixer() { return std::make_shared(); } }