From 938ba62f57ed2c002bae4aec236eeaeb200e4cba Mon Sep 17 00:00:00 2001 From: jacqueline Date: Thu, 4 Jan 2024 15:57:58 +1100 Subject: [PATCH] refactor handling of volume steps; improve controls --- src/audio/audio_fsm.cpp | 6 +++- src/audio/bt_audio_output.cpp | 14 ++++++-- src/audio/i2s_audio_output.cpp | 44 ++++++++++++-------------- src/audio/include/audio_sink.hpp | 10 ++++-- src/audio/include/bt_audio_output.hpp | 10 ++++-- src/audio/include/i2s_audio_output.hpp | 13 +++++--- src/drivers/i2s_dac.cpp | 4 +-- src/drivers/include/wm8523.hpp | 2 ++ src/drivers/wm8523.cpp | 2 ++ src/ui/encoder_input.cpp | 8 ++--- 10 files changed, 72 insertions(+), 41 deletions(-) diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp index 90bfd60b..a5179156 100644 --- a/src/audio/audio_fsm.cpp +++ b/src/audio/audio_fsm.cpp @@ -129,7 +129,7 @@ void Uninitialised::react(const system_fsm::BootComplete& ev) { auto& nvs = sServices->nvs(); sI2SOutput->SetMaxVolume(nvs.AmpMaxVolume()); - sI2SOutput->SetVolumeDb(nvs.AmpCurrentVolume()); + sI2SOutput->SetVolume(nvs.AmpCurrentVolume()); if (sServices->nvs().OutputMode() == drivers::NvsStorage::Output::kHeadphones) { @@ -188,6 +188,10 @@ void Playback::exit() { vTaskDelay(pdMS_TO_TICKS(10)); sOutput->SetMode(IAudioOutput::Modes::kOnPaused); + // Stash the current volume now, in case it changed during playback, since we + // might be powering off soon. + sServices->nvs().AmpCurrentVolume(sOutput->GetVolume()); + events::System().Dispatch(PlaybackFinished{}); events::Ui().Dispatch(PlaybackFinished{}); } diff --git a/src/audio/bt_audio_output.cpp b/src/audio/bt_audio_output.cpp index a189fefe..0c11481b 100644 --- a/src/audio/bt_audio_output.cpp +++ b/src/audio/bt_audio_output.cpp @@ -43,10 +43,18 @@ auto BluetoothAudioOutput::SetMode(Modes mode) -> void { auto BluetoothAudioOutput::SetVolumeImbalance(int_fast8_t balance) -> void {} -auto BluetoothAudioOutput::SetVolume(uint_fast8_t percent) -> void {} +auto BluetoothAudioOutput::SetVolume(uint16_t) -> void {} -auto BluetoothAudioOutput::GetVolume() -> uint_fast8_t { - return 50; +auto BluetoothAudioOutput::GetVolume() -> uint16_t { + return 0; +} + +auto BluetoothAudioOutput::GetVolumePct() -> uint_fast8_t { + return 0; +} + +auto BluetoothAudioOutput::GetVolumeDb() -> int_fast16_t { + return 0; } auto BluetoothAudioOutput::AdjustVolumeUp() -> bool { diff --git a/src/audio/i2s_audio_output.cpp b/src/audio/i2s_audio_output.cpp index 8cfd5b90..29d70fb5 100644 --- a/src/audio/i2s_audio_output.cpp +++ b/src/audio/i2s_audio_output.cpp @@ -91,17 +91,9 @@ auto I2SAudioOutput::SetMaxVolume(uint16_t max) -> void { SetVolume(GetVolume()); } -auto I2SAudioOutput::SetVolumeDb(uint16_t vol) -> void { - current_volume_ = - std::clamp(vol, drivers::wm8523::kAbsoluteMinVolume, max_volume_); - SetVolume(GetVolume()); -} - -auto I2SAudioOutput::SetVolume(uint_fast8_t percent) -> void { - percent = std::min(percent, 100); - float new_value = static_cast(max_volume_) / 100 * percent; - current_volume_ = std::max(new_value, kMinVolume); - ESP_LOGI(kTag, "set volume to %u%% = %u", percent, current_volume_); +auto I2SAudioOutput::SetVolume(uint16_t vol) -> void { + current_volume_ = std::clamp(vol, kMinVolume, max_volume_); + ESP_LOGI(kTag, "set volume to %u%% = %idB", GetVolumePct(), GetVolumeDb()); int32_t left_unclamped = current_volume_ + left_difference_; uint16_t left = std::clamp(left_unclamped, kMinVolume, max_volume_); @@ -112,31 +104,37 @@ auto I2SAudioOutput::SetVolume(uint_fast8_t percent) -> void { current_volume_ | 0x200); } -auto I2SAudioOutput::GetVolume() -> uint_fast8_t { - return static_cast(static_cast(current_volume_) / - max_volume_ * 100.0f); +auto I2SAudioOutput::GetVolume() -> uint16_t { + return current_volume_; +} + +auto I2SAudioOutput::GetVolumePct() -> uint_fast8_t { + return (current_volume_ - kMinVolume) * 100 / (max_volume_ - kMinVolume); +} + +auto I2SAudioOutput::GetVolumeDb() -> int_fast16_t { + // Add two before dividing in order to round correctly. + return (static_cast(current_volume_) - + static_cast(drivers::wm8523::kLineLevelReferenceVolume) + 2) / + 4; } auto I2SAudioOutput::AdjustVolumeUp() -> bool { - if (GetVolume() >= 100) { + if (GetVolume() >= max_volume_) { return false; } - if (GetVolume() >= 95) { - SetVolume(100); - } else { - SetVolume(GetVolume() + 5); - } + SetVolume(GetVolume() + 1); return true; } auto I2SAudioOutput::AdjustVolumeDown() -> bool { - if (GetVolume() == 0) { + if (GetVolume() == kMinVolume) { return false; } - if (GetVolume() <= 5) { + if (GetVolume() <= kMinVolume + 1) { SetVolume(0); } else { - SetVolume(GetVolume() - 5); + SetVolume(GetVolume() - 1); } return true; } diff --git a/src/audio/include/audio_sink.hpp b/src/audio/include/audio_sink.hpp index c37e51fb..eba55eb5 100644 --- a/src/audio/include/audio_sink.hpp +++ b/src/audio/include/audio_sink.hpp @@ -44,8 +44,14 @@ class IAudioOutput { virtual auto SetMode(Modes) -> void = 0; virtual auto SetVolumeImbalance(int_fast8_t balance) -> void = 0; - virtual auto SetVolume(uint_fast8_t percent) -> void = 0; - virtual auto GetVolume() -> uint_fast8_t = 0; + + virtual auto SetVolume(uint16_t) -> void = 0; + + virtual auto GetVolume() -> uint16_t = 0; + + virtual auto GetVolumePct() -> uint_fast8_t = 0; + virtual auto GetVolumeDb() -> int_fast16_t = 0; + virtual auto AdjustVolumeUp() -> bool = 0; virtual auto AdjustVolumeDown() -> bool = 0; diff --git a/src/audio/include/bt_audio_output.hpp b/src/audio/include/bt_audio_output.hpp index 6e5d0720..f23ccd6a 100644 --- a/src/audio/include/bt_audio_output.hpp +++ b/src/audio/include/bt_audio_output.hpp @@ -27,8 +27,14 @@ class BluetoothAudioOutput : public IAudioOutput { auto SetMode(Modes) -> void override; auto SetVolumeImbalance(int_fast8_t balance) -> void override; - auto SetVolume(uint_fast8_t percent) -> void override; - auto GetVolume() -> uint_fast8_t override; + + auto SetVolume(uint16_t) -> void override; + + auto GetVolume() -> uint16_t override; + + auto GetVolumePct() -> uint_fast8_t override; + auto GetVolumeDb() -> int_fast16_t override; + auto AdjustVolumeUp() -> bool override; auto AdjustVolumeDown() -> bool override; diff --git a/src/audio/include/i2s_audio_output.hpp b/src/audio/include/i2s_audio_output.hpp index e5395ade..7c297106 100644 --- a/src/audio/include/i2s_audio_output.hpp +++ b/src/audio/include/i2s_audio_output.hpp @@ -20,8 +20,7 @@ namespace audio { class I2SAudioOutput : public IAudioOutput { public: - I2SAudioOutput(StreamBufferHandle_t, - drivers::IGpios& expander); + I2SAudioOutput(StreamBufferHandle_t, drivers::IGpios& expander); ~I2SAudioOutput(); auto SetMode(Modes) -> void override; @@ -30,8 +29,14 @@ class I2SAudioOutput : public IAudioOutput { auto SetVolumeDb(uint16_t) -> void; auto SetVolumeImbalance(int_fast8_t balance) -> void override; - auto SetVolume(uint_fast8_t percent) -> void override; - auto GetVolume() -> uint_fast8_t override; + + auto SetVolume(uint16_t) -> void override; + + auto GetVolume() -> uint16_t override; + + auto GetVolumePct() -> uint_fast8_t override; + auto GetVolumeDb() -> int_fast16_t override; + auto AdjustVolumeUp() -> bool override; auto AdjustVolumeDown() -> bool override; diff --git a/src/drivers/i2s_dac.cpp b/src/drivers/i2s_dac.cpp index 0ef1005a..4d29f917 100644 --- a/src/drivers/i2s_dac.cpp +++ b/src/drivers/i2s_dac.cpp @@ -95,8 +95,8 @@ I2SDac::I2SDac(IGpios& gpio, i2s_chan_handle_t i2s_handle) vTaskDelay(pdMS_TO_TICKS(10)); wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b0); - // Ramp volume changes - wm8523::WriteRegister(wm8523::Register::kDacCtrl, 0b11); + // Use zero-cross detection for volume changes. + wm8523::WriteRegister(wm8523::Register::kDacCtrl, 0b10000); } I2SDac::~I2SDac() { diff --git a/src/drivers/include/wm8523.hpp b/src/drivers/include/wm8523.hpp index b13cf34b..a64f6bac 100644 --- a/src/drivers/include/wm8523.hpp +++ b/src/drivers/include/wm8523.hpp @@ -23,6 +23,8 @@ extern const uint16_t kLineLevelReferenceVolume; extern const uint16_t kDefaultVolume; extern const uint16_t kDefaultMaxVolume; +extern const uint16_t kZeroDbVolume; + constexpr auto VolumeToDb(uint16_t vol) -> int_fast8_t { return (vol - kLineLevelReferenceVolume) / 4; } diff --git a/src/drivers/wm8523.cpp b/src/drivers/wm8523.cpp index 5f6c8053..9fe3e001 100644 --- a/src/drivers/wm8523.cpp +++ b/src/drivers/wm8523.cpp @@ -32,6 +32,8 @@ const uint16_t kDefaultVolume = kLineLevelReferenceVolume - 96; // Default to +6dB == 2Vrms == 'CD Player' const uint16_t kDefaultMaxVolume = kLineLevelReferenceVolume + 12; +const uint16_t kZeroDbVolume = 0x190; + static const uint8_t kAddress = 0b0011010; auto ReadRegister(Register reg) -> std::optional { diff --git a/src/ui/encoder_input.cpp b/src/ui/encoder_input.cpp index 39aacc0c..f8b6a88b 100644 --- a/src/ui/encoder_input.cpp +++ b/src/ui/encoder_input.cpp @@ -194,7 +194,7 @@ auto EncoderInput::Read(lv_indev_data_t* data) -> void { data->enc_diff = scroller_->AddInput(now_ms, 0); } - trigger = TriggerKey(Keys::kVolumeUp, KeyStyle::kLongPress, now_ms); + trigger = TriggerKey(Keys::kVolumeUp, KeyStyle::kRepeat, now_ms); switch (trigger) { case Trigger::kNone: break; @@ -205,7 +205,7 @@ auto EncoderInput::Read(lv_indev_data_t* data) -> void { break; } - trigger = TriggerKey(Keys::kVolumeDown, KeyStyle::kLongPress, now_ms); + trigger = TriggerKey(Keys::kVolumeDown, KeyStyle::kRepeat, now_ms); switch (trigger) { case Trigger::kNone: break; @@ -242,7 +242,7 @@ auto EncoderInput::Read(lv_indev_data_t* data) -> void { break; } - trigger = TriggerKey(Keys::kVolumeUp, KeyStyle::kLongPress, now_ms); + trigger = TriggerKey(Keys::kVolumeUp, KeyStyle::kRepeat, now_ms); switch (trigger) { case Trigger::kNone: break; @@ -253,7 +253,7 @@ auto EncoderInput::Read(lv_indev_data_t* data) -> void { break; } - trigger = TriggerKey(Keys::kVolumeDown, KeyStyle::kLongPress, now_ms); + trigger = TriggerKey(Keys::kVolumeDown, KeyStyle::kRepeat, now_ms); switch (trigger) { case Trigger::kNone: break;