Fork of Tangara with customizations
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
tangara-fw/src/tangara/audio/processor.hpp

130 lines
3.6 KiB

/*
* Copyright 2023 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#pragma once
#include <stdint.h>
#include <cstdint>
#include <functional>
#include <list>
#include <memory>
#include "audio/audio_events.hpp"
#include "audio/audio_sink.hpp"
#include "audio/audio_source.hpp"
#include "audio/resample.hpp"
#include "codec.hpp"
#include "drivers/pcm_buffer.hpp"
#include "sample.hpp"
namespace audio {
/* Utility for managing buffering samples between digital filters. */
class Buffer {
public:
Buffer(std::span<sample::Sample> storage);
Buffer();
~Buffer();
/* Returns a span of the unused space within the buffer. */
auto writeAcquire() -> std::span<sample::Sample>;
/* Signals how many samples were just added to the writeAcquire span. */
auto writeCommit(size_t) -> void;
/* Returns a span of the samples stored within the buffer. */
auto readAcquire() -> std::span<sample::Sample>;
/* Signals how many samples from the readAcquire span were consumed. */
auto readCommit(size_t) -> void;
auto isEmpty() -> bool;
auto clear() -> void;
Buffer(const Buffer&) = delete;
Buffer& operator=(const Buffer&) = delete;
private:
sample::Sample* storage_;
std::span<sample::Sample> buffer_;
std::span<sample::Sample> samples_in_buffer_;
};
/*
* Handle to a persistent task that converts samples between formats (sample
* rate, channels, bits per sample), in order to put samples in the preferred
* format of the current output device. The resulting samples are forwarded
* to the output device's sink stream.
*/
class SampleProcessor {
public:
SampleProcessor(drivers::PcmBuffer& sink);
~SampleProcessor();
auto SetOutput(std::shared_ptr<IAudioOutput>) -> void;
/*
* Signals to the sample processor that a new discrete stream of audio is now
* being sent. This will typically represent a new track being played.
*/
auto beginStream(std::shared_ptr<TrackInfo>) -> void;
/*
* Sends a span of PCM samples to the processor. Returns a subspan of the
* given span containing samples that were not able to be sent during this
* call, e.g. because of congestion downstream from the processor.
*/
auto continueStream(std::span<sample::Sample>) -> std::span<sample::Sample>;
/*
* Signals to the sample processor that the current stream is ending. This
* can either be because the stream has naturally finished, or because it is
* being interrupted.
* If `cancelled` is false, the sample processor will ensure all previous
* samples are processed and sent before communicating the end of the stream
* onwards. If `cancelled` is true, any samples from the current stream that
* have not yet been played will be discarded.
*/
auto endStream(bool cancelled) -> void;
SampleProcessor(const SampleProcessor&) = delete;
SampleProcessor& operator=(const SampleProcessor&) = delete;
private:
auto Main() -> void;
auto handleBeginStream(std::shared_ptr<TrackInfo>) -> void;
auto handleEndStream(bool cancel) -> void;
auto processSamples(bool finalise) -> bool;
auto hasPendingWork() -> bool;
auto flushOutputBuffer() -> bool;
struct Args {
std::shared_ptr<TrackInfo>* track;
size_t samples_available;
bool is_end_of_stream;
bool clear_buffers;
};
QueueHandle_t commands_;
std::list<Args> pending_commands_;
auto discardCommand(Args& command) -> void;
StreamBufferHandle_t source_;
drivers::PcmBuffer& sink_;
Buffer input_buffer_;
Buffer resampled_buffer_;
Buffer output_buffer_;
std::unique_ptr<Resampler> resampler_;
bool double_samples_;
std::shared_ptr<IAudioOutput> output_;
size_t unprocessed_samples_;
};
} // namespace audio