diff --git a/firmware/application/apps/ui_level.cpp b/firmware/application/apps/ui_level.cpp index 0a3e8fa20..3a1bbec92 100644 --- a/firmware/application/apps/ui_level.cpp +++ b/firmware/application/apps/ui_level.cpp @@ -24,7 +24,9 @@ #include "ui_level.hpp" #include "ui_fileman.hpp" #include "ui_freqman.hpp" +#include "baseband_api.hpp" #include "file.hpp" +#include "oversample.hpp" using namespace portapack; using namespace tonekey; @@ -174,48 +176,52 @@ size_t LevelView::change_mode(freqman_index_t new_mod) { switch (new_mod) { case AM_MODULATION: freqman_set_bandwidth_option(new_mod, field_bw); - // bw DSB (0) default - field_bw.set_by_value(0); baseband::run_image(portapack::spi_flash::image_tag_am_audio); receiver_model.set_modulation(ReceiverModel::Mode::AMAudio); receiver_model.set_am_configuration(field_bw.selected_index_value()); field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_am_configuration(n); }; + // bw DSB (0) default + field_bw.set_by_value(0); text_ctcss.set(" "); break; case NFM_MODULATION: freqman_set_bandwidth_option(new_mod, field_bw); - // bw 16k (2) default - field_bw.set_by_value(2); baseband::run_image(portapack::spi_flash::image_tag_nfm_audio); receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); receiver_model.set_nbfm_configuration(field_bw.selected_index_value()); field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_nbfm_configuration(n); }; + // bw 16k (2) default + field_bw.set_by_value(2); break; case WFM_MODULATION: freqman_set_bandwidth_option(new_mod, field_bw); - // bw 200k (0) only/default - field_bw.set_by_value(0); baseband::run_image(portapack::spi_flash::image_tag_wfm_audio); receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio); receiver_model.set_wfm_configuration(field_bw.selected_index_value()); field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_wfm_configuration(n); }; + // bw 200k (0) only/default + field_bw.set_by_value(0); text_ctcss.set(" "); break; case SPEC_MODULATION: freqman_set_bandwidth_option(new_mod, field_bw); baseband::run_image(portapack::spi_flash::image_tag_capture); receiver_model.set_modulation(ReceiverModel::Mode::Capture); - field_bw.set_by_value(0); field_bw.on_change = [this](size_t, OptionsField::value_t sampling_rate) { - auto anti_alias_baseband_bandwidth_filter = filter_bandwidth_for_sampling_rate(sampling_rate); - receiver_model.set_sampling_rate(sampling_rate); - receiver_model.set_baseband_bandwidth(anti_alias_baseband_bandwidth_filter); + // Baseband needs to know the desired sampling and oversampling rates. + baseband::set_sample_rate(sampling_rate, get_oversample_rate(sampling_rate)); + + // The radio needs to know the effective sampling rate. + auto actual_sampling_rate = get_actual_sample_rate(sampling_rate); + receiver_model.set_sampling_rate(actual_sampling_rate); + receiver_model.set_baseband_bandwidth(filter_bandwidth_for_sampling_rate(actual_sampling_rate)); }; + field_bw.set_by_value(0); default: break; } if (new_mod != SPEC_MODULATION) { - // reset receiver model to fix bug when going from SPEC to audio, the sound is distorded + // Reset receiver model to fix bug when going from SPEC to audio, the sound is distorted. receiver_model.set_sampling_rate(3072000); receiver_model.set_baseband_bandwidth(1750000); } diff --git a/firmware/application/apps/ui_recon.cpp b/firmware/application/apps/ui_recon.cpp index c2d3e4f9d..4df0698d9 100644 --- a/firmware/application/apps/ui_recon.cpp +++ b/firmware/application/apps/ui_recon.cpp @@ -1124,48 +1124,50 @@ size_t ReconView::change_mode(freqman_index_t new_mod) { switch (new_mod) { case AM_MODULATION: freqman_set_bandwidth_option(new_mod, field_bw); - // bw DSB (0) default - field_bw.set_by_value(0); baseband::run_image(portapack::spi_flash::image_tag_am_audio); receiver_model.set_modulation(ReceiverModel::Mode::AMAudio); receiver_model.set_am_configuration(field_bw.selected_index_value()); field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_am_configuration(n); }; + // bw DSB (0) default + field_bw.set_by_value(0); text_ctcss.set(" "); recording_sampling_rate = 12000; break; case NFM_MODULATION: freqman_set_bandwidth_option(new_mod, field_bw); - // bw 16k (2) default - field_bw.set_by_value(2); baseband::run_image(portapack::spi_flash::image_tag_nfm_audio); receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio); receiver_model.set_nbfm_configuration(field_bw.selected_index_value()); field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_nbfm_configuration(n); }; + // bw 16k (2) default + field_bw.set_by_value(2); recording_sampling_rate = 24000; break; case WFM_MODULATION: freqman_set_bandwidth_option(new_mod, field_bw); - // bw 200k (0) default - field_bw.set_by_value(0); baseband::run_image(portapack::spi_flash::image_tag_wfm_audio); receiver_model.set_modulation(ReceiverModel::Mode::WidebandFMAudio); receiver_model.set_wfm_configuration(field_bw.selected_index_value()); field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_wfm_configuration(n); }; + // bw 200k (0) default + field_bw.set_by_value(0); text_ctcss.set(" "); recording_sampling_rate = 48000; break; case SPEC_MODULATION: freqman_set_bandwidth_option(new_mod, field_bw); - // bw 12k5 (0) default - field_bw.set_by_value(0); baseband::run_image(portapack::spi_flash::image_tag_capture); receiver_model.set_modulation(ReceiverModel::Mode::Capture); field_bw.on_change = [this](size_t, OptionsField::value_t sampling_rate) { - auto anti_alias_baseband_bandwidth_filter = filter_bandwidth_for_sampling_rate(sampling_rate); - record_view->set_sampling_rate(sampling_rate); - receiver_model.set_sampling_rate(sampling_rate); - receiver_model.set_baseband_bandwidth(anti_alias_baseband_bandwidth_filter); + // record_view determines the correct oversampling to apply and returns the actual sample rate. + auto actual_sampling_rate = record_view->set_sampling_rate(sampling_rate); + + // The radio needs to know the effective sampling rate. + receiver_model.set_sampling_rate(actual_sampling_rate); + receiver_model.set_baseband_bandwidth(filter_bandwidth_for_sampling_rate(actual_sampling_rate)); }; + // bw 12k5 (0) default + field_bw.set_by_value(0); text_ctcss.set(" "); break; default: @@ -1173,7 +1175,6 @@ size_t ReconView::change_mode(freqman_index_t new_mod) { } if (new_mod != SPEC_MODULATION) { button_audio_app.set_text("AUDIO"); - // TODO: Oversampling. record_view->set_sampling_rate(recording_sampling_rate); // reset receiver model to fix bug when going from SPEC to audio, the sound is distorted receiver_model.set_sampling_rate(3072000); diff --git a/firmware/application/ui/ui_spectrum.cpp b/firmware/application/ui/ui_spectrum.cpp index 52c06839d..1ee2f7344 100644 --- a/firmware/application/ui/ui_spectrum.cpp +++ b/firmware/application/ui/ui_spectrum.cpp @@ -380,10 +380,10 @@ void WaterfallView::on_audio_spectrum() { } /* namespace spectrum */ -// TODO: Comments below refer to a fixed oversample rate (8x), cleanup. uint32_t filter_bandwidth_for_sampling_rate(int32_t sampling_rate) { switch (sampling_rate) { // Use the var fs (sampling_rate) to set up BPF aprox < fs_max / 2 by Nyquist theorem. - case 0 ... 3'500'000: // BW Captured range (0 <= 250kHz max) fs = 8x250k = 2000, 16x150k = 2400, 32x100k = 3200, 32x75k = 2400, (future 64x40 khz = 2400) + case 0 ... 3'500'000: // BW Captured range BW (<=250K) : fs = 8x250k = 2000k, 16x150k = 2400k, 16x100k=1600k, + // 32x75k = 2400k, 32x50k=1600, 32x32k=1024, 64x25k = 1600k, 64x16k = 1024k, 64x12k5 = 800k. return 1'750'000; // Minimum BPF MAX2837 for all those lower BW options. case 4'000'000 ... 7'000'000: // OVS x8, BW capture range (500k...750kHz max) fs_max = 8 x 750k = 6Mhz