From 5f7444d7956a6cc517ada1b8b96c4f9cdd408fd5 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Mon, 21 Nov 2022 08:00:52 +1100 Subject: WIP --- src/audio/CMakeLists.txt | 6 ++ src/audio/i2s_audio_output.cpp | 114 +++++++++++++++++++++++++++++++ src/audio/include/i2s_audio_output.hpp | 32 +++++++++ src/codecs/include/codec.hpp | 29 ++++++++ src/drivers/i2s_audio_output.cpp | 114 ------------------------------- src/drivers/include/i2s_audio_output.hpp | 34 --------- src/main/app_console.cpp | 12 ++-- src/main/app_console.hpp | 8 +-- src/main/main.cpp | 8 +-- 9 files changed, 194 insertions(+), 163 deletions(-) create mode 100644 src/audio/CMakeLists.txt create mode 100644 src/audio/i2s_audio_output.cpp create mode 100644 src/audio/include/i2s_audio_output.hpp create mode 100644 src/codecs/include/codec.hpp delete mode 100644 src/drivers/i2s_audio_output.cpp delete mode 100644 src/drivers/include/i2s_audio_output.hpp (limited to 'src') diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt new file mode 100644 index 00000000..d98484c6 --- /dev/null +++ b/src/audio/CMakeLists.txt @@ -0,0 +1,6 @@ +idf_component_register( + SRCS "audio_decoder.cpp" "fatfs_audio_input.cpp" "audio_task.cpp" + INCLUDE_DIRS "include" + REQUIRES "codecs" "drivers") + +target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/audio/i2s_audio_output.cpp b/src/audio/i2s_audio_output.cpp new file mode 100644 index 00000000..77d01b6a --- /dev/null +++ b/src/audio/i2s_audio_output.cpp @@ -0,0 +1,114 @@ +#include "i2s_audio_output.hpp" + +#include + +#include "audio_element.h" +#include "driver/i2s.h" +#include "esp_err.h" +#include "freertos/portmacro.h" +#include "i2s_stream.h" + +static const i2s_port_t kI2SPort = I2S_NUM_0; +static const char* kTag = "I2SOUT"; + +namespace drivers { + +auto I2SAudioOutput::create(GpioExpander* expander) + -> cpp::result, Error> { + // First, we need to perform initial configuration of the DAC chip. + auto dac_result = drivers::AudioDac::create(expander); + if (dac_result.has_error()) { + ESP_LOGE(kTag, "failed to init dac: %d", dac_result.error()); + return cpp::fail(DAC_CONFIG); + } + std::unique_ptr dac = std::move(dac_result.value()); + + // Soft mute immediately, in order to minimise any clicks and pops caused by + // the initial output element and pipeline configuration. + dac->WriteVolume(255); + + i2s_stream_cfg_t i2s_stream_config = i2s_stream_cfg_t{ + .type = AUDIO_STREAM_WRITER, + .i2s_config = + { + // static_cast bc esp-adf uses enums incorrectly + .mode = static_cast(I2S_MODE_MASTER | I2S_MODE_TX), + .sample_rate = 44100, + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .intr_alloc_flags = ESP_INTR_FLAG_LOWMED, + .dma_buf_count = 8, + .dma_buf_len = 64, + .use_apll = false, + .tx_desc_auto_clear = false, + .fixed_mclk = 0, + .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, + .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, + }, + .i2s_port = kI2SPort, + .use_alc = false, + .volume = 0, // Does nothing; use AudioDac to change this. + .out_rb_size = I2S_STREAM_RINGBUFFER_SIZE, + .task_stack = I2S_STREAM_TASK_STACK, + .task_core = I2S_STREAM_TASK_CORE, + .task_prio = I2S_STREAM_TASK_PRIO, + .stack_in_ext = false, + .multi_out_num = 0, + .uninstall_drv = true, + .need_expand = false, + .expand_src_bits = I2S_BITS_PER_SAMPLE_16BIT, + }; + audio_element_handle_t i2s_stream_writer = + i2s_stream_init(&i2s_stream_config); + if (i2s_stream_writer == NULL) { + return cpp::fail(Error::STREAM_INIT); + } + + // NOTE: i2s_stream_init does some additional setup that hardcodes MCK as + // GPIO0. This happens to work fine for us, but be careful if changing. + i2s_pin_config_t pin_config = {.mck_io_num = GPIO_NUM_0, + .bck_io_num = GPIO_NUM_26, + .ws_io_num = GPIO_NUM_27, + .data_out_num = GPIO_NUM_5, + .data_in_num = I2S_PIN_NO_CHANGE}; + if (esp_err_t err = i2s_set_pin(kI2SPort, &pin_config) != ESP_OK) { + ESP_LOGE(kTag, "failed to configure i2s pins %x", err); + return cpp::fail(Error::I2S_CONFIG); + } + + return std::make_unique(dac, i2s_stream_writer); +} + +I2SAudioOutput::I2SAudioOutput(std::unique_ptr& dac, + audio_element_handle_t element) + : IAudioOutput(element), dac_(std::move(dac)) { + volume_ = 255; +} +I2SAudioOutput::~I2SAudioOutput() { + // TODO: power down the DAC. +} + +auto I2SAudioOutput::SetVolume(uint8_t volume) -> void { + volume_ = volume; + if (!is_soft_muted_) { + dac_->WriteVolume(volume); + } +} + +auto I2SAudioOutput::SetSoftMute(bool enabled) -> void { + if (enabled) { + is_soft_muted_ = true; + dac_->WriteVolume(255); + } else { + is_soft_muted_ = false; + dac_->WriteVolume(volume_); + } +} + +auto I2SAudioOutput::Configure(audio_element_info_t& info) -> void { + audio_element_setinfo(element_, &info); + i2s_stream_set_clk(element_, info.sample_rates, info.bits, info.channels); +} + +} // namespace drivers diff --git a/src/audio/include/i2s_audio_output.hpp b/src/audio/include/i2s_audio_output.hpp new file mode 100644 index 00000000..cd542f71 --- /dev/null +++ b/src/audio/include/i2s_audio_output.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include "result.hpp" + +#include "dac.hpp" +#include "gpio_expander.hpp" + +namespace drivers { + +class I2SAudioOutput : public IAudioOutput { + public: + enum Error { DAC_CONFIG, I2S_CONFIG, STREAM_INIT }; + static auto create(GpioExpander* expander) + -> cpp::result, Error>; + + I2SAudioOutput(std::unique_ptr& dac, + audio_element_handle_t element); + ~I2SAudioOutput(); + + virtual auto SetVolume(uint8_t volume) -> void; + virtual auto Configure(audio_element_info_t& info) -> void; + virtual auto SetSoftMute(bool enabled) -> void; + + private: + std::unique_ptr dac_; + bool is_soft_muted_ = false; +}; + +} // namespace drivers diff --git a/src/codecs/include/codec.hpp b/src/codecs/include/codec.hpp new file mode 100644 index 00000000..5e8763a6 --- /dev/null +++ b/src/codecs/include/codec.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +#include "result.hpp" + +namespace codecs { + + enum CreateCodecError {}; + + auto CreateCodecForExtension(std::string extension) -> cpp::result, CreateCodecError>; + + class ICodec { + public: + virtual ~ICodec() {} + + virtual auto CanHandleExtension(std::string extension) -> bool = 0; + + enum Error {}; + + virtual auto Process( + uint8_t *input, + std::size_t input_len, + uint8_t *output, + std::size_t output_length) -> cpp::result = 0; + }; + +} // namespace codecs diff --git a/src/drivers/i2s_audio_output.cpp b/src/drivers/i2s_audio_output.cpp deleted file mode 100644 index 77d01b6a..00000000 --- a/src/drivers/i2s_audio_output.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "i2s_audio_output.hpp" - -#include - -#include "audio_element.h" -#include "driver/i2s.h" -#include "esp_err.h" -#include "freertos/portmacro.h" -#include "i2s_stream.h" - -static const i2s_port_t kI2SPort = I2S_NUM_0; -static const char* kTag = "I2SOUT"; - -namespace drivers { - -auto I2SAudioOutput::create(GpioExpander* expander) - -> cpp::result, Error> { - // First, we need to perform initial configuration of the DAC chip. - auto dac_result = drivers::AudioDac::create(expander); - if (dac_result.has_error()) { - ESP_LOGE(kTag, "failed to init dac: %d", dac_result.error()); - return cpp::fail(DAC_CONFIG); - } - std::unique_ptr dac = std::move(dac_result.value()); - - // Soft mute immediately, in order to minimise any clicks and pops caused by - // the initial output element and pipeline configuration. - dac->WriteVolume(255); - - i2s_stream_cfg_t i2s_stream_config = i2s_stream_cfg_t{ - .type = AUDIO_STREAM_WRITER, - .i2s_config = - { - // static_cast bc esp-adf uses enums incorrectly - .mode = static_cast(I2S_MODE_MASTER | I2S_MODE_TX), - .sample_rate = 44100, - .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, - .intr_alloc_flags = ESP_INTR_FLAG_LOWMED, - .dma_buf_count = 8, - .dma_buf_len = 64, - .use_apll = false, - .tx_desc_auto_clear = false, - .fixed_mclk = 0, - .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, - .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, - }, - .i2s_port = kI2SPort, - .use_alc = false, - .volume = 0, // Does nothing; use AudioDac to change this. - .out_rb_size = I2S_STREAM_RINGBUFFER_SIZE, - .task_stack = I2S_STREAM_TASK_STACK, - .task_core = I2S_STREAM_TASK_CORE, - .task_prio = I2S_STREAM_TASK_PRIO, - .stack_in_ext = false, - .multi_out_num = 0, - .uninstall_drv = true, - .need_expand = false, - .expand_src_bits = I2S_BITS_PER_SAMPLE_16BIT, - }; - audio_element_handle_t i2s_stream_writer = - i2s_stream_init(&i2s_stream_config); - if (i2s_stream_writer == NULL) { - return cpp::fail(Error::STREAM_INIT); - } - - // NOTE: i2s_stream_init does some additional setup that hardcodes MCK as - // GPIO0. This happens to work fine for us, but be careful if changing. - i2s_pin_config_t pin_config = {.mck_io_num = GPIO_NUM_0, - .bck_io_num = GPIO_NUM_26, - .ws_io_num = GPIO_NUM_27, - .data_out_num = GPIO_NUM_5, - .data_in_num = I2S_PIN_NO_CHANGE}; - if (esp_err_t err = i2s_set_pin(kI2SPort, &pin_config) != ESP_OK) { - ESP_LOGE(kTag, "failed to configure i2s pins %x", err); - return cpp::fail(Error::I2S_CONFIG); - } - - return std::make_unique(dac, i2s_stream_writer); -} - -I2SAudioOutput::I2SAudioOutput(std::unique_ptr& dac, - audio_element_handle_t element) - : IAudioOutput(element), dac_(std::move(dac)) { - volume_ = 255; -} -I2SAudioOutput::~I2SAudioOutput() { - // TODO: power down the DAC. -} - -auto I2SAudioOutput::SetVolume(uint8_t volume) -> void { - volume_ = volume; - if (!is_soft_muted_) { - dac_->WriteVolume(volume); - } -} - -auto I2SAudioOutput::SetSoftMute(bool enabled) -> void { - if (enabled) { - is_soft_muted_ = true; - dac_->WriteVolume(255); - } else { - is_soft_muted_ = false; - dac_->WriteVolume(volume_); - } -} - -auto I2SAudioOutput::Configure(audio_element_info_t& info) -> void { - audio_element_setinfo(element_, &info); - i2s_stream_set_clk(element_, info.sample_rates, info.bits, info.channels); -} - -} // namespace drivers diff --git a/src/drivers/include/i2s_audio_output.hpp b/src/drivers/include/i2s_audio_output.hpp deleted file mode 100644 index ca0e6452..00000000 --- a/src/drivers/include/i2s_audio_output.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include -#include - -#include "audio_element.h" -#include "result.hpp" - -#include "audio_output.hpp" -#include "dac.hpp" -#include "gpio_expander.hpp" - -namespace drivers { - -class I2SAudioOutput : public IAudioOutput { - public: - enum Error { DAC_CONFIG, I2S_CONFIG, STREAM_INIT }; - static auto create(GpioExpander* expander) - -> cpp::result, Error>; - - I2SAudioOutput(std::unique_ptr& dac, - audio_element_handle_t element); - ~I2SAudioOutput(); - - virtual auto SetVolume(uint8_t volume) -> void; - virtual auto Configure(audio_element_info_t& info) -> void; - virtual auto SetSoftMute(bool enabled) -> void; - - private: - std::unique_ptr dac_; - bool is_soft_muted_ = false; -}; - -} // namespace drivers diff --git a/src/main/app_console.cpp b/src/main/app_console.cpp index 74225534..765b17d2 100644 --- a/src/main/app_console.cpp +++ b/src/main/app_console.cpp @@ -12,8 +12,6 @@ namespace console { -static AppConsole* sInstance = nullptr; - std::string toSdPath(std::string filepath) { return std::string(drivers::kStoragePath) + "/" + filepath; } @@ -59,10 +57,12 @@ int CmdPlayFile(int argc, char** argv) { return 1; } + /* sInstance->playback_->Play(toSdPath(argv[1])); if (argc == 3) { sInstance->playback_->SetNextFile(toSdPath(argv[2])); } + */ return 0; } @@ -83,7 +83,7 @@ int CmdToggle(int argc, char** argv) { return 1; } - sInstance->playback_->Toggle(); + //sInstance->playback_->Toggle(); return 0; } @@ -110,7 +110,7 @@ int CmdVolume(int argc, char** argv) { return 1; } - sInstance->playback_->SetVolume((uint8_t)raw_vol); + //sInstance->playback_->SetVolume((uint8_t)raw_vol); return 0; } @@ -125,12 +125,14 @@ void RegisterVolume() { esp_console_cmd_register(&cmd); } -AppConsole::AppConsole(drivers::AudioPlayback* playback) : playback_(playback) { +/* +AppConsole::AppConsole() { sInstance = this; } AppConsole::~AppConsole() { sInstance = nullptr; } +*/ auto AppConsole::RegisterExtraComponents() -> void { RegisterListDir(); diff --git a/src/main/app_console.hpp b/src/main/app_console.hpp index 0beffd76..9cd9d50c 100644 --- a/src/main/app_console.hpp +++ b/src/main/app_console.hpp @@ -2,17 +2,15 @@ #include -#include "audio_playback.hpp" +#include "storage.hpp" #include "console.hpp" namespace console { class AppConsole : public Console { public: - AppConsole(drivers::AudioPlayback* playback); - virtual ~AppConsole(); - - drivers::AudioPlayback* playback_; + AppConsole() {}; + virtual ~AppConsole() {}; protected: virtual auto RegisterExtraComponents() -> void; diff --git a/src/main/main.cpp b/src/main/main.cpp index a18e12d0..24d47e9a 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -5,9 +5,6 @@ #include #include -#include "audio_common.h" -#include "audio_element.h" -#include "audio_pipeline.h" #include "core/lv_disp.h" #include "core/lv_obj_pos.h" #include "driver/gpio.h" @@ -27,7 +24,6 @@ #include "widgets/lv_label.h" #include "app_console.hpp" -#include "audio_playback.hpp" #include "battery.hpp" #include "dac.hpp" #include "display.hpp" @@ -123,6 +119,7 @@ extern "C" void app_main(void) { } std::unique_ptr sink = std::move(sink_res.value()); + /* ESP_LOGI(TAG, "Init audio pipeline"); auto playback_res = drivers::AudioPlayback::create(std::move(sink)); if (playback_res.has_error()) { @@ -132,13 +129,14 @@ extern "C" void app_main(void) { std::unique_ptr playback = std::move(playback_res.value()); playback->SetVolume(130); + */ ESP_LOGI(TAG, "Launch console"); console::AppConsole console(playback.get()); console.Launch(); while (1) { - playback->ProcessEvents(5); + //playback->ProcessEvents(5); vTaskDelay(pdMS_TO_TICKS(100)); } } -- cgit v1.2.3