Add AudioVolumeField -- cleanup (#1107)

* WIP Adding AudioVolumeField

* Fix build break

* Add Bernd to about

---------

Co-authored-by: kallanreed <kallanreed@outlook.com>
This commit is contained in:
Kyle Reed 2023-06-04 12:56:46 -07:00 committed by GitHub
parent 7e8a139732
commit 28319652c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 91 additions and 186 deletions

View File

@ -198,11 +198,6 @@ AnalogAudioView::AnalogAudioView(
this->on_show_options_modulation(); 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) { record_view.on_error = [&nav](std::string message) {
nav.display_modal("Error", 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); 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) { void AnalogAudioView::update_modulation(const ReceiverModel::Mode modulation) {
audio::output::mute(); audio::output::mute();
record_view.stop(); record_view.stop();

View File

@ -207,13 +207,8 @@ class AnalogAudioView : public View {
{"SPEC", toUType(ReceiverModel::Mode::SpectrumAnalysis)}, {"SPEC", toUType(ReceiverModel::Mode::SpectrumAnalysis)},
}}; }};
NumberField field_volume{ AudioVolumeField field_volume{
{28 * 8, 0 * 16}, {28 * 8, 0 * 16}};
2,
{0, 99},
1,
' ',
};
Text text_ctcss{ Text text_ctcss{
{19 * 8, 1 * 16, 11 * 8, 1 * 16}, {19 * 8, 1 * 16, 11 * 8, 1 * 16},
@ -239,7 +234,6 @@ class AnalogAudioView : public View {
void on_show_options_modulation(); void on_show_options_modulation();
void on_frequency_step_changed(rf::Frequency f); void on_frequency_step_changed(rf::Frequency f);
void on_reference_ppm_correction_changed(int32_t v); void on_reference_ppm_correction_changed(int32_t v);
void on_headphone_volume_changed(int32_t v);
void on_edit_frequency(); void on_edit_frequency();
void remove_options_widget(); void remove_options_widget();

View File

@ -100,11 +100,6 @@ AnalogTvView::AnalogTvView(
this->on_show_options_modulation(); 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) { tv.on_select = [this](int32_t offset) {
field_frequency.set_value(receiver_model.tuning_frequency() + 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); 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) { void AnalogTvView::update_modulation(const ReceiverModel::Mode modulation) {
audio::output::mute(); audio::output::mute();

View File

@ -98,13 +98,8 @@ class AnalogTvView : public View {
{"TV ", toUType(ReceiverModel::Mode::WidebandFMAudio)}, {"TV ", toUType(ReceiverModel::Mode::WidebandFMAudio)},
}}; }};
NumberField field_volume{ AudioVolumeField field_volume{
{27 * 8, 0 * 16}, {27 * 8, 0 * 16}};
3,
{0, 255},
1,
' ',
};
std::unique_ptr<Widget> options_widget{}; std::unique_ptr<Widget> options_widget{};
@ -118,7 +113,6 @@ class AnalogTvView : public View {
void on_show_options_modulation(); void on_show_options_modulation();
void on_frequency_step_changed(rf::Frequency f); void on_frequency_step_changed(rf::Frequency f);
void on_reference_ppm_correction_changed(int32_t v); void on_reference_ppm_correction_changed(int32_t v);
void on_headphone_volume_changed(int32_t v);
void on_edit_frequency(); void on_edit_frequency();
void remove_options_widget(); void remove_options_widget();

View File

@ -79,18 +79,21 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) {
update_freq(f); update_freq(f);
}; };
// load app settings // load app settings TODO: needed?
auto rc = settings.load("rx_pocsag", &app_settings); auto rc = settings.load("rx_pocsag", &app_settings);
if (rc == SETTINGS_OK) { if (rc == SETTINGS_OK) {
field_lna.set_value(app_settings.lna); field_lna.set_value(app_settings.lna);
field_vga.set_value(app_settings.vga); field_vga.set_value(app_settings.vga);
field_rf_amp.set_value(app_settings.rx_amp); field_rf_amp.set_value(app_settings.rx_amp);
field_frequency.set_value(app_settings.rx_frequency); 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()); field_frequency.set_value(receiver_model.tuning_frequency());
}
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
receiver_model.set_sampling_rate(3072000); receiver_model.set_sampling_rate(3072000);
receiver_model.set_baseband_bandwidth(1750000); receiver_model.set_baseband_bandwidth(1750000);
receiver_model.enable(); receiver_model.enable();
@ -105,22 +108,10 @@ POCSAGAppView::POCSAGAppView(NavigationView& nav) {
}; };
}; };
check_log.set_value(logging); // TODO app setting instead?
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;
};
ignore_address = persistent_memory::pocsag_ignore_address(); ignore_address = persistent_memory::pocsag_ignore_address();
// TODO is this common enough for a helper?
for (size_t c = 0; c < 7; c++) { for (size_t c = 0; c < 7; c++) {
sym_ignore.set_sym(6 - c, ignore_address % 10); sym_ignore.set_sym(6 - c, ignore_address % 10);
ignore_address /= 10; ignore_address /= 10;
@ -150,20 +141,6 @@ POCSAGAppView::~POCSAGAppView() {
baseband::shutdown(); 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) { void POCSAGAppView::on_packet(const POCSAGPacketMessage* message) {
std::string alphanum_text = ""; std::string alphanum_text = "";
@ -172,14 +149,14 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage* message) {
else { else {
pocsag_decode_batch(message->packet, &pocsag_state); 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) // Ignore (inform, but no log)
// console.write("\n\x1B\x03" + to_string_time(message->packet.timestamp()) + // console.write("\n\x1B\x03" + to_string_time(message->packet.timestamp()) +
// " Ignored address " + to_string_dec_uint(pocsag_state.address)); // " Ignored address " + to_string_dec_uint(pocsag_state.address));
return; return;
} }
// Too many errors for reliable decode // Too many errors for reliable decode
if ((ignore) && (pocsag_state.errors >= 3)) { if ((ignore()) && (pocsag_state.errors >= 3)) {
return; return;
} }
@ -199,7 +176,7 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage* message) {
console.write(console_info); console.write(console_info);
if (logger && logging) { if (logger && logging()) {
logger->log_decoded(message->packet, to_string_dec_uint(pocsag_state.address) + logger->log_decoded(message->packet, to_string_dec_uint(pocsag_state.address) +
" F" + to_string_dec_uint(pocsag_state.function) + " F" + to_string_dec_uint(pocsag_state.function) +
" Address only"); " Address only");
@ -218,15 +195,16 @@ void POCSAGAppView::on_packet(const POCSAGPacketMessage* message) {
console.write(pocsag_state.output); console.write(pocsag_state.output);
} }
if (logger && logging) if (logger && logging())
logger->log_decoded(message->packet, to_string_dec_uint(pocsag_state.address) + logger->log_decoded(message->packet, to_string_dec_uint(pocsag_state.address) +
" F" + to_string_dec_uint(pocsag_state.function) + " F" + to_string_dec_uint(pocsag_state.function) +
" Alpha: " + pocsag_state.output); " Alpha: " + pocsag_state.output);
} }
} }
// TODO: make setting.
// Log raw data whatever it contains // Log raw data whatever it contains
if (logger && logging) if (logger && logging())
logger->log_raw_data(message->packet, target_frequency()); logger->log_raw_data(message->packet, target_frequency());
} }

View File

@ -52,20 +52,18 @@ class POCSAGAppView : public View {
POCSAGAppView(NavigationView& nav); POCSAGAppView(NavigationView& nav);
~POCSAGAppView(); ~POCSAGAppView();
void set_parent_rect(const Rect new_parent_rect) override;
void focus() override;
std::string title() const override { return "POCSAG RX"; }; std::string title() const override { return "POCSAG RX"; };
private: private:
static constexpr uint32_t initial_target_frequency = 466175000; 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 // app save settings
std::app_settings settings{}; std::app_settings settings{};
std::app_settings::AppSettings app_settings{}; std::app_settings::AppSettings app_settings{};
bool logging{false};
bool ignore{false};
uint32_t last_address = 0xFFFFFFFF; uint32_t last_address = 0xFFFFFFFF;
pocsag::POCSAGState pocsag_state{}; pocsag::POCSAGState pocsag_state{};
@ -88,13 +86,9 @@ class POCSAGAppView : public View {
FrequencyField field_frequency{ FrequencyField field_frequency{
{0 * 8, 0 * 8}, {0 * 8, 0 * 8},
}; };
NumberField field_volume{
{28 * 8, 0 * 16}, AudioVolumeField field_volume{
2, {28 * 8, 0 * 16}};
{0, 99},
1,
' ',
};
Checkbox check_ignore{ Checkbox check_ignore{
{0 * 8, 21}, {0 * 8, 21},
@ -105,10 +99,11 @@ class POCSAGAppView : public View {
{13 * 8, 25}, {13 * 8, 25},
7, 7,
SymField::SYMFIELD_DEC}; SymField::SYMFIELD_DEC};
Checkbox check_log{ Checkbox check_log{
{240 - 8 * 8, 21}, {240 - 8 * 8, 21},
3, 3,
"LOG", "Log",
false}; false};
Console console{ Console console{
@ -122,8 +117,6 @@ class POCSAGAppView : public View {
void on_packet(const POCSAGPacketMessage* message); void on_packet(const POCSAGPacketMessage* message);
void on_headphone_volume_changed(int32_t v);
uint32_t target_frequency() const; uint32_t target_frequency() const;
void set_target_frequency(const uint32_t new_value); void set_target_frequency(const uint32_t new_value);

View File

@ -33,6 +33,7 @@ void AboutView::update() {
console.writeln("heurist1,intoxsick,ckuethe"); console.writeln("heurist1,intoxsick,ckuethe");
console.writeln("notpike,jLynx,zigad"); console.writeln("notpike,jLynx,zigad");
console.writeln("MichalLeonBorsuk,jimilinuxguy"); console.writeln("MichalLeonBorsuk,jimilinuxguy");
console.writeln("kallanreed,bernd-herzog");
console.writeln(""); console.writeln("");
break; break;

View File

@ -68,9 +68,6 @@ LevelView::LevelView(NavigationView& nav)
rssi.set_vertical_rssi(true); 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 change_mode(NFM_MODULATION); // Start on AM
field_mode.set_by_value(NFM_MODULATION); // Reflect the mode into the manual selector 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(); audio::output::stop();
} else if (v == 1) { } else if (v == 1) {
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()); // TODO: Needed?
} else { } else {
} }
}; };
@ -158,11 +155,6 @@ LevelView::LevelView(NavigationView& nav)
freq_stats_db.set_style(&style_white); 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) { void LevelView::on_statistics_update(const ChannelStatistics& statistics) {
static int last_max_db = -1000; static int last_max_db = -1000;
static int last_min_rssi = -1000; static int last_min_rssi = -1000;

View File

@ -117,13 +117,8 @@ class LevelView : public View {
RFAmpField field_rf_amp{ RFAmpField field_rf_amp{
{18 * 8, 0 * 16}}; {18 * 8, 0 * 16}};
NumberField field_volume{ AudioVolumeField field_volume{
{24 * 8, 0 * 16}, {24 * 8, 0 * 16}};
2,
{0, 99},
1,
' ',
};
OptionsField field_bw{ OptionsField field_bw{
{3 * 8, 1 * 16}, {3 * 8, 1 * 16},
@ -202,7 +197,6 @@ class LevelView : public View {
}; };
void handle_coded_squelch(const uint32_t value); void handle_coded_squelch(const uint32_t value);
void on_headphone_volume_changed(int32_t v);
MessageHandlerRegistration message_handler_coded_squelch{ MessageHandlerRegistration message_handler_coded_squelch{
Message::ID::CodedSquelch, Message::ID::CodedSquelch,

View File

@ -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) { void MicTXView::set_ptt_visibility(bool v) {
tx_button.hidden(!v); tx_button.hidden(!v);
} }
@ -526,9 +519,6 @@ MicTXView::MicTXView(
set_dirty(); // Refresh interface 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) { field_rxbw.on_change = [this](size_t, int32_t v) {
if (!(enable_am || enable_usb || enable_lsb || enable_dsb || enable_wfm)) { 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) // 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)

View File

@ -76,7 +76,6 @@ class MicTXView : public View {
void configure_baseband(); void configure_baseband();
void rxaudio(bool is_on); void rxaudio(bool is_on);
void on_headphone_volume_changed(int32_t v);
void set_ptt_visibility(bool v); void set_ptt_visibility(bool v);
@ -279,13 +278,8 @@ class MicTXView : public View {
"F TX=RX", "F TX=RX",
false}; false};
NumberField field_volume{ AudioVolumeField field_volume{
{9 * 8, (23 * 8) + 2}, {9 * 8, (23 * 8) + 2}};
2,
{0, 99},
1,
' ',
};
OptionsField field_rxbw{ OptionsField field_rxbw{
{19 * 8, (23 * 8) + 2}, {19 * 8, (23 * 8) + 2},

View File

@ -250,7 +250,7 @@ bool ReconView::recon_save_config_to_sd() {
void ReconView::audio_output_start() { void ReconView::audio_output_start() {
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() { void ReconView::recon_redraw() {
@ -868,10 +868,6 @@ ReconView::ReconView(NavigationView& nav)
squelch = v; squelch = v;
}; };
field_volume.on_change = [this](int32_t v) {
this->on_headphone_volume_changed(v);
};
// PRE-CONFIGURATION: // PRE-CONFIGURATION:
button_scanner_mode.set_style(&style_blue); button_scanner_mode.set_style(&style_blue);
button_scanner_mode.set_text("RECON"); button_scanner_mode.set_text("RECON");
@ -886,8 +882,6 @@ ReconView::ReconView(NavigationView& nav)
field_lock_wait.set_value(recon_lock_duration); field_lock_wait.set_value(recon_lock_duration);
colorize_waits(); colorize_waits();
field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99);
// fill modulation and step options // fill modulation and step options
freqman_set_modulation_option(field_mode); freqman_set_modulation_option(field_mode);
freqman_set_step_option(step_mode); freqman_set_step_option(step_mode);
@ -1301,11 +1295,6 @@ void ReconView::on_stepper_delta(int32_t v) {
timer = 0; 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) { size_t ReconView::change_mode(freqman_index_t new_mod) {
field_mode.on_change = [this](size_t, OptionsField::value_t) {}; field_mode.on_change = [this](size_t, OptionsField::value_t) {};
field_bw.on_change = [this](size_t, OptionsField::value_t) {}; field_bw.on_change = [this](size_t, OptionsField::value_t) {};

View File

@ -112,7 +112,6 @@ class ReconView : public View {
void recon_resume(); void recon_resume();
void frequency_file_load(bool stop_all_before = false); void frequency_file_load(bool stop_all_before = false);
void on_statistics_update(const ChannelStatistics& statistics); void on_statistics_update(const ChannelStatistics& statistics);
void on_headphone_volume_changed(int32_t v);
void on_index_delta(int32_t v); void on_index_delta(int32_t v);
void on_stepper_delta(int32_t v); void on_stepper_delta(int32_t v);
void colorize_waits(); void colorize_waits();
@ -196,13 +195,8 @@ class ReconView : public View {
RFAmpField field_rf_amp{ RFAmpField field_rf_amp{
{18 * 8, 0 * 16}}; {18 * 8, 0 * 16}};
NumberField field_volume{ AudioVolumeField field_volume{
{24 * 8, 0 * 16}, {24 * 8, 0 * 16}};
2,
{0, 99},
1,
' ',
};
OptionsField field_bw{ OptionsField field_bw{
{3 * 8, 1 * 16}, {3 * 8, 1 * 16},

View File

@ -558,9 +558,6 @@ ScannerView::ScannerView(
field_squelch.on_change = [this](int32_t v) { squelch = v; }; field_squelch.on_change = [this](int32_t v) { squelch = v; };
field_squelch.set_value(-10); 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 // LEARN FREQUENCIES
std::string scanner_txt = "SCANNER"; std::string scanner_txt = "SCANNER";
frequency_file_load(scanner_txt); 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 // Update audio & color based on signal level even if paused
if (++color_timer > 2) { // Counter to reduce color toggling when weak signal if (++color_timer > 2) { // Counter to reduce color toggling when weak signal
if (max_db > squelch) { if (max_db > squelch) {
audio::output::start(); // Re-enable audio when signal goes above 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 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); bigdisplay_update(BDC_GREEN);
} else { } else {
audio::output::stop(); // Silence audio when signal drops below squelch 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 scan_thread->set_scanning(false); // WE STOP SCANNING
} }
audio::output::start(); 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() { void ScannerView::scan_resume() {
@ -749,11 +746,6 @@ void ScannerView::user_resume() {
userpause = false; // Resume scanning 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() 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<std::string, int32_t>; using option_t = std::pair<std::string, int32_t>;
using options_t = std::vector<option_t>; using options_t = std::vector<option_t>;

View File

@ -134,7 +134,6 @@ class ScannerView : public View {
void bigdisplay_update(int32_t); void bigdisplay_update(int32_t);
void update_squelch_while_paused(int32_t max_db); void update_squelch_while_paused(int32_t max_db);
void on_statistics_update(const ChannelStatistics& statistics); 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); 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... 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{ RFAmpField field_rf_amp{
{18 * 8, 0 * 16}}; {18 * 8, 0 * 16}};
NumberField field_volume{ AudioVolumeField field_volume{
{24 * 8, 0 * 16}, {24 * 8, 0 * 16}};
2,
{0, 99},
1,
' ',
};
OptionsField field_bw{ OptionsField field_bw{
{3 * 8, 1 * 16}, {3 * 8, 1 * 16},

View File

@ -128,13 +128,6 @@ SondeView::SondeView(NavigationView& nav) {
if (logger) if (logger)
logger->append(LOG_ROOT_DIR "/SONDE.TXT"); 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::start();
audio::output::speaker_unmute(); 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) { void SondeView::set_target_frequency(const uint32_t new_value) {
target_frequency_ = new_value; target_frequency_ = new_value;
receiver_model.set_tuning_frequency(target_frequency_); receiver_model.set_tuning_frequency(target_frequency_);

View File

@ -109,13 +109,8 @@ class SondeView : public View {
{21 * 8, 0, 6 * 8, 4}, {21 * 8, 0, 6 * 8, 4},
}; };
NumberField field_volume{ AudioVolumeField field_volume{
{28 * 8, 0 * 16}, {28 * 8, 0 * 16}};
2,
{0, 99},
1,
' ',
};
Checkbox check_beep{ Checkbox check_beep{
{22 * 8, 6 * 16}, {22 * 8, 6 * 16},
@ -181,7 +176,6 @@ class SondeView : public View {
}}; }};
void on_packet(const sonde::Packet& packet); void on_packet(const sonde::Packet& packet);
void on_headphone_volume_changed(int32_t v);
char* float_to_char(float x, char* p); char* float_to_char(float x, char* p);
void set_target_frequency(const uint32_t new_value); void set_target_frequency(const uint32_t new_value);

View File

@ -35,6 +35,7 @@ using namespace portapack;
#include "dsp_fir_taps.hpp" #include "dsp_fir_taps.hpp"
#include "dsp_iir.hpp" #include "dsp_iir.hpp"
#include "dsp_iir_config.hpp" #include "dsp_iir_config.hpp"
#include "utility.hpp"
namespace { namespace {
@ -154,6 +155,17 @@ void ReceiverModel::set_headphone_volume(volume_t v) {
update_headphone_volume(); 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<int32_t>(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 { uint8_t ReceiverModel::squelch_level() const {
return squelch_level_; return squelch_level_;
} }
@ -265,9 +277,6 @@ void ReceiverModel::update_sampling_rate() {
} }
void ReceiverModel::update_headphone_volume() { 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_); audio::headphone::set_volume(headphone_volume_);
} }

View File

@ -74,6 +74,10 @@ class ReceiverModel {
volume_t headphone_volume() const; volume_t headphone_volume() const;
void set_headphone_volume(volume_t v); 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; uint8_t squelch_level() const;
void set_squelch_level(uint8_t v); void set_squelch_level(uint8_t v);

View File

@ -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 */ } /* namespace ui */

View File

@ -337,6 +337,11 @@ class VGAGainField : public NumberField {
void on_focus() override; void on_focus() override;
}; };
class AudioVolumeField : public NumberField {
public:
AudioVolumeField(Point parent_pos);
};
} /* namespace ui */ } /* namespace ui */
#endif /*__UI_RECEIVER_H__*/ #endif /*__UI_RECEIVER_H__*/

View File

@ -94,13 +94,22 @@ int fast_int_magnitude(int y, int x);
int int_atan2(int y, int x); int int_atan2(int y, int x);
int32_t int16_sin_s4(int32_t x); int32_t int16_sin_s4(int32_t x);
/* Returns value constrained to min and max. */
template <class T>
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 <class T> template <class T>
struct range_t { struct range_t {
const T minimum; const T minimum;
const T maximum; const T maximum;
constexpr const T& clip(const T& value) const { 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 { constexpr void reset_if_outside(T& value, const T& reset_value) const {