WIP initial tts player wiring

custom
jacqueline 9 months ago
parent 370d1853b5
commit 9475d10d10
  1. 6
      src/tangara/audio/audio_fsm.cpp
  2. 24
      src/tangara/tts/player.cpp
  3. 38
      src/tangara/tts/player.hpp
  4. 23
      src/tangara/tts/provider.cpp
  5. 17
      src/tangara/tts/provider.hpp

@ -43,6 +43,7 @@
#include "sample.hpp" #include "sample.hpp"
#include "system_fsm/service_locator.hpp" #include "system_fsm/service_locator.hpp"
#include "system_fsm/system_events.hpp" #include "system_fsm/system_events.hpp"
#include "tts/player.hpp"
namespace audio { namespace audio {
@ -369,6 +370,11 @@ void Uninitialised::react(const system_fsm::BootComplete& ev) {
sBtOutput.reset(new BluetoothAudioOutput( sBtOutput.reset(new BluetoothAudioOutput(
sServices->bluetooth(), *sDrainBuffers, sServices->bg_worker())); 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(); auto& nvs = sServices->nvs();
sI2SOutput->SetMaxVolume(nvs.AmpMaxVolume()); sI2SOutput->SetMaxVolume(nvs.AmpMaxVolume());
sI2SOutput->SetVolume(nvs.AmpCurrentVolume()); sI2SOutput->SetVolume(nvs.AmpCurrentVolume());

@ -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

@ -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

@ -5,21 +5,40 @@
*/ */
#include "tts/provider.hpp" #include "tts/provider.hpp"
#include <stdint.h>
#include <ios>
#include <optional> #include <optional>
#include <sstream>
#include <string> #include <string>
#include <variant> #include <variant>
#include "drivers/storage.hpp"
#include "esp_log.h" #include "esp_log.h"
#include "komihash.h"
#include "tts/events.hpp" #include "tts/events.hpp"
namespace tts { namespace tts {
[[maybe_unused]] static constexpr char kTag[] = "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() {} Provider::Provider() {}
auto Provider::player(std::unique_ptr<Player> p) -> void {
player_ = std::move(p);
}
auto Provider::feed(const Event& e) -> void { auto Provider::feed(const Event& e) -> void {
if (std::holds_alternative<SimpleEvent>(e)) { if (std::holds_alternative<SimpleEvent>(e)) {
// ESP_LOGI(kTag, "context changed"); // ESP_LOGI(kTag, "context changed");
@ -31,6 +50,10 @@ auto Provider::feed(const Event& e) -> void {
// ESP_LOGI(kTag, "new selection: '%s', interactive? %i", // ESP_LOGI(kTag, "new selection: '%s', interactive? %i",
// ev.new_selection->description.value_or("").c_str(), // ev.new_selection->description.value_or("").c_str(),
// ev.new_selection->is_interactive); // ev.new_selection->is_interactive);
std::string new_desc = ev.new_selection->description.value_or("");
if (player_) {
player_->playFile(textToFile(new_desc).value_or(""));
}
} }
} }
} }

@ -6,18 +6,35 @@
#pragma once #pragma once
#include <memory>
#include <optional> #include <optional>
#include <string> #include <string>
#include <variant> #include <variant>
#include "tts/events.hpp" #include "tts/events.hpp"
#include "tts/player.hpp"
namespace tts { 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 { class Provider {
public: public:
Provider(); Provider();
auto player(std::unique_ptr<Player>) -> void;
auto feed(const Event&) -> 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 } // namespace tts

Loading…
Cancel
Save