psemek/libs/audio/source/recorder.cpp

92 lines
2 KiB
C++

#include <psemek/audio/recorder.hpp>
#include <vector>
namespace psemek::audio
{
namespace
{
struct recorder_impl
: recorder
{
recorder_impl()
: channel_(std::make_shared<audio::channel>())
{}
channel_ptr channel() override
{
return channel_;
}
std::size_t request(std::size_t sample_count) override
{
std::size_t count = 0;
if (storage_.size() < samples_.size() + sample_count)
{
storage_.resize(std::max<std::size_t>(samples_.size() + sample_count, storage_.size() * 2));
samples_ = {storage_.data(), storage_.data() + samples_.size()};
}
if (auto stream = channel_->stream())
{
count = stream->read({storage_.data() + samples_.size(), sample_count});
if (count < sample_count)
channel_->stop();
}
std::fill(storage_.data() + samples_.size() + count, storage_.data() + samples_.size() + sample_count, 0.f);
samples_ = {storage_.data(), storage_.data() + samples_.size() + sample_count};
return sample_count;
}
util::span<float const> buffer() const override
{
return samples_;
}
std::vector<float> grab_buffer() override
{
storage_.resize(samples_.size());
samples_ = {};
return std::move(storage_);
}
private:
channel_ptr channel_;
std::vector<float> storage_;
util::span<float const> samples_;
};
}
std::shared_ptr<recorder> make_recorder()
{
return std::make_shared<recorder_impl>();
}
std::shared_ptr<recorder> make_recorder(stream_ptr stream)
{
auto recorder = make_recorder();
recorder->channel()->stream(std::move(stream));
return recorder;
}
std::shared_ptr<track> record(stream_ptr stream)
{
if (!stream->length())
throw std::runtime_error("cannot record an infinite stream");
return record(stream, *stream->length());
}
std::shared_ptr<track> record(stream_ptr stream, duration duration)
{
auto recorder = make_recorder(std::move(stream));
recorder->request(duration.samples());
return load_raw(recorder->grab_buffer());
}
}