From efcedd9005f4365b65a632b5448face9b4aad075 Mon Sep 17 00:00:00 2001 From: Brumi-2021 <86470699+Brumi-2021@users.noreply.github.com> Date: Sat, 21 Oct 2023 01:43:22 +0200 Subject: [PATCH] Add "Hear Mic" feature to the Mic App (#1518) * Add "Hear Mic" feature to the Mic App * Following consensus change about ternary operators --- firmware/application/apps/ui_mictx.cpp | 40 ++++++++++++++++++++++++-- firmware/application/apps/ui_mictx.hpp | 7 +++++ firmware/application/audio.cpp | 8 ++++++ firmware/application/audio.hpp | 6 ++++ firmware/common/ak4951.cpp | 35 ++++++++++++++++++++-- firmware/common/ak4951.hpp | 3 ++ firmware/common/wm8731.hpp | 16 ++++++++++- 7 files changed, 108 insertions(+), 7 deletions(-) diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index 1706afc0..4aa216d4 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -184,6 +184,10 @@ void MicTXView::rxaudio(bool is_on) { baseband::run_image(portapack::spi_flash::image_tag_mic_tx); audio::output::stop(); audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // When detected AK4951 => set up ALC mode; when detected WM8731 => set up mic_boost ON/OFF. + if (mic_to_HP_enabled) + audio::input::loopback_mic_to_hp_enable(); + else + audio::input::loopback_mic_to_hp_disable(); portapack::pin_i2s0_rx_sda.mode(3); configure_baseband(); } @@ -215,6 +219,7 @@ MicTXView::MicTXView( &field_frequency, &options_tone_key, &check_rogerbeep, + &check_mic_to_HP, // check box to activate "hear mic" &check_common_freq_tx_rx, // added to handle common or separate freq- TX/RX &check_rxactive, &field_volume, @@ -242,6 +247,7 @@ MicTXView::MicTXView( &field_frequency, &options_tone_key, &check_rogerbeep, + &check_mic_to_HP, // check box to activate "hear mic" &check_common_freq_tx_rx, // added to handle common or separate freq- TX/RX &check_rxactive, &field_volume, @@ -287,7 +293,11 @@ MicTXView::MicTXView( } ak4951_alc_and_wm8731_boost_GUI = v; // 0..4, WM8731_boost dB's options, (combination boost on/off, and effective gain in captured data >>x) audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // Detected (WM8731), set up the proper wm_boost on/off, 0..4 (0,1) boost_on, (2,3,4) boost_off - configure_baseband(); // to update in real time, sending msg, var-parameters >>shift_bits FM msg, to audio_tx from M0 to M4 Proc - + if (mic_to_HP_enabled) + audio::input::loopback_mic_to_hp_enable(); + else + audio::input::loopback_mic_to_hp_disable(); + configure_baseband(); // to update in real time, sending msg, var-parameters >>shift_bits FM msg, to audio_tx from M0 to M4 Proc - }; options_wm8731_boost_mode.set_selected_index(3); // preset GUI index 3 as default WM -> -02 dB's. } else { @@ -295,7 +305,11 @@ MicTXView::MicTXView( options_ak4951_alc_mode.on_change = [this](size_t, int8_t v) { ak4951_alc_and_wm8731_boost_GUI = v; // 0..11, AK4951 Mic -Automatic volume Level Control options, audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // Detected (AK4951) ==> Set up proper ALC mode from 0..11 options - configure_baseband(); // sending fixed >>8_FM, var-parameters msg, to audiotx from this M0 to M4 process. + if (mic_to_HP_enabled) + audio::input::loopback_mic_to_hp_enable(); + else + audio::input::loopback_mic_to_hp_disable(); + configure_baseband(); // sending fixed >>8_FM, var-parameters msg, to audiotx from this M0 to M4 process. }; } @@ -475,6 +489,20 @@ MicTXView::MicTXView( rogerbeep_enabled = v; }; + check_mic_to_HP.on_select = [this](Checkbox&, bool v) { + mic_to_HP_enabled = v; + if (mic_to_HP_enabled) + audio::input::loopback_mic_to_hp_enable(); + else + audio::input::loopback_mic_to_hp_disable(); + if (mic_to_HP_enabled) { // When user click to "hear mic to HP", we will select the higher acoustic sound Option MODE ALC or BOOST- + if (audio::debug::codec_name() == "WM8731") { + options_wm8731_boost_mode.set_selected_index(0); // In WM we always go to Boost +12 dB’s respect reference level + } else if (ak4951_alc_and_wm8731_boost_GUI == 0) // In AK we are changing only that ALC index =0, because in that option, there is no sound. + options_ak4951_alc_mode.set_selected_index(1); // alc_mode =0 , means no ALC,no DIGITAL filter block (by passed), and that mode has no loopback mode. + } + }; + check_common_freq_tx_rx.on_select = [this](Checkbox&, bool v) { bool_same_F_tx_rx_enabled = v; field_rxfrequency.hidden(v); // Hide or show separated freq RX field. (When no hide user can enter down indep. freq for RX) @@ -501,8 +529,10 @@ MicTXView::MicTXView( check_rxactive.on_select = [this](Checkbox&, bool v) { // vumeter.set_value(0); //Start with a clean vumeter rx_enabled = v; + check_mic_to_HP.hidden(rx_enabled); // Hide or show "Hear Mic" checkbox depending if we activate the receiver (we should better not activate both things) + check_mic_to_HP.set_value(false); // If activate receiver sound , reset the possible activation of "Hear to Mic" . // check_va.hidden(v); //Hide or show voice activation - rxaudio(v); // Activate-Deactivate audio rx accordingly + rxaudio(v); // Activate-Deactivate audio RX (receiver) accordingly set_dirty(); // Refresh interface }; @@ -603,6 +633,10 @@ MicTXView::MicTXView( audio::set_rate(audio::Rate::Hz_24000); audio::input::start(ak4951_alc_and_wm8731_boost_GUI); // When detected AK4951 => set up ALC mode; when detected WM8731 => set up mic_boost ON/OFF. + if (mic_to_HP_enabled) + audio::input::loopback_mic_to_hp_enable(); + else + audio::input::loopback_mic_to_hp_disable(); } MicTXView::MicTXView( diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp index c479155e..4df94208 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -94,6 +94,7 @@ class MicTXView : public View { bool va_enabled{false}; bool ptt_enabled{true}; bool rogerbeep_enabled{false}; + bool mic_to_HP_enabled{false}; bool bool_same_F_tx_rx_enabled{false}; bool rx_enabled{false}; uint32_t tone_key_index{}; @@ -277,6 +278,12 @@ class MicTXView : public View { "Roger beep", false}; + Checkbox check_mic_to_HP{ + {18 * 8, (14 * 8) + 4}, + 10, + "Hear Mic", + false}; + Checkbox check_rxactive{ {3 * 8, (21 * 8) - 7}, 8, // it was 18, but if it is string size should be 8 diff --git a/firmware/application/audio.cpp b/firmware/application/audio.cpp index d7f1036d..59f885be 100644 --- a/firmware/application/audio.cpp +++ b/firmware/application/audio.cpp @@ -208,6 +208,14 @@ void stop() { audio_codec->microphone_disable(); } +void loopback_mic_to_hp_enable() { + audio_codec->microphone_to_HP_enable(); +} + +void loopback_mic_to_hp_disable() { + audio_codec->microphone_to_HP_disable(); +} + } /* namespace input */ namespace headphone { diff --git a/firmware/application/audio.hpp b/firmware/application/audio.hpp index bf09f753..f5cba0e9 100644 --- a/firmware/application/audio.hpp +++ b/firmware/application/audio.hpp @@ -53,6 +53,9 @@ class Codec { virtual void microphone_enable(int8_t alc_mode) = 0; // added user-GUI AK4951 ,selected ALC mode. virtual void microphone_disable() = 0; + virtual void microphone_to_HP_enable() = 0; + virtual void microphone_to_HP_disable() = 0; + virtual size_t reg_count() const = 0; virtual size_t reg_bits() const = 0; virtual uint32_t reg_read(const size_t register_number) = 0; @@ -79,6 +82,9 @@ namespace input { void start(int8_t alc_mode); // added parameter user-GUI select AK4951-ALC mode for config mic path,(recording mode in datasheet), void stop(); +void loopback_mic_to_hp_enable(); +void loopback_mic_to_hp_disable(); + } /* namespace input */ namespace headphone { diff --git a/firmware/common/ak4951.cpp b/firmware/common/ak4951.cpp index 1422138e..2c029cf0 100644 --- a/firmware/common/ak4951.cpp +++ b/firmware/common/ak4951.cpp @@ -279,7 +279,7 @@ void AK4951::microphone_enable(int8_t alc_mode) { update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode. map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal. Mic Amp Lch and ADC Lch Power Management - map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal. Mic Amp Rch and ADC Rch Power Management + map.r.power_management_1.PMADR = 0; // ADC Rch = Rch input signal. Mic Amp Rch and ADC Rch Power Management. (PMADL=1, PMADR=0) means MONO MIC input connected to Left pin. map.r.power_management_1.PMPFIL = 0; // Pre-loading , Programmable Dig. filter OFF ,filter unused, routed around.(original value = 0 ) update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used ) @@ -461,7 +461,7 @@ void AK4951::microphone_enable(int8_t alc_mode) { // When changing those modes, PMPFIL bit must be “0”, it is OK (*1) map.r.digital_filter_mode.ADCPF = 1; // ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode) map.r.digital_filter_mode.PFSDO = 1; // ADC (+ 1st order HPF) Output - map.r.digital_filter_mode.PFDAC = 0b00; // (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin) + map.r.digital_filter_mode.PFDAC = 0b00; // (Input selector for DAC (initially not used in MIC), SDTI= Audio Serial Data Input Pin) update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode. // The EQn (n=1, 2, 3, 4 or 5) coefficient must be set when EQn bit = “0” or PMPFIL bit = “0”., but we are already (*1) @@ -501,7 +501,7 @@ void AK4951::microphone_enable(int8_t alc_mode) { // Acitivating digital block , power supply map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal. Mic Amp Lch and ADC Lch Power Management - map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal. Mic Amp Rch and ADC Rch Power Management + map.r.power_management_1.PMADR = 0; // ADC Rch = Rch input signal. Mic Amp Rch and ADC Rch Power Management. (PMADL=1, PMADR=0) means MONO MIC input connected to Left pin. map.r.power_management_1.PMPFIL = 1; // Pre-loaded in top part. Orig value=0, Programmable Digital filter unused (not power up), routed around. update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used ) @@ -522,8 +522,13 @@ void AK4951::microphone_disable() { map.r.power_management_1.PMADL = 0; // original code , disable Power managem.Mic ADC L map.r.power_management_1.PMADR = 0; // original code , disable Power managem.Mic ADC R map.r.power_management_1.PMPFIL = 0; // original code , disable Power managem. all Programmable Dig. block + map.r.power_management_1.PMDAC = 0; // Pre-loaded power management DAC block OFF update(Register::PowerManagement1); + map.r.power_management_2.PMHPL = 0; // Pre-loaded power management HP LEFT block OFF + map.r.power_management_2.PMHPR = 0; // Pre-loaded power management HP RIGHT block OFF + update(Register::PowerManagement2); // Deactivating the Power management of the HP L&R blocks. + map.r.alc_mode_control_1.ALC = 0; // original code , Restore , disable ALC block. update(Register::ALCModeControl1); @@ -560,6 +565,30 @@ void AK4951::microphone_disable() { update(Register::DigitalFilterSelect3); } +void AK4951::microphone_to_HP_enable() { + map.r.digital_filter_mode.PFDAC = 0b01; // (Input selector for DAC, audio Loopback Mode . + update(Register::DigitalFilterMode); // Writing the Audio Path , Audio mode path : Loopback Mode . + + map.r.power_management_1.PMDAC = 1; // Pre-loaded power management DAC block ON + update(Register::PowerManagement1); // Activating the Power management of the DAC block for the loopback mode + + map.r.power_management_2.PMHPL = 1; // Pre-loaded power management HP LEFT block ON + map.r.power_management_2.PMHPR = 1; // Pre-loaded power management HP RIGHT block ON + update(Register::PowerManagement2); // Activating the Power management of the HP L&R blocks. +} + +void AK4951::microphone_to_HP_disable() { + map.r.digital_filter_mode.PFDAC = 0b00; // (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin) + update(Register::DigitalFilterMode); // Writing the Audio Path , Audio mode path : Loopback Mode . + + map.r.power_management_1.PMDAC = 0; // Pre-loaded power management DAC block OFF + update(Register::PowerManagement1); // Deactivating the Power management of the DAC block for the loopback mode + + map.r.power_management_2.PMHPL = 0; // Pre-loaded power management HP LEFT block OFF + map.r.power_management_2.PMHPR = 0; // Pre-loaded power management HP RIGHT block OFF + update(Register::PowerManagement2); // Deactivating the Power management of the HP L&R blocks. +} + reg_t AK4951::read(const address_t reg_address) { const std::array tx{reg_address}; std::array rx{0x00}; diff --git a/firmware/common/ak4951.hpp b/firmware/common/ak4951.hpp index 0fc69eca..2638efd8 100644 --- a/firmware/common/ak4951.hpp +++ b/firmware/common/ak4951.hpp @@ -847,6 +847,9 @@ class AK4951 : public audio::Codec { void microphone_enable(int8_t alc_mode); // added user GUI parameter , to set up AK4951 ALC mode. void microphone_disable(); + void microphone_to_HP_enable(); + void microphone_to_HP_disable(); + size_t reg_count() const override { return asahi_kasei::ak4951::reg_count; } diff --git a/firmware/common/wm8731.hpp b/firmware/common/wm8731.hpp index 197d8dcf..fcc64d4f 100644 --- a/firmware/common/wm8731.hpp +++ b/firmware/common/wm8731.hpp @@ -359,7 +359,21 @@ class WM8731 : public audio::Codec { } void microphone_disable() override { - // TODO: Implement + microphone_mute(true); + microphone_to_HP_disable(); + } + + void microphone_to_HP_enable() override { + map.r.analog_audio_path_control.sidetone = 1; // Side Tone Switch (Analogue) 1 = Enable Side Tone + map.r.analog_audio_path_control.sideatt = 0b00; // Side Tone Attenuation 00 = -6dB + write(Register::AnalogAudioPathControl); + headphone_enable(); + } + + void microphone_to_HP_disable() override { + map.r.analog_audio_path_control.sidetone = 0; // Side Tone Switch (Analogue) 0 = Disable Side Tone + map.r.analog_audio_path_control.sideatt = 0b11; // Side Tone Attenuation 11 = -15dB + write(Register::AnalogAudioPathControl); } void microphone_boost(const bool boost) {