diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 2d5acdf8be..8a20f09106 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -500,6 +500,13 @@ bool MainWindow::loadConfig(const QString& cfgfile, bool check_crash, restoreState(m_settings->value("gui/state", saveState()).toByteArray()); } + int_val = m_settings->value("output/sample_rate", 48000).toInt(&conv_ok); + if (conv_ok && (int_val > 0)) + { + rx->set_audio_rate(int_val); + uiDockAudio->setFftSampleRate(int_val); + } + QString indev = m_settings->value("input/device", "").toString(); if (!indev.isEmpty()) { @@ -633,6 +640,7 @@ bool MainWindow::loadConfig(const QString& cfgfile, bool check_crash, uiDockFft->readSettings(m_settings); uiDockAudio->readSettings(m_settings); dxc_options->readSettings(m_settings); + rx->commit_audio_rate(); { int64_val = m_settings->value("input/frequency", 14236000).toLongLong(&conv_ok); @@ -1063,6 +1071,7 @@ void MainWindow::selectDemod(int mode_idx) int filter_preset = uiDockRxOpt->currentFilter(); int flo=0, fhi=0, click_res=100; bool rds_enabled; + int audio_rate = rx->get_audio_rate(); // validate mode_idx if (mode_idx < DockRxOpt::MODE_OFF || mode_idx >= DockRxOpt::MODE_LAST) @@ -1101,27 +1110,27 @@ void MainWindow::selectDemod(int mode_idx) /* Raw I/Q; max 96 ksps*/ rx->set_demod(receiver::RX_DEMOD_NONE); ui->plotter->setDemodRanges(-40000, -200, 200, 40000, true); - uiDockAudio->setFftRange(0,24000); + uiDockAudio->setFftRange(-std::min(24000, audio_rate / 2), std::min(24000, audio_rate / 2)); click_res = 100; break; case DockRxOpt::MODE_AM: rx->set_demod(receiver::RX_DEMOD_AM); ui->plotter->setDemodRanges(-40000, -200, 200, 40000, true); - uiDockAudio->setFftRange(0,6000); + uiDockAudio->setFftRange(0, std::min(6000, audio_rate / 2)); click_res = 100; break; case DockRxOpt::MODE_AM_SYNC: rx->set_demod(receiver::RX_DEMOD_AMSYNC); ui->plotter->setDemodRanges(-40000, -200, 200, 40000, true); - uiDockAudio->setFftRange(0,6000); + uiDockAudio->setFftRange(0, std::min(6000, audio_rate / 2)); click_res = 100; break; case DockRxOpt::MODE_NFM: ui->plotter->setDemodRanges(-40000, -1000, 1000, 40000, true); - uiDockAudio->setFftRange(0, 5000); + uiDockAudio->setFftRange(0, std::min(5000, audio_rate / 2)); rx->set_demod(receiver::RX_DEMOD_NFM); rx->set_fm_maxdev(uiDockRxOpt->currentMaxdev()); rx->set_fm_deemph(uiDockRxOpt->currentEmph()); @@ -1133,7 +1142,7 @@ void MainWindow::selectDemod(int mode_idx) case DockRxOpt::MODE_WFM_STEREO_OIRT: /* Broadcast FM */ ui->plotter->setDemodRanges(-120e3, -10000, 10000, 120e3, true); - uiDockAudio->setFftRange(0,24000); /** FIXME: get audio rate from rx **/ + uiDockAudio->setFftRange(0, std::min(24000, audio_rate / 2)); click_res = 1000; if (mode_idx == DockRxOpt::MODE_WFM_MONO) rx->set_demod(receiver::RX_DEMOD_WFM_M); @@ -1151,7 +1160,7 @@ void MainWindow::selectDemod(int mode_idx) /* LSB */ rx->set_demod(receiver::RX_DEMOD_SSB); ui->plotter->setDemodRanges(-40000, -100, -5000, 0, false); - uiDockAudio->setFftRange(0,3000); + uiDockAudio->setFftRange(0, std::min(3000, audio_rate / 2)); click_res = 100; break; @@ -1159,7 +1168,7 @@ void MainWindow::selectDemod(int mode_idx) /* USB */ rx->set_demod(receiver::RX_DEMOD_SSB); ui->plotter->setDemodRanges(0, 5000, 100, 40000, false); - uiDockAudio->setFftRange(0,3000); + uiDockAudio->setFftRange(0, std::min(3000, audio_rate / 2)); click_res = 100; break; @@ -1168,7 +1177,7 @@ void MainWindow::selectDemod(int mode_idx) rx->set_demod(receiver::RX_DEMOD_SSB); cwofs = -uiDockRxOpt->getCwOffset(); ui->plotter->setDemodRanges(-5000, -100, 100, 5000, true); - uiDockAudio->setFftRange(0,1500); + uiDockAudio->setFftRange(0, std::min(1500, audio_rate / 2)); click_res = 10; break; @@ -1177,7 +1186,7 @@ void MainWindow::selectDemod(int mode_idx) rx->set_demod(receiver::RX_DEMOD_SSB); cwofs = uiDockRxOpt->getCwOffset(); ui->plotter->setDemodRanges(-5000, -100, 100, 5000, true); - uiDockAudio->setFftRange(0,1500); + uiDockAudio->setFftRange(0, std::min(1500, audio_rate / 2)); click_res = 10; break; diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index 8f36d78183..8ecf794276 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -124,14 +124,7 @@ receiver::receiver(const std::string input_device, audio_udp_sink = make_udp_sink_f(); -#ifdef WITH_PULSEAUDIO - audio_snk = make_pa_sink(audio_device, d_audio_rate, "GQRX", "Audio output"); -#elif WITH_PORTAUDIO - audio_snk = make_portaudio_sink(audio_device, d_audio_rate, "GQRX", "Audio output"); -#else - audio_snk = gr::audio::sink::make(d_audio_rate, audio_device, true); -#endif - + create_audio_device(audio_device); output_devstr = audio_device; /* wav sink and source is created when rec/play is started */ @@ -276,13 +269,7 @@ void receiver::set_output_device(const std::string device) audio_snk.reset(); try { -#ifdef WITH_PULSEAUDIO - audio_snk = make_pa_sink(device, d_audio_rate, "GQRX", "Audio output"); -#elif WITH_PORTAUDIO - audio_snk = make_portaudio_sink(device, d_audio_rate, "GQRX", "Audio output"); -#else - audio_snk = gr::audio::sink::make(d_audio_rate, device, true); -#endif + create_audio_device(device); if (d_demod != RX_DEMOD_OFF) { @@ -970,6 +957,27 @@ receiver::status receiver::set_amsync_pll_bw(float pll_bw) return STATUS_OK; } +receiver::status receiver::set_audio_rate(int rate) +{ + if(d_audio_rate != rate) + { + d_audio_rate = rate; + audio_fft->set_quad_rate(rate); + } + return STATUS_OK; +} + +receiver::status receiver::commit_audio_rate() +{ + rx->set_audio_rate(d_audio_rate); + return STATUS_OK; +} + +int receiver::get_audio_rate() +{ + return d_audio_rate; +} + receiver::status receiver::set_af_gain(float gain_db) { float k; @@ -1448,3 +1456,15 @@ std::string receiver::escape_filename(std::string filename) ss2 << std::quoted(ss1.str(), '\'', '\\'); return ss2.str(); } + +void receiver::create_audio_device(const std::string device) +{ +#ifdef WITH_PULSEAUDIO + audio_snk = make_pa_sink(device, d_audio_rate, "GQRX", "Audio output"); +#elif WITH_PORTAUDIO + audio_snk = make_portaudio_sink(device, d_audio_rate, "GQRX", "Audio output"); +#else + audio_snk = gr::audio::sink::make(d_audio_rate, device, true); +#endif + +} diff --git a/src/applications/gqrx/receiver.h b/src/applications/gqrx/receiver.h index abf827cb83..e72de51e7f 100644 --- a/src/applications/gqrx/receiver.h +++ b/src/applications/gqrx/receiver.h @@ -200,6 +200,9 @@ class receiver status set_amsync_pll_bw(float pll_bw); /* Audio parameters */ + status set_audio_rate(int rate); + status commit_audio_rate(); + int get_audio_rate(); status set_af_gain(float gain_db); status start_audio_recording(const std::string filename); status stop_audio_recording(); @@ -296,6 +299,7 @@ class receiver //! Get a path to a file containing random bytes static std::string get_zero_file(void); + void create_audio_device(const std::string device); }; #endif // RECEIVER_H diff --git a/src/dsp/fm_deemph.cpp b/src/dsp/fm_deemph.cpp index d37675d78b..f28cb63406 100644 --- a/src/dsp/fm_deemph.cpp +++ b/src/dsp/fm_deemph.cpp @@ -42,12 +42,13 @@ fm_deemph::fm_deemph(float quad_rate, double tau) : gr::hier_block2 ("fm_deemph", gr::io_signature::make (MIN_IN, MAX_IN, sizeof (float)), gr::io_signature::make (MIN_OUT, MAX_OUT, sizeof (float))), - d_quad_rate(quad_rate) + d_quad_rate(quad_rate), + d_tau(tau) { /* de-emphasis */ d_fftaps.resize(2); d_fbtaps.resize(2); - calculate_iir_taps(tau); + calculate_iir_taps(d_tau); d_deemph = gr::filter::iir_filter_ffd::make(d_fftaps, d_fbtaps, false); connect(self(), 0, d_deemph, 0); @@ -63,10 +64,19 @@ fm_deemph::~fm_deemph () */ void fm_deemph::set_tau(double tau) { - calculate_iir_taps(tau); + d_tau = tau; + calculate_iir_taps(d_tau); d_deemph->set_taps(d_fftaps, d_fbtaps); } +void fm_deemph::set_rate(double rate) +{ + d_quad_rate = rate; + calculate_iir_taps(d_tau); + d_deemph->set_taps(d_fftaps, d_fbtaps); +} + + /*! \brief Calculate taps for FM de-emph IIR filter. */ void fm_deemph::calculate_iir_taps(double tau) { diff --git a/src/dsp/fm_deemph.h b/src/dsp/fm_deemph.h index 0f040d0f41..f459993cfb 100644 --- a/src/dsp/fm_deemph.h +++ b/src/dsp/fm_deemph.h @@ -58,6 +58,7 @@ class fm_deemph : public gr::hier_block2 ~fm_deemph(); void set_tau(double tau); + void set_rate(double rate); private: /* GR blocks */ @@ -65,6 +66,7 @@ class fm_deemph : public gr::hier_block2 /* other parameters */ float d_quad_rate; /*! Quadrature rate. */ + double d_tau; /* De-emph IIR filter taps */ std::vector d_fftaps; /*! Feed forward taps. */ diff --git a/src/dsp/rx_fft.cpp b/src/dsp/rx_fft.cpp index 12d533b50b..a414e1cc8b 100644 --- a/src/dsp/rx_fft.cpp +++ b/src/dsp/rx_fft.cpp @@ -360,27 +360,41 @@ void rx_fft_f::apply_window(unsigned int size) } +/*! \brief Update circular buffer and FFT object. */ +void rx_fft_f::set_params() +{ + std::lock_guard lock(d_mutex); + + /* reset window */ + int wintype = d_wintype; // FIXME: would be nicer with a window_reset() + d_wintype = -1; + set_window_type(wintype); + + /* reset FFT object (also reset FFTW plan) */ + delete d_fft; +#if GNURADIO_VERSION < 0x030900 + d_fft = new gr::fft::fft_complex(d_fftsize, true); +#else + d_fft = new gr::fft::fft_complex_fwd(d_fftsize); +#endif +} + /*! \brief Set new FFT size. */ void rx_fft_f::set_fft_size(unsigned int fftsize) { if (fftsize != d_fftsize) { - std::lock_guard lock(d_mutex); - d_fftsize = fftsize; + set_params(); + } +} - /* reset window */ - int wintype = d_wintype; // FIXME: would be nicer with a window_reset() - d_wintype = -1; - set_window_type(wintype); - - /* reset FFT object (also reset FFTW plan) */ - delete d_fft; -#if GNURADIO_VERSION < 0x030900 - d_fft = new gr::fft::fft_complex(d_fftsize, true); -#else - d_fft = new gr::fft::fft_complex_fwd(d_fftsize); -#endif +/*! \brief Set new quadrature rate. */ +void rx_fft_f::set_quad_rate(double quad_rate) +{ + if (quad_rate != d_audiorate) { + d_audiorate = quad_rate; + set_params(); } } diff --git a/src/dsp/rx_fft.h b/src/dsp/rx_fft.h index cc035e0d47..0f20c0b4bc 100644 --- a/src/dsp/rx_fft.h +++ b/src/dsp/rx_fft.h @@ -164,6 +164,7 @@ class rx_fft_f : public gr::sync_block int get_window_type() const; void set_fft_size(unsigned int fftsize); + void set_quad_rate(double quad_rate); unsigned int get_fft_size() const; private: @@ -185,6 +186,7 @@ class rx_fft_f : public gr::sync_block std::chrono::time_point d_lasttime; void apply_window(unsigned int size); + void set_params(); }; diff --git a/src/dsp/stereo_demod.cpp b/src/dsp/stereo_demod.cpp index 5a425f5cad..ec768b6c65 100644 --- a/src/dsp/stereo_demod.cpp +++ b/src/dsp/stereo_demod.cpp @@ -151,3 +151,19 @@ stereo_demod::~stereo_demod() { } + +void stereo_demod::set_audio_rate(float audio_rate) +{ + if (std::abs(d_audio_rate-audio_rate) > 0.5) + { + d_audio_rate = audio_rate; + audio_rr0->set_rate(d_audio_rate/d_input_rate); + deemph0->set_rate(d_audio_rate); + if(d_stereo) + { + audio_rr1->set_rate(d_audio_rate/d_input_rate); + deemph1->set_rate(d_audio_rate); + } + } +} + diff --git a/src/dsp/stereo_demod.h b/src/dsp/stereo_demod.h index a462ce0540..27461a521d 100644 --- a/src/dsp/stereo_demod.h +++ b/src/dsp/stereo_demod.h @@ -93,6 +93,7 @@ class stereo_demod : public gr::hier_block2 public: ~stereo_demod(); + void set_audio_rate(float audio_rate); private: /* GR blocks */ diff --git a/src/qtgui/dockaudio.cpp b/src/qtgui/dockaudio.cpp index da24f33e24..c5abb8965f 100644 --- a/src/qtgui/dockaudio.cpp +++ b/src/qtgui/dockaudio.cpp @@ -104,6 +104,11 @@ void DockAudio::setFftRange(quint64 minf, quint64 maxf) } } +void DockAudio::setFftSampleRate(quint64 rate) +{ + ui->audioSpectrum->setSampleRate(rate); +} + void DockAudio::setNewFftData(float *fftData, int size) { ui->audioSpectrum->setNewFftData(fftData, size); diff --git a/src/qtgui/dockaudio.h b/src/qtgui/dockaudio.h index 78bd289649..f5b32c35ca 100644 --- a/src/qtgui/dockaudio.h +++ b/src/qtgui/dockaudio.h @@ -51,6 +51,7 @@ class DockAudio : public QDockWidget ~DockAudio(); void setFftRange(quint64 minf, quint64 maxf); + void setFftSampleRate(quint64 rate); void setNewFftData(float *fftData, int size); void setInvertScrolling(bool enabled); int fftRate() const { return 10; } diff --git a/src/qtgui/ioconfig.cpp b/src/qtgui/ioconfig.cpp index 25667f7f2a..a8f6feb492 100644 --- a/src/qtgui/ioconfig.cpp +++ b/src/qtgui/ioconfig.cpp @@ -86,6 +86,20 @@ CIoConfig::CIoConfig(QSettings * settings, connect(ui->inSrCombo, SIGNAL(editTextChanged(QString)), this, SLOT(inputRateChanged(QString))); connect(ui->decimCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(decimationChanged(int))); connect(m_scanButton, SIGNAL(clicked(bool)), this, SLOT(onScanButtonClicked())); + ui->outSrCombo->addItem("96 kHz", 96000); + ui->outSrCombo->addItem("88.2 kHz", 88200); + ui->outSrCombo->addItem("48 kHz", 48000); + ui->outSrCombo->addItem("44.1 kHz", 44100); + ui->outSrCombo->addItem("24 kHz", 24000); + ui->outSrCombo->addItem("22.05 kHz", 22050); + ui->outSrCombo->addItem("12 kHz", 12000); + ui->outSrCombo->addItem("11.025 kHz", 11025); + ui->outSrCombo->addItem("8 kHz", 8000); + int found = ui->outSrCombo->findData(settings->value("output/sample_rate", 48000)); + if (found == -1) + ui->outSrCombo->setCurrentIndex(0); + else + ui->outSrCombo->setCurrentIndex(found); } CIoConfig::~CIoConfig() @@ -212,6 +226,12 @@ void CIoConfig::saveConfig() else m_settings->remove("input/sample_rate"); + int_val = ui->outSrCombo->currentData().toInt(&conv_ok); + if (conv_ok) + m_settings->setValue("output/sample_rate", int_val); + else + m_settings->remove("output/sample_rate"); + idx = ui->decimCombo->currentIndex(); int_val = idx2decim(idx); if (int_val < 2) diff --git a/src/qtgui/ioconfig.ui b/src/qtgui/ioconfig.ui index dd54af36ff..f3b93831d7 100644 --- a/src/qtgui/ioconfig.ui +++ b/src/qtgui/ioconfig.ui @@ -316,11 +316,6 @@ Leave it at default unless you know what you are doing. Select the audio sample rate - - - 48 kHz - - diff --git a/src/receivers/nbrx.cpp b/src/receivers/nbrx.cpp index f8aff9f63a..3a08607f0a 100644 --- a/src/receivers/nbrx.cpp +++ b/src/receivers/nbrx.cpp @@ -112,6 +112,67 @@ void nbrx::set_quad_rate(float quad_rate) } } +void nbrx::set_audio_rate(float audio_rate) +{ + if (std::abs(d_audio_rate-audio_rate) > 0.5) + { + qDebug() << "Changing NB_RX audio rate:" << d_audio_rate << "->" << audio_rate; + d_audio_rate = audio_rate; + if (audio_rr0 && (d_audio_rate == PREF_QUAD_RATE)) + { + lock(); + qDebug() << "nbrx::set_audio_rate Bypassing resampler "; + disconnect(demod, 0, audio_rr0, 0); + disconnect(audio_rr0, 0, self(), 0); // left channel + if (d_demod == NBRX_DEMOD_NONE) + { + disconnect(demod, 1, audio_rr1, 0); + disconnect(audio_rr1, 0, self(), 1); // right channel + } + else + disconnect(audio_rr0, 0, self(), 1); // right channel + audio_rr0.reset(); + audio_rr1.reset(); + connect(demod, 0, self(), 0); + if (d_demod == NBRX_DEMOD_NONE) + connect(demod, 1, self(), 1); + else + connect(demod, 0, self(), 1); + unlock(); + return; + } + if (!audio_rr0 && (d_audio_rate != PREF_QUAD_RATE)) + { + lock(); + disconnect(demod, 0, self(), 0); + disconnect(demod, 1, self(), 1); + qDebug() << "nbrx::set_audio_rate Resampling audio " << PREF_QUAD_RATE << " -> " + << d_audio_rate; + audio_rr0 = make_resampler_ff(d_audio_rate / PREF_QUAD_RATE); + audio_rr1 = make_resampler_ff(d_audio_rate / PREF_QUAD_RATE); + connect(demod, 0, audio_rr0, 0); + connect(audio_rr0, 0, self(), 0); // left channel + if (d_demod == NBRX_DEMOD_NONE) + { + connect(demod, 1, audio_rr1, 0); + connect(audio_rr1, 0, self(), 1); // right channel + } + else + connect(audio_rr0, 0, self(), 1); // right channel + unlock(); + return; + } + qDebug() << "nbrx::set_audio_rate rate=" << d_audio_rate << " demod=" << + d_demod; + if (audio_rr0) + { + audio_rr0->set_rate(d_audio_rate / PREF_QUAD_RATE); + if (d_demod == NBRX_DEMOD_NONE) + audio_rr1->set_rate(d_audio_rate / PREF_QUAD_RATE); + } + } +} + void nbrx::set_filter(double low, double high, double tw) { filter->set_param(low, high, tw); @@ -268,6 +329,7 @@ void nbrx::set_demod(int rx_demod) connect(audio_rr0, 0, self(), 0); connect(audio_rr1, 0, self(), 1); + audio_rr1->set_rate(d_audio_rate / PREF_QUAD_RATE); } else { diff --git a/src/receivers/nbrx.h b/src/receivers/nbrx.h index 20fcd7d3fe..402ae4262c 100644 --- a/src/receivers/nbrx.h +++ b/src/receivers/nbrx.h @@ -74,6 +74,7 @@ class nbrx : public receiver_base_cf bool stop(); void set_quad_rate(float quad_rate); + void set_audio_rate(float audio_rate); void set_filter(double low, double high, double tw); void set_cw_offset(double offset); diff --git a/src/receivers/receiver_base.h b/src/receivers/receiver_base.h index 8a5d7cbaa2..425a66c7e3 100644 --- a/src/receivers/receiver_base.h +++ b/src/receivers/receiver_base.h @@ -56,6 +56,7 @@ class receiver_base_cf : public gr::hier_block2 virtual bool stop() = 0; virtual void set_quad_rate(float quad_rate) = 0; + virtual void set_audio_rate(float audio_rate) = 0; virtual void set_filter(double low, double high, double tw) = 0; virtual void set_cw_offset(double offset) = 0; diff --git a/src/receivers/wfmrx.cpp b/src/receivers/wfmrx.cpp index 6345c3021b..7f0b60f085 100644 --- a/src/receivers/wfmrx.cpp +++ b/src/receivers/wfmrx.cpp @@ -98,6 +98,26 @@ void wfmrx::set_quad_rate(float quad_rate) } } +void wfmrx::set_audio_rate(float audio_rate) +{ + d_audio_rate = audio_rate; + switch (d_demod) { + + case WFMRX_DEMOD_MONO: + default: + mono->set_audio_rate(audio_rate); + break; + + case WFMRX_DEMOD_STEREO: + stereo->set_audio_rate(audio_rate); + break; + + case WFMRX_DEMOD_STEREO_UKW: + stereo_oirt->set_audio_rate(audio_rate); + break; + } +} + void wfmrx::set_filter(double low, double high, double tw) { filter->set_param(low, high, tw); @@ -212,18 +232,21 @@ void wfmrx::set_demod(int demod) connect(demod_fm, 0, mono, 0); connect(mono, 0, self(), 0); // left channel connect(mono, 1, self(), 1); // right channel + mono->set_audio_rate(d_audio_rate); break; case WFMRX_DEMOD_STEREO: connect(demod_fm, 0, stereo, 0); connect(stereo, 0, self(), 0); // left channel connect(stereo, 1, self(), 1); // right channel + stereo->set_audio_rate(d_audio_rate); break; case WFMRX_DEMOD_STEREO_UKW: connect(demod_fm, 0, stereo_oirt, 0); connect(stereo_oirt, 0, self(), 0); // left channel connect(stereo_oirt, 1, self(), 1); // right channel + stereo_oirt->set_audio_rate(d_audio_rate); break; } d_demod = (wfmrx_demod) demod; diff --git a/src/receivers/wfmrx.h b/src/receivers/wfmrx.h index cc0e036141..129ffc0ec0 100644 --- a/src/receivers/wfmrx.h +++ b/src/receivers/wfmrx.h @@ -70,6 +70,7 @@ class wfmrx : public receiver_base_cf bool stop(); void set_quad_rate(float quad_rate); + void set_audio_rate(float audio_rate); void set_filter(double low, double high, double tw); void set_cw_offset(double offset) { (void)offset; }