From 28319652c1a5d2aa0342c5f48c2c67f26b51b0f7 Mon Sep 17 00:00:00 2001 From: Kyle Reed Date: Sun, 4 Jun 2023 12:56:46 -0700 Subject: [PATCH] Add AudioVolumeField -- cleanup (#1107) * WIP Adding AudioVolumeField * Fix build break * Add Bernd to about --------- Co-authored-by: kallanreed --- .../application/apps/analog_audio_app.cpp | 10 ---- .../application/apps/analog_audio_app.hpp | 10 +--- firmware/application/apps/analog_tv_app.cpp | 10 ---- firmware/application/apps/analog_tv_app.hpp | 10 +--- firmware/application/apps/pocsag_app.cpp | 52 ++++++------------- firmware/application/apps/pocsag_app.hpp | 23 +++----- firmware/application/apps/ui_about_simple.cpp | 1 + firmware/application/apps/ui_level.cpp | 10 +--- firmware/application/apps/ui_level.hpp | 10 +--- firmware/application/apps/ui_mictx.cpp | 10 ---- firmware/application/apps/ui_mictx.hpp | 10 +--- firmware/application/apps/ui_recon.cpp | 13 +---- firmware/application/apps/ui_recon.hpp | 10 +--- firmware/application/apps/ui_scanner.cpp | 14 ++--- firmware/application/apps/ui_scanner.hpp | 10 +--- firmware/application/apps/ui_sonde.cpp | 12 ----- firmware/application/apps/ui_sonde.hpp | 10 +--- firmware/application/receiver_model.cpp | 15 ++++-- firmware/application/receiver_model.hpp | 4 ++ firmware/application/ui/ui_receiver.cpp | 17 ++++++ firmware/application/ui/ui_receiver.hpp | 5 ++ firmware/common/utility.hpp | 11 +++- 22 files changed, 91 insertions(+), 186 deletions(-) diff --git a/firmware/application/apps/analog_audio_app.cpp b/firmware/application/apps/analog_audio_app.cpp index ce5f01ea..b8ebdc48 100644 --- a/firmware/application/apps/analog_audio_app.cpp +++ b/firmware/application/apps/analog_audio_app.cpp @@ -198,11 +198,6 @@ AnalogAudioView::AnalogAudioView( this->on_show_options_modulation(); }; - field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99); - field_volume.on_change = [this](int32_t v) { - this->on_headphone_volume_changed(v); - }; - record_view.on_error = [&nav](std::string message) { nav.display_modal("Error", message); }; @@ -391,11 +386,6 @@ void AnalogAudioView::on_reference_ppm_correction_changed(int32_t v) { persistent_memory::set_correction_ppb(v * 1000); } -void AnalogAudioView::on_headphone_volume_changed(int32_t v) { - const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max; - receiver_model.set_headphone_volume(new_volume); -} - void AnalogAudioView::update_modulation(const ReceiverModel::Mode modulation) { audio::output::mute(); record_view.stop(); diff --git a/firmware/application/apps/analog_audio_app.hpp b/firmware/application/apps/analog_audio_app.hpp index 37fc46ae..b7f37aad 100644 --- a/firmware/application/apps/analog_audio_app.hpp +++ b/firmware/application/apps/analog_audio_app.hpp @@ -207,13 +207,8 @@ class AnalogAudioView : public View { {"SPEC", toUType(ReceiverModel::Mode::SpectrumAnalysis)}, }}; - NumberField field_volume{ - {28 * 8, 0 * 16}, - 2, - {0, 99}, - 1, - ' ', - }; + AudioVolumeField field_volume{ + {28 * 8, 0 * 16}}; Text text_ctcss{ {19 * 8, 1 * 16, 11 * 8, 1 * 16}, @@ -239,7 +234,6 @@ class AnalogAudioView : public View { void on_show_options_modulation(); void on_frequency_step_changed(rf::Frequency f); void on_reference_ppm_correction_changed(int32_t v); - void on_headphone_volume_changed(int32_t v); void on_edit_frequency(); void remove_options_widget(); diff --git a/firmware/application/apps/analog_tv_app.cpp b/firmware/application/apps/analog_tv_app.cpp index 05df59db..39926b58 100644 --- a/firmware/application/apps/analog_tv_app.cpp +++ b/firmware/application/apps/analog_tv_app.cpp @@ -100,11 +100,6 @@ AnalogTvView::AnalogTvView( this->on_show_options_modulation(); }; - field_volume.set_value(0); - field_volume.on_change = [this](int32_t v) { - this->on_headphone_volume_changed(v); - }; - tv.on_select = [this](int32_t offset) { field_frequency.set_value(receiver_model.tuning_frequency() + offset); }; @@ -225,11 +220,6 @@ void AnalogTvView::on_reference_ppm_correction_changed(int32_t v) { persistent_memory::set_correction_ppb(v * 1000); } -void AnalogTvView::on_headphone_volume_changed(int32_t v) { - (void)v; // avoid warning - // tv::TVView::set_headphone_volume(this,v); -} - void AnalogTvView::update_modulation(const ReceiverModel::Mode modulation) { audio::output::mute(); diff --git a/firmware/application/apps/analog_tv_app.hpp b/firmware/application/apps/analog_tv_app.hpp index acffab88..90e3606f 100644 --- a/firmware/application/apps/analog_tv_app.hpp +++ b/firmware/application/apps/analog_tv_app.hpp @@ -98,13 +98,8 @@ class AnalogTvView : public View { {"TV ", toUType(ReceiverModel::Mode::WidebandFMAudio)}, }}; - NumberField field_volume{ - {27 * 8, 0 * 16}, - 3, - {0, 255}, - 1, - ' ', - }; + AudioVolumeField field_volume{ + {27 * 8, 0 * 16}}; std::unique_ptr options_widget{}; @@ -118,7 +113,6 @@ class AnalogTvView : public View { void on_show_options_modulation(); void on_frequency_step_changed(rf::Frequency f); void on_reference_ppm_correction_changed(int32_t v); - void on_headphone_volume_changed(int32_t v); void on_edit_frequency(); void remove_options_widget(); diff --git a/firmware/application/apps/pocsag_app.cpp b/firmware/application/apps/pocsag_app.cpp index 67aff790..1ae94f2c 100644 --- a/firmware/application/apps/pocsag_app.cpp +++ b/firmware/application/apps/pocsag_app.cpp @@ -79,18 +79,21 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) { update_freq(f); }; - // load app settings + // load app settings TODO: needed? auto rc = settings.load("rx_pocsag", &app_settings); if (rc == SETTINGS_OK) { field_lna.set_value(app_settings.lna); field_vga.set_value(app_settings.vga); field_rf_amp.set_value(app_settings.rx_amp); field_frequency.set_value(app_settings.rx_frequency); - } else + } else { + field_lna.set_value(receiver_model.lna()); + field_vga.set_value(receiver_model.vga()); + field_rf_amp.set_value(receiver_model.rf_amp()); field_frequency.set_value(receiver_model.tuning_frequency()); + } receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); - receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000); receiver_model.enable(); @@ -105,22 +108,10 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) { }; }; - check_log.set_value(logging); - check_log.on_select = [this](Checkbox&, bool v) { - logging = v; - }; - - field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99); - field_volume.on_change = [this](int32_t v) { - this->on_headphone_volume_changed(v); - }; - - check_ignore.set_value(ignore); - check_ignore.on_select = [this](Checkbox&, bool v) { - ignore = v; - }; - + // TODO app setting instead? ignore_address = persistent_memory::pocsag_ignore_address(); + + // TODO is this common enough for a helper? for (size_t c = 0; c < 7; c++) { sym_ignore.set_sym(6 - c, ignore_address % 10); ignore_address /= 10; @@ -150,20 +141,6 @@ POCSAGAppView::~POCSAGAppView() { baseband::shutdown(); } -void POCSAGAppView::focus() { - field_frequency.focus(); -} - -void POCSAGAppView::on_headphone_volume_changed(int32_t v) { - const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max; - receiver_model.set_headphone_volume(new_volume); -} - -// Useless ? -void POCSAGAppView::set_parent_rect(const Rect new_parent_rect) { - View::set_parent_rect(new_parent_rect); -} - void POCSAGAppView::on_packet(const POCSAGPacketMessage* message) { std::string alphanum_text = ""; @@ -172,14 +149,14 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage* message) { else { pocsag_decode_batch(message->packet, &pocsag_state); - if ((ignore) && (pocsag_state.address == sym_ignore.value_dec_u32())) { + if ((ignore()) && (pocsag_state.address == sym_ignore.value_dec_u32())) { // Ignore (inform, but no log) // console.write("\n\x1B\x03" + to_string_time(message->packet.timestamp()) + // " Ignored address " + to_string_dec_uint(pocsag_state.address)); return; } // Too many errors for reliable decode - if ((ignore) && (pocsag_state.errors >= 3)) { + if ((ignore()) && (pocsag_state.errors >= 3)) { return; } @@ -199,7 +176,7 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage* message) { console.write(console_info); - if (logger && logging) { + if (logger && logging()) { logger->log_decoded(message->packet, to_string_dec_uint(pocsag_state.address) + " F" + to_string_dec_uint(pocsag_state.function) + " Address only"); @@ -218,15 +195,16 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage* message) { console.write(pocsag_state.output); } - if (logger && logging) + if (logger && logging()) logger->log_decoded(message->packet, to_string_dec_uint(pocsag_state.address) + " F" + to_string_dec_uint(pocsag_state.function) + " Alpha: " + pocsag_state.output); } } + // TODO: make setting. // Log raw data whatever it contains - if (logger && logging) + if (logger && logging()) logger->log_raw_data(message->packet, target_frequency()); } diff --git a/firmware/application/apps/pocsag_app.hpp b/firmware/application/apps/pocsag_app.hpp index 1cde04b9..74ebe656 100644 --- a/firmware/application/apps/pocsag_app.hpp +++ b/firmware/application/apps/pocsag_app.hpp @@ -52,20 +52,18 @@ class POCSAGAppView : public View { POCSAGAppView(NavigationView& nav); ~POCSAGAppView(); - void set_parent_rect(const Rect new_parent_rect) override; - void focus() override; - std::string title() const override { return "POCSAG RX"; }; private: static constexpr uint32_t initial_target_frequency = 466175000; + bool logging() const { return check_log.value(); }; + bool ignore() const { return check_ignore.value(); }; + // app save settings std::app_settings settings{}; std::app_settings::AppSettings app_settings{}; - bool logging{false}; - bool ignore{false}; uint32_t last_address = 0xFFFFFFFF; pocsag::POCSAGState pocsag_state{}; @@ -88,13 +86,9 @@ class POCSAGAppView : public View { FrequencyField field_frequency{ {0 * 8, 0 * 8}, }; - NumberField field_volume{ - {28 * 8, 0 * 16}, - 2, - {0, 99}, - 1, - ' ', - }; + + AudioVolumeField field_volume{ + {28 * 8, 0 * 16}}; Checkbox check_ignore{ {0 * 8, 21}, @@ -105,10 +99,11 @@ class POCSAGAppView : public View { {13 * 8, 25}, 7, SymField::SYMFIELD_DEC}; + Checkbox check_log{ {240 - 8 * 8, 21}, 3, - "LOG", + "Log", false}; Console console{ @@ -122,8 +117,6 @@ class POCSAGAppView : public View { void on_packet(const POCSAGPacketMessage* message); - void on_headphone_volume_changed(int32_t v); - uint32_t target_frequency() const; void set_target_frequency(const uint32_t new_value); diff --git a/firmware/application/apps/ui_about_simple.cpp b/firmware/application/apps/ui_about_simple.cpp index 84a972c0..60b2ffb2 100644 --- a/firmware/application/apps/ui_about_simple.cpp +++ b/firmware/application/apps/ui_about_simple.cpp @@ -33,6 +33,7 @@ void AboutView::update() { console.writeln("heurist1,intoxsick,ckuethe"); console.writeln("notpike,jLynx,zigad"); console.writeln("MichalLeonBorsuk,jimilinuxguy"); + console.writeln("kallanreed,bernd-herzog"); console.writeln(""); break; diff --git a/firmware/application/apps/ui_level.cpp b/firmware/application/apps/ui_level.cpp index d2a69665..d0adc22d 100644 --- a/firmware/application/apps/ui_level.cpp +++ b/firmware/application/apps/ui_level.cpp @@ -68,9 +68,6 @@ LevelView::LevelView(NavigationView& nav) rssi.set_vertical_rssi(true); - field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); }; - field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99); - change_mode(NFM_MODULATION); // Start on AM field_mode.set_by_value(NFM_MODULATION); // Reflect the mode into the manual selector @@ -135,7 +132,7 @@ LevelView::LevelView(NavigationView& nav) audio::output::stop(); } else if (v == 1) { audio::output::start(); - this->on_headphone_volume_changed((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99); + receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // TODO: Needed? } else { } }; @@ -158,11 +155,6 @@ LevelView::LevelView(NavigationView& nav) freq_stats_db.set_style(&style_white); } -void LevelView::on_headphone_volume_changed(int32_t v) { - const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max; - receiver_model.set_headphone_volume(new_volume); -} - void LevelView::on_statistics_update(const ChannelStatistics& statistics) { static int last_max_db = -1000; static int last_min_rssi = -1000; diff --git a/firmware/application/apps/ui_level.hpp b/firmware/application/apps/ui_level.hpp index b932ce99..2b043569 100644 --- a/firmware/application/apps/ui_level.hpp +++ b/firmware/application/apps/ui_level.hpp @@ -117,13 +117,8 @@ class LevelView : public View { RFAmpField field_rf_amp{ {18 * 8, 0 * 16}}; - NumberField field_volume{ - {24 * 8, 0 * 16}, - 2, - {0, 99}, - 1, - ' ', - }; + AudioVolumeField field_volume{ + {24 * 8, 0 * 16}}; OptionsField field_bw{ {3 * 8, 1 * 16}, @@ -202,7 +197,6 @@ class LevelView : public View { }; void handle_coded_squelch(const uint32_t value); - void on_headphone_volume_changed(int32_t v); MessageHandlerRegistration message_handler_coded_squelch{ Message::ID::CodedSquelch, diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index 972ddb13..cfb36a8d 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -196,13 +196,6 @@ void MicTXView::rxaudio(bool is_on) { } } -void MicTXView::on_headphone_volume_changed(int32_t v) { - // if (rx_enabled) { - const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max; - receiver_model.set_headphone_volume(new_volume); - //} -} - void MicTXView::set_ptt_visibility(bool v) { tx_button.hidden(!v); } @@ -526,9 +519,6 @@ MicTXView::MicTXView( set_dirty(); // Refresh interface }; - field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99); - field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); }; - field_rxbw.on_change = [this](size_t, int32_t v) { if (!(enable_am || enable_usb || enable_lsb || enable_dsb || enable_wfm)) { // In Previous fw versions, that nbfm_configuration(n) was done in any mode (FM/AM/SSB/DSB)...strictly speaking only need it in (NFM/FM) diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp index 6cfe9c13..372326cd 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -76,7 +76,6 @@ class MicTXView : public View { void configure_baseband(); void rxaudio(bool is_on); - void on_headphone_volume_changed(int32_t v); void set_ptt_visibility(bool v); @@ -279,13 +278,8 @@ class MicTXView : public View { "F TX=RX", false}; - NumberField field_volume{ - {9 * 8, (23 * 8) + 2}, - 2, - {0, 99}, - 1, - ' ', - }; + AudioVolumeField field_volume{ + {9 * 8, (23 * 8) + 2}}; OptionsField field_rxbw{ {19 * 8, (23 * 8) + 2}, diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index 26dd5ffd..c01e7bb3 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -250,7 +250,7 @@ bool ReconView::recon_save_config_to_sd() { void ReconView::audio_output_start() { audio::output::start(); - this->on_headphone_volume_changed((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99); + receiver_model.set_headphone_volume(receiver_model.headphone_volume()); } void ReconView::recon_redraw() { @@ -868,10 +868,6 @@ ReconView::ReconView(NavigationView& nav) squelch = v; }; - field_volume.on_change = [this](int32_t v) { - this->on_headphone_volume_changed(v); - }; - // PRE-CONFIGURATION: button_scanner_mode.set_style(&style_blue); button_scanner_mode.set_text("RECON"); @@ -886,8 +882,6 @@ ReconView::ReconView(NavigationView& nav) field_lock_wait.set_value(recon_lock_duration); colorize_waits(); - field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99); - // fill modulation and step options freqman_set_modulation_option(field_mode); freqman_set_step_option(step_mode); @@ -1301,11 +1295,6 @@ void ReconView::on_stepper_delta(int32_t v) { timer = 0; } -void ReconView::on_headphone_volume_changed(int32_t v) { - const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max; - receiver_model.set_headphone_volume(new_volume); -} - size_t ReconView::change_mode(freqman_index_t new_mod) { field_mode.on_change = [this](size_t, OptionsField::value_t) {}; field_bw.on_change = [this](size_t, OptionsField::value_t) {}; diff --git a/firmware/application/apps/ui_recon.hpp b/firmware/application/apps/ui_recon.hpp index b626f1ad..b594a672 100644 --- a/firmware/application/apps/ui_recon.hpp +++ b/firmware/application/apps/ui_recon.hpp @@ -112,7 +112,6 @@ class ReconView : public View { void recon_resume(); void frequency_file_load(bool stop_all_before = false); void on_statistics_update(const ChannelStatistics& statistics); - void on_headphone_volume_changed(int32_t v); void on_index_delta(int32_t v); void on_stepper_delta(int32_t v); void colorize_waits(); @@ -196,13 +195,8 @@ class ReconView : public View { RFAmpField field_rf_amp{ {18 * 8, 0 * 16}}; - NumberField field_volume{ - {24 * 8, 0 * 16}, - 2, - {0, 99}, - 1, - ' ', - }; + AudioVolumeField field_volume{ + {24 * 8, 0 * 16}}; OptionsField field_bw{ {3 * 8, 1 * 16}, diff --git a/firmware/application/apps/ui_scanner.cpp b/firmware/application/apps/ui_scanner.cpp index 0bf4aa45..de0b6c40 100644 --- a/firmware/application/apps/ui_scanner.cpp +++ b/firmware/application/apps/ui_scanner.cpp @@ -558,9 +558,6 @@ ScannerView::ScannerView( field_squelch.on_change = [this](int32_t v) { squelch = v; }; field_squelch.set_value(-10); - field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99); - field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); }; - // LEARN FREQUENCIES std::string scanner_txt = "SCANNER"; frequency_file_load(scanner_txt); @@ -667,8 +664,8 @@ void ScannerView::update_squelch_while_paused(int32_t max_db) { // Update audio & color based on signal level even if paused if (++color_timer > 2) { // Counter to reduce color toggling when weak signal if (max_db > squelch) { - audio::output::start(); // Re-enable audio when signal goes above squelch - on_headphone_volume_changed(field_volume.value()); // quick fix to make sure WM8731S chips don't stay silent after pause + audio::output::start(); // Re-enable audio when signal goes above squelch + receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // quick fix to make sure WM8731S chips don't stay silent after pause bigdisplay_update(BDC_GREEN); } else { audio::output::stop(); // Silence audio when signal drops below squelch @@ -730,7 +727,7 @@ void ScannerView::scan_pause() { scan_thread->set_scanning(false); // WE STOP SCANNING } audio::output::start(); - on_headphone_volume_changed(field_volume.value()); // quick fix to make sure WM8731S chips don't stay silent after pause + receiver_model.set_headphone_volume(receiver_model.headphone_volume()); // quick fix to make sure WM8731S chips don't stay silent after pause } void ScannerView::scan_resume() { @@ -749,11 +746,6 @@ void ScannerView::user_resume() { userpause = false; // Resume scanning } -void ScannerView::on_headphone_volume_changed(int32_t v) { - const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max; - receiver_model.set_headphone_volume(new_volume); -} - void ScannerView::change_mode(freqman_index_t new_mod) { // Before this, do a scan_thread->stop(); After this do a start_scan_thread() using option_t = std::pair; using options_t = std::vector; diff --git a/firmware/application/apps/ui_scanner.hpp b/firmware/application/apps/ui_scanner.hpp index cfe86bb3..90fd049f 100644 --- a/firmware/application/apps/ui_scanner.hpp +++ b/firmware/application/apps/ui_scanner.hpp @@ -134,7 +134,6 @@ class ScannerView : public View { void bigdisplay_update(int32_t); void update_squelch_while_paused(int32_t max_db); void on_statistics_update(const ChannelStatistics& statistics); - void on_headphone_volume_changed(int32_t v); void handle_retune(int64_t freq, uint32_t freq_idx); jammer::jammer_range_t frequency_range{false, 0, 0}; // perfect for manual scan task too... @@ -182,13 +181,8 @@ class ScannerView : public View { RFAmpField field_rf_amp{ {18 * 8, 0 * 16}}; - NumberField field_volume{ - {24 * 8, 0 * 16}, - 2, - {0, 99}, - 1, - ' ', - }; + AudioVolumeField field_volume{ + {24 * 8, 0 * 16}}; OptionsField field_bw{ {3 * 8, 1 * 16}, diff --git a/firmware/application/apps/ui_sonde.cpp b/firmware/application/apps/ui_sonde.cpp index a3c9c828..7bcc812d 100644 --- a/firmware/application/apps/ui_sonde.cpp +++ b/firmware/application/apps/ui_sonde.cpp @@ -128,13 +128,6 @@ SondeView::SondeView(NavigationView& nav) { if (logger) logger->append(LOG_ROOT_DIR "/SONDE.TXT"); - // initialize audio: - field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99); - - field_volume.on_change = [this](int32_t v) { - this->on_headphone_volume_changed(v); - }; - audio::output::start(); audio::output::speaker_unmute(); @@ -251,11 +244,6 @@ void SondeView::on_packet(const sonde::Packet& packet) { } } -void SondeView::on_headphone_volume_changed(int32_t v) { - const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max; - receiver_model.set_headphone_volume(new_volume); -} - void SondeView::set_target_frequency(const uint32_t new_value) { target_frequency_ = new_value; receiver_model.set_tuning_frequency(target_frequency_); diff --git a/firmware/application/apps/ui_sonde.hpp b/firmware/application/apps/ui_sonde.hpp index a0768548..b64bb36c 100644 --- a/firmware/application/apps/ui_sonde.hpp +++ b/firmware/application/apps/ui_sonde.hpp @@ -109,13 +109,8 @@ class SondeView : public View { {21 * 8, 0, 6 * 8, 4}, }; - NumberField field_volume{ - {28 * 8, 0 * 16}, - 2, - {0, 99}, - 1, - ' ', - }; + AudioVolumeField field_volume{ + {28 * 8, 0 * 16}}; Checkbox check_beep{ {22 * 8, 6 * 16}, @@ -181,7 +176,6 @@ class SondeView : public View { }}; void on_packet(const sonde::Packet& packet); - void on_headphone_volume_changed(int32_t v); char* float_to_char(float x, char* p); void set_target_frequency(const uint32_t new_value); diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index 827241ac..bdf3152d 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -35,6 +35,7 @@ using namespace portapack; #include "dsp_fir_taps.hpp" #include "dsp_iir.hpp" #include "dsp_iir_config.hpp" +#include "utility.hpp" namespace { @@ -154,6 +155,17 @@ void ReceiverModel::set_headphone_volume(volume_t v) { update_headphone_volume(); } +int32_t ReceiverModel::normalized_headphone_volume() const { + return (headphone_volume_ - audio::headphone::volume_range().max).decibel() + 99; +} + +void ReceiverModel::set_normalized_headphone_volume(int32_t v) { + // TODO: Linear map instead to ensure 0 is minimal value. + v = clip(v, 0, 99); + auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max; + set_headphone_volume(new_volume); +} + uint8_t ReceiverModel::squelch_level() const { return squelch_level_; } @@ -265,9 +277,6 @@ void ReceiverModel::update_sampling_rate() { } void ReceiverModel::update_headphone_volume() { - // TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do - // both? - audio::headphone::set_volume(headphone_volume_); } diff --git a/firmware/application/receiver_model.hpp b/firmware/application/receiver_model.hpp index cb1013a2..26631c14 100644 --- a/firmware/application/receiver_model.hpp +++ b/firmware/application/receiver_model.hpp @@ -74,6 +74,10 @@ class ReceiverModel { volume_t headphone_volume() const; void set_headphone_volume(volume_t v); + /* Volume range 0-99, normalized for audio HW. */ + int32_t normalized_headphone_volume() const; + void set_normalized_headphone_volume(int32_t v); + uint8_t squelch_level() const; void set_squelch_level(uint8_t v); diff --git a/firmware/application/ui/ui_receiver.cpp b/firmware/application/ui/ui_receiver.cpp index 6ad4d907..1614769a 100644 --- a/firmware/application/ui/ui_receiver.cpp +++ b/firmware/application/ui/ui_receiver.cpp @@ -381,4 +381,21 @@ void VGAGainField::on_focus() { } } +/* AudioVolumeField *******************************************************/ + +AudioVolumeField::AudioVolumeField( + Point parent_pos) + : NumberField{ + parent_pos, + /* length */ 2, + /* range */ {0, 99}, + /* step */ 1, + /* fill char */ ' '} { + set_value(receiver_model.normalized_headphone_volume()); + + on_change = [](int32_t v) { + receiver_model.set_normalized_headphone_volume(v); + }; +} + } /* namespace ui */ diff --git a/firmware/application/ui/ui_receiver.hpp b/firmware/application/ui/ui_receiver.hpp index a0d531f9..a9ae5ad0 100644 --- a/firmware/application/ui/ui_receiver.hpp +++ b/firmware/application/ui/ui_receiver.hpp @@ -337,6 +337,11 @@ class VGAGainField : public NumberField { void on_focus() override; }; +class AudioVolumeField : public NumberField { + public: + AudioVolumeField(Point parent_pos); +}; + } /* namespace ui */ #endif /*__UI_RECEIVER_H__*/ diff --git a/firmware/common/utility.hpp b/firmware/common/utility.hpp index 76d6adbf..6e29eebd 100644 --- a/firmware/common/utility.hpp +++ b/firmware/common/utility.hpp @@ -94,13 +94,22 @@ int fast_int_magnitude(int y, int x); int int_atan2(int y, int x); int32_t int16_sin_s4(int32_t x); +/* Returns value constrained to min and max. */ +template +constexpr const T& clip(const T& value, const T& minimum, const T& maximum) { + return std::max(std::min(value, maximum), minimum); +} + +// TODO: need to decide if this is inclusive or exclusive. +// The implementations are different and cause the subtle +// bugs mentioned below. template struct range_t { const T minimum; const T maximum; constexpr const T& clip(const T& value) const { - return std::max(std::min(value, maximum), minimum); + return ::clip(value, minimum, maximum); } constexpr void reset_if_outside(T& value, const T& reset_value) const {