Re-enable the parts of the audio pipeline that are working

custom
jacqueline 2 years ago
parent c7901ae429
commit 8ed3d7e31f
  1. 2
      src/audio/audio_playback.cpp
  2. 9
      src/audio/fatfs_audio_input.cpp
  3. 83
      src/drivers/dac.cpp
  4. 18
      src/drivers/include/dac.hpp
  5. 5
      src/main/main.cpp

@ -43,9 +43,11 @@ auto AudioPlayback::create(drivers::GpioExpander* expander,
playback->ConnectElements(codec.get(), sink.get());
// Launch!
/*
playback->element_handles_.push_back(StartAudioTask("src", source));
playback->element_handles_.push_back(StartAudioTask("dec", codec));
playback->element_handles_.push_back(StartAudioTask("sink", sink));
*/
return playback;
}

@ -106,6 +106,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result<void, AudioProcessingError> {
read_size = file_buffer_.begin() - file_buffer_write_pos_;
}
ESP_LOGI(kTag, "reading up to %d bytes", (int) read_size);
UINT bytes_read = 0;
FRESULT result =
f_read(&current_file_, std::addressof(file_buffer_write_pos_),
@ -115,6 +117,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result<void, AudioProcessingError> {
return cpp::fail(IO_ERROR);
}
ESP_LOGI(kTag, "actual read size %d bytes", (int) bytes_read);
if (f_eof(&current_file_)) {
f_close(&current_file_);
is_file_open_ = false;
@ -130,7 +134,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result<void, AudioProcessingError> {
}
// Now stream data into the output buffer until it's full.
while (1) {
while (GetRingBufferDistance() > 0) {
ESP_LOGI(kTag, "writing up to %d bytes", (int) GetRingBufferDistance());
ChunkWriteResult result = chunk_writer_->WriteChunkToStream(
[&](cpp::span<std::byte> d) { return SendChunk(d); }, kServiceInterval);
@ -146,6 +151,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result<void, AudioProcessingError> {
return cpp::fail(IO_ERROR);
}
}
return {};
}
auto FatfsAudioInput::SendChunk(cpp::span<std::byte> dest) -> size_t {

@ -4,9 +4,9 @@
#include "assert.h"
#include "driver/i2c.h"
#include "driver/i2s.h"
#include "driver/i2s_common.h"
#include "driver/i2s_std.h"
#include "driver/i2s_types.h"
#include "driver/i2s_types_legacy.h"
#include "esp_err.h"
#include "esp_log.h"
#include "hal/i2c_types.h"
@ -28,45 +28,43 @@ static const AudioDac::BitsPerSample kDefaultBps = AudioDac::BPS_16;
auto AudioDac::create(GpioExpander* expander)
-> cpp::result<std::unique_ptr<AudioDac>, Error> {
// TODO: tune.
i2s_chan_handle_t i2s_handle;
i2s_chan_config_t channel_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
i2s_new_channel(&channel_config, &i2s_handle, NULL);
//
// First, instantiate the instance so it can do all of its power on
// configuration.
std::unique_ptr<AudioDac> dac = std::make_unique<AudioDac>(expander);
std::unique_ptr<AudioDac> dac = std::make_unique<AudioDac>(expander, i2s_handle);
// Whilst we wait for the initial boot, we can work on installing the I2S
// driver.
i2s_config_t i2s_config = {
// static_cast bc esp-adf uses enums incorrectly
.mode = static_cast<i2s_mode_t>(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,
// TODO(jacqueline): tune dma buffer size. this seems very smol.
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0,
.mclk_multiple = I2S_MCLK_MULTIPLE_512, // TODO: double check
.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
i2s_std_config_t i2s_config = {
.clk_cfg = dac->clock_config_,
.slot_cfg = dac->slot_config_,
.gpio_cfg = {
.mclk = GPIO_NUM_0,
.bclk = GPIO_NUM_26,
.ws = GPIO_NUM_27,
.dout = GPIO_NUM_5,
.din = I2S_GPIO_UNUSED,
.invert_flags = {
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false,
}
},
};
if (esp_err_t err =
i2s_driver_install(kI2SPort, &i2s_config, 0, NULL) != ESP_OK) {
ESP_LOGE(kTag, "failed to configure i2s pins %x", err);
if (esp_err_t err = i2s_channel_init_std_mode(i2s_handle, &i2s_config) != ESP_OK) {
ESP_LOGE(kTag, "failed to initialise i2s channel %x", err);
return cpp::fail(Error::FAILED_TO_INSTALL_I2S);
}
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::FAILED_TO_INSTALL_I2S);
}
// TODO: does starting the channel mean the dac will boot into a more
// meaningful state?
i2s_channel_enable(dac->i2s_handle_);
// Now let's double check that the DAC itself came up whilst we we working.
bool is_booted = dac->WaitForPowerState(
@ -92,13 +90,17 @@ auto AudioDac::create(GpioExpander* expander)
return dac;
}
AudioDac::AudioDac(GpioExpander* gpio) : gpio_(gpio) {
AudioDac::AudioDac(GpioExpander* gpio, i2s_chan_handle_t i2s_handle) : gpio_(gpio),
i2s_handle_(i2s_handle),
clock_config_(I2S_STD_CLK_DEFAULT_CONFIG(48000)),
slot_config_(I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO)) {
gpio_->set_pin(GpioExpander::AUDIO_POWER_ENABLE, true);
gpio_->Write();
}
AudioDac::~AudioDac() {
i2s_driver_uninstall(kI2SPort);
i2s_channel_disable(i2s_handle_);
i2s_del_channel(i2s_handle_);
gpio_->set_pin(GpioExpander::AUDIO_POWER_ENABLE, false);
gpio_->Write();
}
@ -136,7 +138,7 @@ bool AudioDac::WaitForPowerState(
if (has_matched) {
break;
} else {
ESP_LOGI(kTag, "Waiting for power state (was %d %x)", result.first,
ESP_LOGI(kTag, "Waiting for power state (was %d 0x%x)", result.first,
(uint8_t)result.second);
vTaskDelay(pdMS_TO_TICKS(1));
}
@ -148,14 +150,23 @@ auto AudioDac::Reconfigure(BitsPerSample bps, SampleRate rate) -> bool {
// TODO(jacqueline): investigate how reliable the auto-clocking of the dac
// is. We might need to explicit reconfigure the dac here as well if it's not
// good enough.
i2s_set_clk(kI2SPort, rate, bps, I2S_CHANNEL_STEREO);
i2s_channel_disable(i2s_handle_);
slot_config_.slot_bit_width = (i2s_slot_bit_width_t) bps;
i2s_channel_reconfig_std_slot(i2s_handle_, &slot_config_);
// TODO: update mclk multiple as well if needed?
clock_config_.sample_rate_hz = rate;
i2s_channel_reconfig_std_clock(i2s_handle_, &clock_config_);
i2s_channel_enable(i2s_handle_);
return true;
}
auto AudioDac::WriteData(const cpp::span<std::byte>& data, TickType_t max_wait)
-> std::size_t {
std::size_t res = 0;
i2s_write(kI2SPort, data.data(), data.size(), &res, max_wait);
i2s_channel_write(i2s_handle_, data.data(), data.size(), &res, max_wait);
return res;
}

@ -3,13 +3,15 @@
#include <stdint.h>
#include <functional>
#include <memory>
#include <utility>
#include "driver/i2s_types.h"
#include "esp_err.h"
#include "freertos/portmacro.h"
#include "hal/i2s_types.h"
#include "result.hpp"
#include "span.hpp"
#include "driver/i2s_types_legacy.h"
#include "driver/i2s_std.h"
#include "gpio_expander.hpp"
@ -29,7 +31,7 @@ class AudioDac {
static auto create(GpioExpander* expander)
-> cpp::result<std::unique_ptr<AudioDac>, Error>;
AudioDac(GpioExpander* gpio);
AudioDac(GpioExpander* gpio, i2s_chan_handle_t i2s_handle);
~AudioDac();
/**
@ -54,9 +56,9 @@ class AudioDac {
std::pair<bool, PowerState> ReadPowerState();
enum BitsPerSample {
BPS_16 = I2S_BITS_PER_SAMPLE_16BIT,
BPS_24 = I2S_BITS_PER_SAMPLE_24BIT,
BPS_32 = I2S_BITS_PER_SAMPLE_32BIT
BPS_16 = I2S_DATA_BIT_WIDTH_16BIT,
BPS_24 = I2S_DATA_BIT_WIDTH_24BIT,
BPS_32 = I2S_DATA_BIT_WIDTH_32BIT,
};
enum SampleRate {
SAMPLE_RATE_44_1 = 44100,
@ -75,6 +77,10 @@ class AudioDac {
private:
GpioExpander* gpio_;
i2s_chan_handle_t i2s_handle_;
i2s_std_clk_config_t clock_config_;
i2s_std_slot_config_t slot_config_;
/*
* Pools the power state for up to 10ms, waiting for the given predicate to

@ -122,8 +122,6 @@ extern "C" void app_main(void) {
(void*)lvglArgs, 1, sLvglStack,
&sLvglTaskBuffer, 1);
// TODO(jacqueline): re-enable this once our pipeline works.
/*
ESP_LOGI(TAG, "Init audio pipeline");
auto playback_res = audio::AudioPlayback::create(expander, storage);
if (playback_res.has_error()) {
@ -132,10 +130,9 @@ extern "C" void app_main(void) {
}
std::shared_ptr<audio::AudioPlayback> playback =
std::move(playback_res.value());
*/
ESP_LOGI(TAG, "Launch console");
console::AppConsole console(nullptr);
console::AppConsole console(playback.get());
console.Launch();
while (1) {

Loading…
Cancel
Save