summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-07-19 13:59:30 +1000
committerjacqueline <me@jacqueline.id.au>2024-07-19 13:59:30 +1000
commit9475d10d1000c7e21a7ea311b0c8ee6a72ef46c4 (patch)
tree099258a8107f75f14cf5b2f451f1d4008da1dfa4 /src
parent370d1853b5d099de28c032def4ce3e53b7d735ad (diff)
downloadtangara-fw-9475d10d1000c7e21a7ea311b0c8ee6a72ef46c4.tar.gz
WIP initial tts player wiring
Diffstat (limited to 'src')
-rw-r--r--src/tangara/audio/audio_fsm.cpp6
-rw-r--r--src/tangara/tts/player.cpp24
-rw-r--r--src/tangara/tts/player.hpp38
-rw-r--r--src/tangara/tts/provider.cpp23
-rw-r--r--src/tangara/tts/provider.hpp17
5 files changed, 108 insertions, 0 deletions
diff --git a/src/tangara/audio/audio_fsm.cpp b/src/tangara/audio/audio_fsm.cpp
index ad60ab86..dbf1954c 100644
--- a/src/tangara/audio/audio_fsm.cpp
+++ b/src/tangara/audio/audio_fsm.cpp
@@ -43,6 +43,7 @@
#include "sample.hpp"
#include "system_fsm/service_locator.hpp"
#include "system_fsm/system_events.hpp"
+#include "tts/player.hpp"
namespace audio {
@@ -369,6 +370,11 @@ void Uninitialised::react(const system_fsm::BootComplete& ev) {
sBtOutput.reset(new BluetoothAudioOutput(
sServices->bluetooth(), *sDrainBuffers, sServices->bg_worker()));
+ auto& tts_provider = sServices->tts();
+ auto tts_player = std::make_unique<tts::Player>(
+ sServices->bg_worker(), sDrainBuffers->second, *sStreamFactory);
+ tts_provider.player(std::move(tts_player));
+
auto& nvs = sServices->nvs();
sI2SOutput->SetMaxVolume(nvs.AmpMaxVolume());
sI2SOutput->SetVolume(nvs.AmpCurrentVolume());
diff --git a/src/tangara/tts/player.cpp b/src/tangara/tts/player.cpp
new file mode 100644
index 00000000..70959992
--- /dev/null
+++ b/src/tangara/tts/player.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2024 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "tts/player.hpp"
+
+#include "esp_log.h"
+
+namespace tts {
+
+[[maybe_unused]] static constexpr char kTag[] = "ttsplay";
+
+Player::Player(tasks::WorkerPool& worker,
+ drivers::PcmBuffer& output,
+ audio::FatfsStreamFactory& factory)
+ : bg_(worker), stream_factory_(factory), output_(output) {}
+
+auto Player::playFile(const std::string& path) -> void {
+ ESP_LOGI(kTag, "playing '%s'", path.c_str());
+}
+
+} // namespace tts
diff --git a/src/tangara/tts/player.hpp b/src/tangara/tts/player.hpp
new file mode 100644
index 00000000..a132b9cd
--- /dev/null
+++ b/src/tangara/tts/player.hpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <string>
+
+#include "audio/fatfs_stream_factory.hpp"
+#include "drivers/pcm_buffer.hpp"
+#include "tasks.hpp"
+
+namespace tts {
+
+/*
+ * A TTS Player is the output stage of the TTS pipeline. It receives a stream
+ * of filenames that should be played, and handles decoding these files and
+ * sending them to the output buffer.
+ */
+class Player {
+ public:
+ Player(tasks::WorkerPool&, drivers::PcmBuffer&, audio::FatfsStreamFactory&);
+
+ auto playFile(const std::string& path) -> void;
+
+ // Not copyable or movable.
+ Player(const Player&) = delete;
+ Player& operator=(const Player&) = delete;
+
+ private:
+ tasks::WorkerPool& bg_;
+ audio::FatfsStreamFactory& stream_factory_;
+ drivers::PcmBuffer& output_;
+};
+
+} // namespace tts
diff --git a/src/tangara/tts/provider.cpp b/src/tangara/tts/provider.cpp
index 7d33bae6..24229233 100644
--- a/src/tangara/tts/provider.cpp
+++ b/src/tangara/tts/provider.cpp
@@ -5,21 +5,40 @@
*/
#include "tts/provider.hpp"
+#include <stdint.h>
+#include <ios>
#include <optional>
+#include <sstream>
#include <string>
#include <variant>
+#include "drivers/storage.hpp"
#include "esp_log.h"
+#include "komihash.h"
#include "tts/events.hpp"
namespace tts {
[[maybe_unused]] static constexpr char kTag[] = "tts";
+static const char* kTtsPath = "/.tangara-tts/";
+
+static auto textToFile(const std::string& text) -> std::optional<std::string> {
+ uint64_t hash = komihash(text.data(), text.size(), 0);
+ std::stringstream stream;
+ stream << drivers::kStoragePath << kTtsPath;
+ stream << std::hex << hash;
+ return stream.str();
+}
+
Provider::Provider() {}
+auto Provider::player(std::unique_ptr<Player> p) -> void {
+ player_ = std::move(p);
+}
+
auto Provider::feed(const Event& e) -> void {
if (std::holds_alternative<SimpleEvent>(e)) {
// ESP_LOGI(kTag, "context changed");
@@ -31,6 +50,10 @@ auto Provider::feed(const Event& e) -> void {
// ESP_LOGI(kTag, "new selection: '%s', interactive? %i",
// ev.new_selection->description.value_or("").c_str(),
// ev.new_selection->is_interactive);
+ std::string new_desc = ev.new_selection->description.value_or("");
+ if (player_) {
+ player_->playFile(textToFile(new_desc).value_or(""));
+ }
}
}
}
diff --git a/src/tangara/tts/provider.hpp b/src/tangara/tts/provider.hpp
index 59f61a6c..8fe143cc 100644
--- a/src/tangara/tts/provider.hpp
+++ b/src/tangara/tts/provider.hpp
@@ -6,18 +6,35 @@
#pragma once
+#include <memory>
#include <optional>
#include <string>
#include <variant>
#include "tts/events.hpp"
+#include "tts/player.hpp"
namespace tts {
+/*
+ * A TTS Provider is responsible for receiving system events that may be
+ * relevant to TTS, and digesting them into discrete 'utterances' that can be
+ * used to generate audio feedback.
+ */
class Provider {
public:
Provider();
+
+ auto player(std::unique_ptr<Player>) -> void;
+
auto feed(const Event&) -> void;
+
+ // Not copyable or movable.
+ Provider(const Provider&) = delete;
+ Provider& operator=(const Provider&) = delete;
+
+ private:
+ std::unique_ptr<Player> player_;
};
} // namespace tts