summaryrefslogtreecommitdiff
path: root/src/audio
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-08-16 15:11:30 +1000
committerjacqueline <me@jacqueline.id.au>2023-08-16 15:11:44 +1000
commitf3c5eec0251ec98f90d324c88d3519de2e6ee5e0 (patch)
tree90cd471dd980c77440e1b901dd5c6c91492d27d6 /src/audio
parentc635d5011c37c02246135fe0df404631ec111bd6 (diff)
downloadtangara-fw-f3c5eec0251ec98f90d324c88d3519de2e6ee5e0.tar.gz
Rename the main audio tasks to be more sensible
Diffstat (limited to 'src/audio')
-rw-r--r--src/audio/CMakeLists.txt4
-rw-r--r--src/audio/audio_converter.cpp (renamed from src/audio/sink_mixer.cpp)20
-rw-r--r--src/audio/audio_decoder.cpp (renamed from src/audio/audio_task.cpp)31
-rw-r--r--src/audio/audio_fsm.cpp15
-rw-r--r--src/audio/include/audio_converter.hpp (renamed from src/audio/include/sink_mixer.hpp)18
-rw-r--r--src/audio/include/audio_decoder.hpp (renamed from src/audio/include/audio_task.hpp)24
-rw-r--r--src/audio/include/audio_fsm.hpp6
7 files changed, 66 insertions, 52 deletions
diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt
index de6c9b64..df5622f5 100644
--- a/src/audio/CMakeLists.txt
+++ b/src/audio/CMakeLists.txt
@@ -3,8 +3,8 @@
# SPDX-License-Identifier: GPL-3.0-only
idf_component_register(
- SRCS "audio_task.cpp" "fatfs_audio_input.cpp" "i2s_audio_output.cpp"
- "track_queue.cpp" "audio_fsm.cpp" "sink_mixer.cpp" "resample.cpp"
+ SRCS "audio_decoder.cpp" "fatfs_audio_input.cpp" "i2s_audio_output.cpp"
+ "track_queue.cpp" "audio_fsm.cpp" "audio_converter.cpp" "resample.cpp"
"fatfs_source.cpp" "bt_audio_output.cpp"
INCLUDE_DIRS "include"
REQUIRES "codecs" "drivers" "cbor" "result" "tasks" "span" "memory" "tinyfsm"
diff --git a/src/audio/sink_mixer.cpp b/src/audio/audio_converter.cpp
index ad7198dc..c540d821 100644
--- a/src/audio/sink_mixer.cpp
+++ b/src/audio/audio_converter.cpp
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: GPL-3.0-only
*/
-#include "sink_mixer.hpp"
+#include "audio_converter.hpp"
#include <algorithm>
#include <cmath>
@@ -28,7 +28,7 @@ static constexpr std::size_t kSampleBufferLength = 240 * 2;
namespace audio {
-SinkMixer::SinkMixer()
+SampleConverter::SampleConverter()
: commands_(xQueueCreate(1, sizeof(Args))),
resampler_(nullptr),
source_(xStreamBufferCreateWithCaps(kSourceBufferLength,
@@ -49,21 +49,21 @@ SinkMixer::SinkMixer()
tasks::StartPersistent<tasks::Type::kMixer>([&]() { Main(); });
}
-SinkMixer::~SinkMixer() {
+SampleConverter::~SampleConverter() {
vQueueDelete(commands_);
vStreamBufferDelete(source_);
}
-auto SinkMixer::SetOutput(std::shared_ptr<IAudioOutput> output) -> void {
+auto SampleConverter::SetOutput(std::shared_ptr<IAudioOutput> output) -> void {
// FIXME: We should add synchronisation here, but we should be careful about
// not impacting performance given that the output will change only very
// rarely (if ever).
sink_ = output;
}
-auto SinkMixer::MixAndSend(cpp::span<sample::Sample> input,
- const IAudioOutput::Format& format,
- bool is_eos) -> void {
+auto SampleConverter::ConvertSamples(cpp::span<sample::Sample> input,
+ const IAudioOutput::Format& format,
+ bool is_eos) -> void {
Args args{
.format = format,
.samples_available = input.size(),
@@ -81,7 +81,7 @@ auto SinkMixer::MixAndSend(cpp::span<sample::Sample> input,
}
}
-auto SinkMixer::Main() -> void {
+auto SampleConverter::Main() -> void {
for (;;) {
Args args;
while (!xQueueReceive(commands_, &args, portMAX_DELAY)) {
@@ -149,8 +149,8 @@ auto SinkMixer::Main() -> void {
}
}
-auto SinkMixer::HandleSamples(cpp::span<sample::Sample> input, bool is_eos)
- -> size_t {
+auto SampleConverter::HandleSamples(cpp::span<sample::Sample> input,
+ bool is_eos) -> size_t {
if (source_format_ == target_format_) {
// The happiest possible case: the input format matches the output
// format already.
diff --git a/src/audio/audio_task.cpp b/src/audio/audio_decoder.cpp
index 99b1c170..03f81124 100644
--- a/src/audio/audio_task.cpp
+++ b/src/audio/audio_decoder.cpp
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: GPL-3.0-only
*/
-#include "audio_task.hpp"
+#include "audio_decoder.hpp"
#include <cstdint>
#include <cstdlib>
@@ -28,6 +28,7 @@
#include "freertos/ringbuf.h"
#include "span.hpp"
+#include "audio_converter.hpp"
#include "audio_events.hpp"
#include "audio_fsm.hpp"
#include "audio_sink.hpp"
@@ -36,7 +37,6 @@
#include "event_queue.hpp"
#include "fatfs_audio_input.hpp"
#include "sample.hpp"
-#include "sink_mixer.hpp"
#include "tasks.hpp"
#include "track.hpp"
#include "types.hpp"
@@ -76,23 +76,27 @@ auto Timer::AddSamples(std::size_t samples) -> void {
}
}
-auto AudioTask::Start(std::shared_ptr<IAudioSource> source,
- std::shared_ptr<SinkMixer> sink) -> AudioTask* {
- AudioTask* task = new AudioTask(source, sink);
+auto Decoder::Start(std::shared_ptr<IAudioSource> source,
+ std::shared_ptr<SampleConverter> sink) -> Decoder* {
+ Decoder* task = new Decoder(source, sink);
tasks::StartPersistent<tasks::Type::kAudio>([=]() { task->Main(); });
return task;
}
-AudioTask::AudioTask(std::shared_ptr<IAudioSource> source,
- std::shared_ptr<SinkMixer> mixer)
- : source_(source), mixer_(mixer), codec_(), timer_(), current_format_() {
+Decoder::Decoder(std::shared_ptr<IAudioSource> source,
+ std::shared_ptr<SampleConverter> mixer)
+ : source_(source),
+ converter_(mixer),
+ codec_(),
+ timer_(),
+ current_format_() {
codec_buffer_ = {
reinterpret_cast<sample::Sample*>(heap_caps_calloc(
kCodecBufferLength, sizeof(sample::Sample), MALLOC_CAP_SPIRAM)),
kCodecBufferLength};
}
-void AudioTask::Main() {
+void Decoder::Main() {
for (;;) {
if (source_->HasNewStream() || !stream_) {
std::shared_ptr<codecs::IStream> new_stream = source_->NextStream();
@@ -110,7 +114,7 @@ void AudioTask::Main() {
}
}
-auto AudioTask::BeginDecoding(std::shared_ptr<codecs::IStream> stream) -> bool {
+auto Decoder::BeginDecoding(std::shared_ptr<codecs::IStream> stream) -> bool {
codec_.reset(codecs::CreateCodecForType(stream->type()).value_or(nullptr));
if (!codec_) {
ESP_LOGE(kTag, "no codec found");
@@ -140,15 +144,16 @@ auto AudioTask::BeginDecoding(std::shared_ptr<codecs::IStream> stream) -> bool {
return true;
}
-auto AudioTask::ContinueDecoding() -> bool {
+auto Decoder::ContinueDecoding() -> bool {
auto res = codec_->DecodeTo(codec_buffer_);
if (res.has_error()) {
return true;
}
if (res->samples_written > 0) {
- mixer_->MixAndSend(codec_buffer_.first(res->samples_written),
- current_sink_format_.value(), res->is_stream_finished);
+ converter_->ConvertSamples(codec_buffer_.first(res->samples_written),
+ current_sink_format_.value(),
+ res->is_stream_finished);
}
if (timer_) {
diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp
index 1ea670af..e68eedaf 100644
--- a/src/audio/audio_fsm.cpp
+++ b/src/audio/audio_fsm.cpp
@@ -15,8 +15,9 @@
#include "freertos/portmacro.h"
#include "freertos/projdefs.h"
+#include "audio_converter.hpp"
+#include "audio_decoder.hpp"
#include "audio_events.hpp"
-#include "audio_task.hpp"
#include "bluetooth.hpp"
#include "bt_audio_output.hpp"
#include "event_queue.hpp"
@@ -24,7 +25,6 @@
#include "future_fetcher.hpp"
#include "i2s_audio_output.hpp"
#include "i2s_dac.hpp"
-#include "sink_mixer.hpp"
#include "system_events.hpp"
#include "track.hpp"
#include "track_queue.hpp"
@@ -37,10 +37,9 @@ drivers::IGpios* AudioState::sIGpios;
std::shared_ptr<drivers::I2SDac> AudioState::sDac;
std::weak_ptr<database::Database> AudioState::sDatabase;
-std::unique_ptr<AudioTask> AudioState::sTask;
-
std::shared_ptr<FatfsAudioInput> AudioState::sFileSource;
-std::shared_ptr<SinkMixer> AudioState::sMixer;
+std::unique_ptr<Decoder> AudioState::sDecoder;
+std::shared_ptr<SampleConverter> AudioState::sSampleConverter;
std::shared_ptr<IAudioOutput> AudioState::sOutput;
TrackQueue* AudioState::sTrackQueue;
@@ -65,10 +64,10 @@ auto AudioState::Init(drivers::IGpios* gpio_expander,
sOutput.reset(new I2SAudioOutput(sIGpios, sDac));
// sOutput.reset(new BluetoothAudioOutput(bluetooth));
- sMixer.reset(new SinkMixer());
- sMixer->SetOutput(sOutput);
+ sSampleConverter.reset(new SampleConverter());
+ sSampleConverter->SetOutput(sOutput);
- AudioTask::Start(sFileSource, sMixer);
+ Decoder::Start(sFileSource, sSampleConverter);
return true;
}
diff --git a/src/audio/include/sink_mixer.hpp b/src/audio/include/audio_converter.hpp
index d046f835..81532969 100644
--- a/src/audio/include/sink_mixer.hpp
+++ b/src/audio/include/audio_converter.hpp
@@ -18,19 +18,21 @@
namespace audio {
/*
- * Handles the final downmix + resample + quantisation stage of audio,
- * generation sending the result directly to an IAudioOutput.
+ * 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 SinkMixer {
+class SampleConverter {
public:
- SinkMixer();
- ~SinkMixer();
+ SampleConverter();
+ ~SampleConverter();
auto SetOutput(std::shared_ptr<IAudioOutput>) -> void;
- auto MixAndSend(cpp::span<sample::Sample>,
- const IAudioOutput::Format& format,
- bool is_eos) -> void;
+ auto ConvertSamples(cpp::span<sample::Sample>,
+ const IAudioOutput::Format& format,
+ bool is_eos) -> void;
private:
auto Main() -> void;
diff --git a/src/audio/include/audio_task.hpp b/src/audio/include/audio_decoder.hpp
index 08c5769c..1759f6e4 100644
--- a/src/audio/include/audio_task.hpp
+++ b/src/audio/include/audio_decoder.hpp
@@ -9,15 +9,18 @@
#include <cstdint>
#include <memory>
+#include "audio_converter.hpp"
#include "audio_sink.hpp"
#include "audio_source.hpp"
#include "codec.hpp"
-#include "sink_mixer.hpp"
#include "track.hpp"
#include "types.hpp"
namespace audio {
+/*
+ * Sample-based timer for the current elapsed playback time.
+ */
class Timer {
public:
Timer(const codecs::ICodec::OutputFormat& format);
@@ -32,25 +35,30 @@ class Timer {
uint32_t total_duration_seconds_;
};
-class AudioTask {
+/*
+ * Handle to a persistent task that takes bytes from the given source, decodes
+ * them into sample::Sample (normalised to 16 bit signed PCM), and then
+ * forwards the resulting stream to the given converter.
+ */
+class Decoder {
public:
static auto Start(std::shared_ptr<IAudioSource> source,
- std::shared_ptr<SinkMixer> mixer) -> AudioTask*;
+ std::shared_ptr<SampleConverter> converter) -> Decoder*;
auto Main() -> void;
- AudioTask(const AudioTask&) = delete;
- AudioTask& operator=(const AudioTask&) = delete;
+ Decoder(const Decoder&) = delete;
+ Decoder& operator=(const Decoder&) = delete;
private:
- AudioTask(std::shared_ptr<IAudioSource> source,
- std::shared_ptr<SinkMixer> mixer);
+ Decoder(std::shared_ptr<IAudioSource> source,
+ std::shared_ptr<SampleConverter> converter);
auto BeginDecoding(std::shared_ptr<codecs::IStream>) -> bool;
auto ContinueDecoding() -> bool;
std::shared_ptr<IAudioSource> source_;
- std::shared_ptr<SinkMixer> mixer_;
+ std::shared_ptr<SampleConverter> converter_;
std::shared_ptr<codecs::IStream> stream_;
std::unique_ptr<codecs::ICodec> codec_;
diff --git a/src/audio/include/audio_fsm.hpp b/src/audio/include/audio_fsm.hpp
index 6c785426..430bc298 100644
--- a/src/audio/include/audio_fsm.hpp
+++ b/src/audio/include/audio_fsm.hpp
@@ -13,8 +13,8 @@
#include "audio_sink.hpp"
#include "tinyfsm.hpp"
+#include "audio_decoder.hpp"
#include "audio_events.hpp"
-#include "audio_task.hpp"
#include "bt_audio_output.hpp"
#include "database.hpp"
#include "display.hpp"
@@ -68,9 +68,9 @@ class AudioState : public tinyfsm::Fsm<AudioState> {
static std::shared_ptr<drivers::I2SDac> sDac;
static std::weak_ptr<database::Database> sDatabase;
- static std::unique_ptr<AudioTask> sTask;
static std::shared_ptr<FatfsAudioInput> sFileSource;
- static std::shared_ptr<SinkMixer> sMixer;
+ static std::unique_ptr<Decoder> sDecoder;
+ static std::shared_ptr<SampleConverter> sSampleConverter;
static std::shared_ptr<IAudioOutput> sOutput;
static TrackQueue* sTrackQueue;