1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-10-01 01:06:35 -04:00

merge with dev

This commit is contained in:
f4exb 2017-10-04 01:56:50 +02:00
commit be5652f8f1
241 changed files with 4416 additions and 2741 deletions

View File

@ -264,6 +264,8 @@ set(sdrbase_SOURCES
sdrbase/gui/samplingdevicecontrol.cpp sdrbase/gui/samplingdevicecontrol.cpp
sdrbase/gui/scale.cpp sdrbase/gui/scale.cpp
sdrbase/gui/scaleengine.cpp sdrbase/gui/scaleengine.cpp
sdrbase/gui/transverterbutton.cpp
sdrbase/gui/transverterdialog.cpp
sdrbase/gui/valuedial.cpp sdrbase/gui/valuedial.cpp
sdrbase/gui/valuedialz.cpp sdrbase/gui/valuedialz.cpp
@ -386,6 +388,8 @@ set(sdrbase_HEADERS
sdrbase/gui/samplingdevicecontrol.h sdrbase/gui/samplingdevicecontrol.h
sdrbase/gui/scale.h sdrbase/gui/scale.h
sdrbase/gui/scaleengine.h sdrbase/gui/scaleengine.h
sdrbase/gui/transverterbutton.h
sdrbase/gui/transverterdialog.h
sdrbase/gui/valuedial.h sdrbase/gui/valuedial.h
sdrbase/gui/valuedialz.h sdrbase/gui/valuedialz.h
@ -393,7 +397,7 @@ set(sdrbase_HEADERS
sdrbase/dsp/devicesamplesink.h sdrbase/dsp/devicesamplesink.h
sdrbase/plugin/pluginapi.h sdrbase/plugin/pluginapi.h
sdrbase/plugin/plugininstanceui.h sdrbase/plugin/plugininstancegui.h
sdrbase/plugin/plugininterface.h sdrbase/plugin/plugininterface.h
sdrbase/plugin/pluginmanager.h sdrbase/plugin/pluginmanager.h
@ -439,6 +443,7 @@ set(sdrbase_FORMS
sdrbase/gui/audiodialog.ui sdrbase/gui/audiodialog.ui
sdrbase/gui/samplingdevicecontrol.ui sdrbase/gui/samplingdevicecontrol.ui
sdrbase/gui/myposdialog.ui sdrbase/gui/myposdialog.ui
sdrbase/gui/transverterdialog.ui
) )
set(sdrbase_RESOURCES set(sdrbase_RESOURCES

View File

@ -6,6 +6,7 @@
QT += core gui multimedia opengl QT += core gui multimedia opengl
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
QMAKE_CXXFLAGS += -std=c++11
TEMPLATE = app TEMPLATE = app
TARGET = sdrangel TARGET = sdrangel

8
debian/changelog vendored
View File

@ -1,3 +1,11 @@
sdrangel (3.7.3-1) unstable; urgency=medium
* For Airspy, Funcube Pro and Pro+, PlutoSDR Rx and Tx, RTLSDR:
* Button and dialog to set frequency translation for transverter operation
* GUI and demod separation step 1 partial
-- Edouard Griffiths, F4EXB <f4exb06@gmail.com> Wed, 04 Oct 2017 23:14:18 +0200
sdrangel (3.7.2-1) unstable; urgency=medium sdrangel (3.7.2-1) unstable; urgency=medium
* PlutoSDR: Remove from device enumeration if device is not accessible * PlutoSDR: Remove from device enumeration if device is not accessible

2
debian/control vendored
View File

@ -10,7 +10,7 @@ Homepage: https://github.com/f4exb/sdrangel
Package: sdrangel Package: sdrangel
Architecture: any Architecture: any
Depends: libc6, libasound2, libfftw3-single3, libgcc1, libgl1-mesa-glx, libnanomsg0, libqt5core5a, libqt5gui5, libqt5multimedia5, libqt5network5, libqt5opengl5, libqt5widgets5, libqt5multimedia5-plugins, libstdc++6, libusb-1.0-0, libopencv-dev, libsqlite3-dev, pulseaudio, libxml2, ${shlibs:Depends}, ${misc:Depends} Depends: libc6, libasound2, libfftw3-single3, libgcc1, libgl1-mesa-glx, libnanomsg0|libnanomsg4, libqt5core5a, libqt5gui5, libqt5multimedia5, libqt5network5, libqt5opengl5, libqt5widgets5, libqt5multimedia5-plugins, libstdc++6, libusb-1.0-0, libopencv-dev, libsqlite3-dev, pulseaudio, libxml2, ${shlibs:Depends}, ${misc:Depends}
Description: SDR/Analyzer/Generator front-end for various hardware Description: SDR/Analyzer/Generator front-end for various hardware
SDR/Analyzer/Generator front-end for Airspy, BladeRF, HackRF, RTL-SDR, FunCube, LimeSDR, PlutoSDR. SDR/Analyzer/Generator front-end for Airspy, BladeRF, HackRF, RTL-SDR, FunCube, LimeSDR, PlutoSDR.
Also File source and sink for I/Q samples, network I/Q sources with SDRDaemon. Also File source and sink for I/Q samples, network I/Q sources with SDRDaemon.

View File

@ -56,20 +56,41 @@ bool DeviceLimeSDR::setNCOFrequency(lms_device_t *device, bool dir_tx, std::size
return false; return false;
} }
if (dir_tx)
{
if (LMS_WriteParam(device,LMS7param(CMIX_BYP_TXTSP),0) < 0) {
fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot enable Tx NCO\n");
return false;
}
}
else
{
if (LMS_WriteParam(device,LMS7param(CMIX_BYP_RXTSP),0) < 0) {
fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot enable Rx NCO\n");
return false;
}
}
return true; return true;
} }
else else
{ {
if (LMS_SetNCOIndex(device, dir_tx, chan, LMS_NCO_VAL_COUNT, true) < 0) if (dir_tx)
{ {
fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot disable NCO\n"); if (LMS_WriteParam(device,LMS7param(CMIX_BYP_TXTSP),1) < 0) {
return false; fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot disable Tx NCO\n");
return false;
}
} }
else else
{ {
fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: NCO disabled\n"); if (LMS_WriteParam(device,LMS7param(CMIX_BYP_RXTSP),1) < 0) {
return true; fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot disable Rx NCO\n");
return false;
}
} }
return true;
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,5 +1,6 @@
# Udev rules for the Funcube Dongle Pro+ (0xfb31) # Udev rules for the Funcube Dongle Pro+ (0xfb31)
# HIDAPI/libusb: # HIDAPI/libusb:
SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb31", GROUP:="audio", MODE:="0666" SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb56", MODE:="0666"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb31", MODE:="0666"

View File

@ -22,5 +22,11 @@ const char *fcd_traits<ProPlus>::displayedName = "FunCube Dongle Pro+";
const char *fcd_traits<Pro>::pluginDisplayedName = "FunCube Pro Input"; const char *fcd_traits<Pro>::pluginDisplayedName = "FunCube Pro Input";
const char *fcd_traits<ProPlus>::pluginDisplayedName = "FunCube Pro+ Input"; const char *fcd_traits<ProPlus>::pluginDisplayedName = "FunCube Pro+ Input";
const char *fcd_traits<Pro>::pluginVersion = "3.5.0"; const char *fcd_traits<Pro>::pluginVersion = "3.7.3";
const char *fcd_traits<ProPlus>::pluginVersion = "3.5.0"; const char *fcd_traits<ProPlus>::pluginVersion = "3.7.3";
const int64_t fcd_traits<Pro>::loLowLimitFreq = 64000000L;
const int64_t fcd_traits<ProPlus>::loLowLimitFreq = 150000L;
const int64_t fcd_traits<Pro>::loHighLimitFreq = 1700000000L;
const int64_t fcd_traits<ProPlus>::loHighLimitFreq = 2000000000L;

View File

@ -30,6 +30,8 @@ struct fcd_traits
static const char *displayedName; static const char *displayedName;
static const char *pluginDisplayedName; static const char *pluginDisplayedName;
static const char *pluginVersion; static const char *pluginVersion;
static const int64_t loLowLimitFreq;
static const int64_t loHighLimitFreq;
}; };
template<> template<>
@ -46,6 +48,8 @@ struct fcd_traits<Pro>
static const char *displayedName; static const char *displayedName;
static const char *pluginDisplayedName; static const char *pluginDisplayedName;
static const char *pluginVersion; static const char *pluginVersion;
static const int64_t loLowLimitFreq;
static const int64_t loHighLimitFreq;
}; };
template<> template<>
@ -62,6 +66,8 @@ struct fcd_traits<ProPlus>
static const char *displayedName; static const char *displayedName;
static const char *pluginDisplayedName; static const char *pluginDisplayedName;
static const char *pluginVersion; static const char *pluginVersion;
static const int64_t loLowLimitFreq;
static const int64_t loHighLimitFreq;
}; };
template <fcd_type FCDType> const char *fcd_traits<FCDType>::alsaDeviceName = ""; template <fcd_type FCDType> const char *fcd_traits<FCDType>::alsaDeviceName = "";

View File

@ -14,19 +14,25 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#include "../../channelrx/chanalyzer/chanalyzer.h" #include "chanalyzer.h"
#include <dsp/downchannelizer.h>
#include <QTime> #include <QTime>
#include <QDebug> #include <QDebug>
#include <stdio.h> #include <stdio.h>
#include <dsp/downchannelizer.h>
#include "dsp/threadedbasebandsamplesink.h"
#include "device/devicesourceapi.h"
#include "audio/audiooutput.h" #include "audio/audiooutput.h"
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelAnalyzer, Message) MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelAnalyzer, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgReportChannelSampleRateChanged, Message)
ChannelAnalyzer::ChannelAnalyzer(BasebandSampleSink* sampleSink) : ChannelAnalyzer::ChannelAnalyzer(DeviceSourceAPI *deviceAPI) :
m_sampleSink(sampleSink), m_deviceAPI(deviceAPI),
m_sampleSink(0),
m_settingsMutex(QMutex::Recursive) m_settingsMutex(QMutex::Recursive)
{ {
m_Bandwidth = 5000; m_Bandwidth = 5000;
@ -42,12 +48,20 @@ ChannelAnalyzer::ChannelAnalyzer(BasebandSampleSink* sampleSink) :
m_magsq = 0; m_magsq = 0;
SSBFilter = new fftfilt(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate, ssbFftLen); SSBFilter = new fftfilt(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate, ssbFftLen);
DSBFilter = new fftfilt(m_Bandwidth / m_sampleRate, 2*ssbFftLen); DSBFilter = new fftfilt(m_Bandwidth / m_sampleRate, 2*ssbFftLen);
m_channelizer = new DownChannelizer(this);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged()));
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
} }
ChannelAnalyzer::~ChannelAnalyzer() ChannelAnalyzer::~ChannelAnalyzer()
{ {
if (SSBFilter) delete SSBFilter; if (SSBFilter) delete SSBFilter;
if (DSBFilter) delete DSBFilter; if (DSBFilter) delete DSBFilter;
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
} }
void ChannelAnalyzer::configure(MessageQueue* messageQueue, void ChannelAnalyzer::configure(MessageQueue* messageQueue,
@ -130,6 +144,12 @@ void ChannelAnalyzer::stop()
{ {
} }
void ChannelAnalyzer::channelSampleRateChanged()
{
MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create();
getMessageQueueToGUI()->push(msg);
}
bool ChannelAnalyzer::handleMessage(const Message& cmd) bool ChannelAnalyzer::handleMessage(const Message& cmd)
{ {
float band, lowCutoff; float band, lowCutoff;
@ -148,6 +168,16 @@ bool ChannelAnalyzer::handleMessage(const Message& cmd)
return true; return true;
} }
else if (MsgConfigureChannelizer::match(cmd))
{
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
m_channelizer->getInputSampleRate(),
cfg.getCenterFrequency());
return true;
}
else if (MsgConfigureChannelAnalyzer::match(cmd)) else if (MsgConfigureChannelAnalyzer::match(cmd))
{ {
MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd; MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd;

View File

@ -27,10 +27,87 @@
#define ssbFftLen 1024 #define ssbFftLen 1024
class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class ChannelAnalyzer : public BasebandSampleSink { class ChannelAnalyzer : public BasebandSampleSink {
public: public:
ChannelAnalyzer(BasebandSampleSink* m_sampleSink); class MsgConfigureChannelAnalyzer : public Message {
MESSAGE_CLASS_DECLARATION
public:
Real getBandwidth() const { return m_Bandwidth; }
Real getLoCutoff() const { return m_LowCutoff; }
int getSpanLog2() const { return m_spanLog2; }
bool getSSB() const { return m_ssb; }
static MsgConfigureChannelAnalyzer* create(Real Bandwidth,
Real LowCutoff,
int spanLog2,
bool ssb)
{
return new MsgConfigureChannelAnalyzer(Bandwidth, LowCutoff, spanLog2, ssb);
}
private:
Real m_Bandwidth;
Real m_LowCutoff;
int m_spanLog2;
bool m_ssb;
MsgConfigureChannelAnalyzer(Real Bandwidth,
Real LowCutoff,
int spanLog2,
bool ssb) :
Message(),
m_Bandwidth(Bandwidth),
m_LowCutoff(LowCutoff),
m_spanLog2(spanLog2),
m_ssb(ssb)
{ }
};
class MsgConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int centerFrequency)
{
return new MsgConfigureChannelizer(centerFrequency);
}
private:
int m_centerFrequency;
MsgConfigureChannelizer(int centerFrequency) :
Message(),
m_centerFrequency(centerFrequency)
{ }
};
class MsgReportChannelSampleRateChanged : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgReportChannelSampleRateChanged* create()
{
return new MsgReportChannelSampleRateChanged();
}
private:
MsgReportChannelSampleRateChanged() :
Message()
{ }
};
ChannelAnalyzer(DeviceSourceAPI *deviceAPI);
virtual ~ChannelAnalyzer(); virtual ~ChannelAnalyzer();
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
void configure(MessageQueue* messageQueue, void configure(MessageQueue* messageQueue,
Real Bandwidth, Real Bandwidth,
@ -46,41 +123,13 @@ public:
virtual void stop(); virtual void stop();
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
private slots:
void channelSampleRateChanged();
private: private:
class MsgConfigureChannelAnalyzer : public Message { DeviceSourceAPI *m_deviceAPI;
MESSAGE_CLASS_DECLARATION ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
public:
Real getBandwidth() const { return m_Bandwidth; }
Real getLoCutoff() const { return m_LowCutoff; }
int getSpanLog2() const { return m_spanLog2; }
bool getSSB() const { return m_ssb; }
static MsgConfigureChannelAnalyzer* create(Real Bandwidth,
Real LowCutoff,
int spanLog2,
bool ssb)
{
return new MsgConfigureChannelAnalyzer(Bandwidth, LowCutoff, spanLog2, ssb);
}
private:
Real m_Bandwidth;
Real m_LowCutoff;
int m_spanLog2;
bool m_ssb;
MsgConfigureChannelAnalyzer(Real Bandwidth,
Real LowCutoff,
int spanLog2,
bool ssb) :
Message(),
m_Bandwidth(Bandwidth),
m_LowCutoff(LowCutoff),
m_spanLog2(spanLog2),
m_ssb(ssb)
{ }
};
Real m_Bandwidth; Real m_Bandwidth;
Real m_LowCutoff; Real m_LowCutoff;

View File

@ -154,11 +154,32 @@ bool ChannelAnalyzerGUI::deserialize(const QByteArray& data)
} }
} }
bool ChannelAnalyzerGUI::handleMessage(const Message& message __attribute__((unused))) bool ChannelAnalyzerGUI::handleMessage(const Message& message)
{ {
if (ChannelAnalyzer::MsgReportChannelSampleRateChanged::match(message))
{
setNewRate(m_spanLog2);
return true;
}
return false; return false;
} }
void ChannelAnalyzerGUI::handleInputMessages()
{
Message* message;
while ((message = getInputMessageQueue()->pop()) != 0)
{
qDebug("ChannelAnalyzerGUI::handleInputMessages: message: %s", message->getIdentifier());
if (handleMessage(*message))
{
delete message;
}
}
}
void ChannelAnalyzerGUI::viewChanged() void ChannelAnalyzerGUI::viewChanged()
{ {
applySettings(); applySettings();
@ -171,11 +192,6 @@ void ChannelAnalyzerGUI::tick()
ui->channelPower->setText(QString::number(m_channelPowerDbAvg.average(), 'f', 1)); ui->channelPower->setText(QString::number(m_channelPowerDbAvg.average(), 'f', 1));
} }
void ChannelAnalyzerGUI::channelSampleRateChanged()
{
setNewRate(m_spanLog2);
}
void ChannelAnalyzerGUI::on_deltaMinus_toggled(bool minus) void ChannelAnalyzerGUI::on_deltaMinus_toggled(bool minus)
{ {
int deltaFrequency = m_channelMarker.getCenterFrequency(); int deltaFrequency = m_channelMarker.getCenterFrequency();
@ -326,11 +342,9 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceSourceAPI *de
m_spectrumVis = new SpectrumVis(ui->glSpectrum); m_spectrumVis = new SpectrumVis(ui->glSpectrum);
m_scopeVis = new ScopeVis(ui->glScope); m_scopeVis = new ScopeVis(ui->glScope);
m_spectrumScopeComboVis = new SpectrumScopeComboVis(m_spectrumVis, m_scopeVis); m_spectrumScopeComboVis = new SpectrumScopeComboVis(m_spectrumVis, m_scopeVis);
m_channelAnalyzer = new ChannelAnalyzer(m_spectrumScopeComboVis); m_channelAnalyzer = new ChannelAnalyzer(m_deviceAPI);
m_channelizer = new DownChannelizer(m_channelAnalyzer); m_channelAnalyzer->setSampleSink(m_spectrumScopeComboVis);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); m_channelAnalyzer->setMessageQueueToGUI(getInputMessageQueue());
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged()));
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold)); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold));
ui->deltaFrequency->setValueRange(7, 0U, 9999999U); ui->deltaFrequency->setValueRange(7, 0U, 9999999U);
@ -361,6 +375,8 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceSourceAPI *de
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
applySettings(); applySettings();
setNewRate(m_spanLog2); setNewRate(m_spanLog2);
} }
@ -368,9 +384,6 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceSourceAPI *de
ChannelAnalyzerGUI::~ChannelAnalyzerGUI() ChannelAnalyzerGUI::~ChannelAnalyzerGUI()
{ {
m_deviceAPI->removeChannelInstance(this); m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
delete m_channelAnalyzer; delete m_channelAnalyzer;
delete m_spectrumVis; delete m_spectrumVis;
delete m_scopeVis; delete m_scopeVis;
@ -457,9 +470,8 @@ void ChannelAnalyzerGUI::applySettings()
ui->deltaFrequency->setValue(abs(m_channelMarker.getCenterFrequency())); ui->deltaFrequency->setValue(abs(m_channelMarker.getCenterFrequency()));
ui->deltaMinus->setChecked(m_channelMarker.getCenterFrequency() < 0); ui->deltaMinus->setChecked(m_channelMarker.getCenterFrequency() < 0);
m_channelizer->configure(m_channelizer->getInputMessageQueue(), ChannelAnalyzer::MsgConfigureChannelizer *msg = ChannelAnalyzer::MsgConfigureChannelizer::create(m_channelMarker.getCenterFrequency());
m_channelizer->getInputSampleRate(), m_channelAnalyzer->getInputMessageQueue()->push(msg);
m_channelMarker.getCenterFrequency());
m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(), m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(),
ui->BW->value() * 100.0, ui->BW->value() * 100.0,

View File

@ -17,10 +17,10 @@
#ifndef INCLUDE_CHANNELANALYZERGUI_H #ifndef INCLUDE_CHANNELANALYZERGUI_H
#define INCLUDE_CHANNELANALYZERGUI_H #define INCLUDE_CHANNELANALYZERGUI_H
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
class PluginAPI; class PluginAPI;
@ -37,7 +37,7 @@ namespace Ui {
class ChannelAnalyzerGUI; class ChannelAnalyzerGUI;
} }
class ChannelAnalyzerGUI : public RollupWidget, public PluginInstanceUI { class ChannelAnalyzerGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:
@ -59,7 +59,6 @@ public:
private slots: private slots:
void viewChanged(); void viewChanged();
void channelSampleRateChanged();
void on_deltaFrequency_changed(quint64 value); void on_deltaFrequency_changed(quint64 value);
void on_deltaMinus_toggled(bool minus); void on_deltaMinus_toggled(bool minus);
void on_BW_valueChanged(int value); void on_BW_valueChanged(int value);
@ -68,6 +67,7 @@ private slots:
void on_ssb_toggled(bool checked); void on_ssb_toggled(bool checked);
void onWidgetRolled(QWidget* widget, bool rollDown); void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDoubleClicked(); void onMenuDoubleClicked();
void handleInputMessages();
void tick(); void tick();
private: private:
@ -81,8 +81,8 @@ private:
int m_spanLog2; int m_spanLog2;
MovingAverage<Real> m_channelPowerDbAvg; MovingAverage<Real> m_channelPowerDbAvg;
ThreadedBasebandSampleSink* m_threadedChannelizer; // ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer; // DownChannelizer* m_channelizer;
ChannelAnalyzer* m_channelAnalyzer; ChannelAnalyzer* m_channelAnalyzer;
SpectrumScopeComboVis* m_spectrumScopeComboVis; SpectrumScopeComboVis* m_spectrumScopeComboVis;
SpectrumVis* m_spectrumVis; SpectrumVis* m_spectrumVis;

View File

@ -33,7 +33,7 @@ void ChannelAnalyzerPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerRxChannel(ChannelAnalyzerGUI::m_channelID, this); m_pluginAPI->registerRxChannel(ChannelAnalyzerGUI::m_channelID, this);
} }
PluginInstanceUI* ChannelAnalyzerPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) PluginInstanceGUI* ChannelAnalyzerPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{ {
if(channelName == ChannelAnalyzerGUI::m_channelID) if(channelName == ChannelAnalyzerGUI::m_channelID)
{ {

View File

@ -17,7 +17,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -16,17 +16,23 @@
#include "chanalyzerng.h" #include "chanalyzerng.h"
#include <dsp/downchannelizer.h>
#include <QTime> #include <QTime>
#include <QDebug> #include <QDebug>
#include <stdio.h> #include <stdio.h>
#include "device/devicesourceapi.h"
#include "audio/audiooutput.h" #include "audio/audiooutput.h"
#include "dsp/threadedbasebandsamplesink.h"
#include "dsp/downchannelizer.h"
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelAnalyzer, Message) MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelAnalyzer, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgReportChannelSampleRateChanged, Message)
ChannelAnalyzerNG::ChannelAnalyzerNG(BasebandSampleSink* sampleSink) : ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) :
m_sampleSink(sampleSink), m_deviceAPI(deviceAPI),
m_sampleSink(0),
m_settingsMutex(QMutex::Recursive) m_settingsMutex(QMutex::Recursive)
{ {
m_undersampleCount = 0; m_undersampleCount = 0;
@ -38,6 +44,12 @@ ChannelAnalyzerNG::ChannelAnalyzerNG(BasebandSampleSink* sampleSink) :
m_interpolatorDistanceRemain = 0.0f; m_interpolatorDistanceRemain = 0.0f;
SSBFilter = new fftfilt(m_config.m_LowCutoff / m_config.m_inputSampleRate, m_config.m_Bandwidth / m_config.m_inputSampleRate, ssbFftLen); SSBFilter = new fftfilt(m_config.m_LowCutoff / m_config.m_inputSampleRate, m_config.m_Bandwidth / m_config.m_inputSampleRate, ssbFftLen);
DSBFilter = new fftfilt(m_config.m_Bandwidth / m_config.m_inputSampleRate, 2*ssbFftLen); DSBFilter = new fftfilt(m_config.m_Bandwidth / m_config.m_inputSampleRate, 2*ssbFftLen);
m_channelizer = new DownChannelizer(this);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged()));
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
apply(true); apply(true);
} }
@ -45,6 +57,9 @@ ChannelAnalyzerNG::~ChannelAnalyzerNG()
{ {
if (SSBFilter) delete SSBFilter; if (SSBFilter) delete SSBFilter;
if (DSBFilter) delete DSBFilter; if (DSBFilter) delete DSBFilter;
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
} }
void ChannelAnalyzerNG::configure(MessageQueue* messageQueue, void ChannelAnalyzerNG::configure(MessageQueue* messageQueue,
@ -54,7 +69,7 @@ void ChannelAnalyzerNG::configure(MessageQueue* messageQueue,
int spanLog2, int spanLog2,
bool ssb) bool ssb)
{ {
Message* cmd = MsgConfigureChannelAnalyzer::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb); Message* cmd = MsgConfigureChannelAnalyzer::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb);
messageQueue->push(cmd); messageQueue->push(cmd);
} }
@ -102,6 +117,12 @@ void ChannelAnalyzerNG::stop()
{ {
} }
void ChannelAnalyzerNG::channelizerInputSampleRateChanged()
{
MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create();
getMessageQueueToGUI()->push(msg);
}
bool ChannelAnalyzerNG::handleMessage(const Message& cmd) bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
{ {
qDebug() << "ChannelAnalyzerNG::handleMessage: " << cmd.getIdentifier(); qDebug() << "ChannelAnalyzerNG::handleMessage: " << cmd.getIdentifier();
@ -120,11 +141,19 @@ bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
apply(); apply();
return true; return true;
} }
else if (MsgConfigureChannelizer::match(cmd))
{
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(),
cfg.getCenterFrequency());
return true;
}
else if (MsgConfigureChannelAnalyzer::match(cmd)) else if (MsgConfigureChannelAnalyzer::match(cmd))
{ {
MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd; MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd;
m_config.m_channelSampleRate = cfg.getChannelSampleRate(); m_config.m_channelSampleRate = cfg.getChannelSampleRate();
m_config.m_Bandwidth = cfg.getBandwidth(); m_config.m_Bandwidth = cfg.getBandwidth();
m_config.m_LowCutoff = cfg.getLoCutoff(); m_config.m_LowCutoff = cfg.getLoCutoff();
m_config.m_spanLog2 = cfg.getSpanLog2(); m_config.m_spanLog2 = cfg.getSpanLog2();
@ -153,6 +182,8 @@ bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
} }
} }
void ChannelAnalyzerNG::apply(bool force) void ChannelAnalyzerNG::apply(bool force)
{ {
if ((m_running.m_frequency != m_config.m_frequency) || if ((m_running.m_frequency != m_config.m_frequency) ||

View File

@ -29,10 +29,102 @@
#define ssbFftLen 1024 #define ssbFftLen 1024
class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class ChannelAnalyzerNG : public BasebandSampleSink { class ChannelAnalyzerNG : public BasebandSampleSink {
public: public:
ChannelAnalyzerNG(BasebandSampleSink* m_sampleSink); class MsgConfigureChannelAnalyzer : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getChannelSampleRate() const { return m_channelSampleRate; }
Real getBandwidth() const { return m_Bandwidth; }
Real getLoCutoff() const { return m_LowCutoff; }
int getSpanLog2() const { return m_spanLog2; }
bool getSSB() const { return m_ssb; }
static MsgConfigureChannelAnalyzer* create(
int channelSampleRate,
Real Bandwidth,
Real LowCutoff,
int spanLog2,
bool ssb)
{
return new MsgConfigureChannelAnalyzer(
channelSampleRate,
Bandwidth,
LowCutoff,
spanLog2,
ssb);
}
private:
int m_channelSampleRate;
Real m_Bandwidth;
Real m_LowCutoff;
int m_spanLog2;
bool m_ssb;
MsgConfigureChannelAnalyzer(
int channelSampleRate,
Real Bandwidth,
Real LowCutoff,
int spanLog2,
bool ssb) :
Message(),
m_channelSampleRate(channelSampleRate),
m_Bandwidth(Bandwidth),
m_LowCutoff(LowCutoff),
m_spanLog2(spanLog2),
m_ssb(ssb)
{ }
};
class MsgConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
{
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
}
private:
int m_sampleRate;
int m_centerFrequency;
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
Message(),
m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency)
{ }
};
class MsgReportChannelSampleRateChanged : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgReportChannelSampleRateChanged* create()
{
return new MsgReportChannelSampleRateChanged();
}
private:
MsgReportChannelSampleRateChanged() :
Message()
{ }
};
ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI);
virtual ~ChannelAnalyzerNG(); virtual ~ChannelAnalyzerNG();
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
void configure(MessageQueue* messageQueue, void configure(MessageQueue* messageQueue,
int channelSampleRate, int channelSampleRate,
@ -41,6 +133,7 @@ public:
int spanLog2, int spanLog2,
bool ssb); bool ssb);
DownChannelizer *getChannelizer() { return m_channelizer; }
int getInputSampleRate() const { return m_running.m_inputSampleRate; } int getInputSampleRate() const { return m_running.m_inputSampleRate; }
int getChannelSampleRate() const { return m_running.m_channelSampleRate; } int getChannelSampleRate() const { return m_running.m_channelSampleRate; }
double getMagSq() const { return m_magsq; } double getMagSq() const { return m_magsq; }
@ -50,48 +143,10 @@ public:
virtual void stop(); virtual void stop();
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
private slots:
void channelizerInputSampleRateChanged();
private: private:
class MsgConfigureChannelAnalyzer : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getChannelSampleRate() const { return m_channelSampleRate; }
Real getBandwidth() const { return m_Bandwidth; }
Real getLoCutoff() const { return m_LowCutoff; }
int getSpanLog2() const { return m_spanLog2; }
bool getSSB() const { return m_ssb; }
static MsgConfigureChannelAnalyzer* create(
int channelSampleRate,
Real Bandwidth,
Real LowCutoff,
int spanLog2,
bool ssb)
{
return new MsgConfigureChannelAnalyzer(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb);
}
private:
int m_channelSampleRate;
Real m_Bandwidth;
Real m_LowCutoff;
int m_spanLog2;
bool m_ssb;
MsgConfigureChannelAnalyzer(
int channelSampleRate,
Real Bandwidth,
Real LowCutoff,
int spanLog2,
bool ssb) :
Message(),
m_channelSampleRate(channelSampleRate),
m_Bandwidth(Bandwidth),
m_LowCutoff(LowCutoff),
m_spanLog2(spanLog2),
m_ssb(ssb)
{ }
};
struct Config struct Config
{ {
@ -117,6 +172,10 @@ private:
Config m_config; Config m_config;
Config m_running; Config m_running;
DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
int m_undersampleCount; int m_undersampleCount;
fftfilt::cmplx m_sum; fftfilt::cmplx m_sum;
bool m_usb; bool m_usb;

View File

@ -159,7 +159,29 @@ bool ChannelAnalyzerNGGUI::deserialize(const QByteArray& data)
bool ChannelAnalyzerNGGUI::handleMessage(const Message& message __attribute__((unused))) bool ChannelAnalyzerNGGUI::handleMessage(const Message& message __attribute__((unused)))
{ {
return false; if (ChannelAnalyzerNG::MsgReportChannelSampleRateChanged::match(message))
{
setNewFinalRate(m_spanLog2);
applySettings();
return true;
}
return false;
}
void ChannelAnalyzerNGGUI::handleInputMessages()
{
Message* message;
while ((message = getInputMessageQueue()->pop()) != 0)
{
qDebug("ChannelAnalyzerGUI::handleInputMessages: message: %s", message->getIdentifier());
if (handleMessage(*message))
{
delete message;
}
}
} }
void ChannelAnalyzerNGGUI::viewChanged() void ChannelAnalyzerNGGUI::viewChanged()
@ -174,12 +196,12 @@ void ChannelAnalyzerNGGUI::tick()
ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.average(), 0, 'f', 1)); ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.average(), 0, 'f', 1));
} }
void ChannelAnalyzerNGGUI::channelizerInputSampleRateChanged() //void ChannelAnalyzerNGGUI::channelizerInputSampleRateChanged()
{ //{
//ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate()); // //ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate());
setNewFinalRate(m_spanLog2); // setNewFinalRate(m_spanLog2);
applySettings(); // applySettings();
} //}
void ChannelAnalyzerNGGUI::on_channelSampleRate_changed(quint64 value) void ChannelAnalyzerNGGUI::on_channelSampleRate_changed(quint64 value)
{ {
@ -204,7 +226,7 @@ int ChannelAnalyzerNGGUI::getRequestedChannelSampleRate()
if (ui->useRationalDownsampler->isChecked()) { if (ui->useRationalDownsampler->isChecked()) {
return ui->channelSampleRate->getValueNew(); return ui->channelSampleRate->getValueNew();
} else { } else {
return m_channelizer->getInputSampleRate(); return m_channelAnalyzer->getChannelizer()->getInputSampleRate();
} }
} }
@ -348,11 +370,13 @@ ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceSourceAPI
m_spectrumVis = new SpectrumVis(ui->glSpectrum); m_spectrumVis = new SpectrumVis(ui->glSpectrum);
m_scopeVis = new ScopeVisNG(ui->glScope); m_scopeVis = new ScopeVisNG(ui->glScope);
m_spectrumScopeComboVis = new SpectrumScopeNGComboVis(m_spectrumVis, m_scopeVis); m_spectrumScopeComboVis = new SpectrumScopeNGComboVis(m_spectrumVis, m_scopeVis);
m_channelAnalyzer = new ChannelAnalyzerNG(m_spectrumScopeComboVis); m_channelAnalyzer = new ChannelAnalyzerNG(m_deviceAPI);
m_channelizer = new DownChannelizer(m_channelAnalyzer); m_channelAnalyzer->setSampleSink(m_spectrumScopeComboVis);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); m_channelAnalyzer->setMessageQueueToGUI(getInputMessageQueue());
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged())); // m_channelizer = new DownChannelizer(m_channelAnalyzer);
m_deviceAPI->addThreadedSink(m_threadedChannelizer); // m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
// connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged()));
// m_deviceAPI->addThreadedSink(m_threadedChannelizer);
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
@ -389,6 +413,8 @@ ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceSourceAPI
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
applySettings(); applySettings();
setNewFinalRate(m_spanLog2); setNewFinalRate(m_spanLog2);
} }
@ -396,9 +422,9 @@ ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceSourceAPI
ChannelAnalyzerNGGUI::~ChannelAnalyzerNGGUI() ChannelAnalyzerNGGUI::~ChannelAnalyzerNGGUI()
{ {
m_deviceAPI->removeChannelInstance(this); m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer); // m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer; // delete m_threadedChannelizer;
delete m_channelizer; // delete m_channelizer;
delete m_channelAnalyzer; delete m_channelAnalyzer;
delete m_spectrumVis; delete m_spectrumVis;
delete m_scopeVis; delete m_scopeVis;
@ -514,14 +540,25 @@ void ChannelAnalyzerNGGUI::applySettings()
setTitleColor(m_channelMarker.getColor()); setTitleColor(m_channelMarker.getColor());
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_channelizer->configure(m_channelizer->getInputMessageQueue(), int sampleRate = getRequestedChannelSampleRate();
//m_channelizer->getInputSampleRate(),
getRequestedChannelSampleRate(), ChannelAnalyzerNG::MsgConfigureChannelizer *msgChannelizer = ChannelAnalyzerNG::MsgConfigureChannelizer::create(sampleRate, m_channelMarker.getCenterFrequency());
m_channelMarker.getCenterFrequency()); m_channelAnalyzer->getInputMessageQueue()->push(msgChannelizer);
ChannelAnalyzerNG::MsgConfigureChannelizer *msg =
ChannelAnalyzerNG::MsgConfigureChannelizer::create(
sampleRate,
m_channelMarker.getCenterFrequency());
m_channelAnalyzer->getInputMessageQueue()->push(msg);
// m_channelizer->configure(m_channelizer->getInputMessageQueue(),
// //m_channelizer->getInputSampleRate(),
// getRequestedChannelSampleRate(),
// m_channelMarker.getCenterFrequency());
m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(), m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(),
//m_channelizer->getInputSampleRate(), // TODO: specify required channel sample rate //m_channelizer->getInputSampleRate(), // TODO: specify required channel sample rate
getRequestedChannelSampleRate(), // TODO: specify required channel sample rate sampleRate, // TODO: specify required channel sample rate
ui->BW->value() * 100.0, ui->BW->value() * 100.0,
ui->lowCut->value() * 100.0, ui->lowCut->value() * 100.0,
m_spanLog2, m_spanLog2,

View File

@ -17,10 +17,10 @@
#ifndef INCLUDE_CHANNELANALYZERNGGUI_H #ifndef INCLUDE_CHANNELANALYZERNGGUI_H
#define INCLUDE_CHANNELANALYZERNGGUI_H #define INCLUDE_CHANNELANALYZERNGGUI_H
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
class PluginAPI; class PluginAPI;
@ -37,7 +37,7 @@ namespace Ui {
class ChannelAnalyzerNGGUI; class ChannelAnalyzerNGGUI;
} }
class ChannelAnalyzerNGGUI : public RollupWidget, public PluginInstanceUI { class ChannelAnalyzerNGGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:
@ -59,7 +59,7 @@ public:
private slots: private slots:
void viewChanged(); void viewChanged();
void channelizerInputSampleRateChanged(); // void channelizerInputSampleRateChanged();
void on_deltaFrequency_changed(qint64 value); void on_deltaFrequency_changed(qint64 value);
void on_channelSampleRate_changed(quint64 value); void on_channelSampleRate_changed(quint64 value);
void on_useRationalDownsampler_toggled(bool checked); void on_useRationalDownsampler_toggled(bool checked);
@ -69,6 +69,7 @@ private slots:
void on_ssb_toggled(bool checked); void on_ssb_toggled(bool checked);
void onWidgetRolled(QWidget* widget, bool rollDown); void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDoubleClicked(); void onMenuDoubleClicked();
void handleInputMessages();
void tick(); void tick();
private: private:
@ -82,8 +83,8 @@ private:
int m_spanLog2; int m_spanLog2;
MovingAverage<double> m_channelPowerDbAvg; MovingAverage<double> m_channelPowerDbAvg;
ThreadedBasebandSampleSink* m_threadedChannelizer; // ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer; // DownChannelizer* m_channelizer;
ChannelAnalyzerNG* m_channelAnalyzer; ChannelAnalyzerNG* m_channelAnalyzer;
SpectrumScopeNGComboVis* m_spectrumScopeComboVis; SpectrumScopeNGComboVis* m_spectrumScopeComboVis;
SpectrumVis* m_spectrumVis; SpectrumVis* m_spectrumVis;

View File

@ -48,7 +48,7 @@ void ChannelAnalyzerNGPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerRxChannel(ChannelAnalyzerNGGUI::m_channelID, this); m_pluginAPI->registerRxChannel(ChannelAnalyzerNGGUI::m_channelID, this);
} }
PluginInstanceUI* ChannelAnalyzerNGPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) PluginInstanceGUI* ChannelAnalyzerNGPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{ {
if(channelName == ChannelAnalyzerNGGUI::m_channelID) if(channelName == ChannelAnalyzerNGGUI::m_channelID)
{ {

View File

@ -34,7 +34,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -3,12 +3,14 @@ project(am)
set(am_SOURCES set(am_SOURCES
amdemod.cpp amdemod.cpp
amdemodgui.cpp amdemodgui.cpp
amdemodsettings.cpp
amdemodplugin.cpp amdemodplugin.cpp
) )
set(am_HEADERS set(am_HEADERS
amdemod.h amdemod.h
amdemodgui.h amdemodgui.h
amdemodsettings.h
amdemodplugin.h amdemodplugin.h
) )

View File

@ -26,12 +26,16 @@
#include "audio/audiooutput.h" #include "audio/audiooutput.h"
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "dsp/pidcontroller.h" #include "dsp/pidcontroller.h"
#include "dsp/threadedbasebandsamplesink.h"
#include "device/devicesourceapi.h"
MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message) MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message)
MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureChannelizer, Message)
const int AMDemod::m_udpBlockSize = 512; const int AMDemod::m_udpBlockSize = 512;
AMDemod::AMDemod() : AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_squelchOpen(false), m_squelchOpen(false),
m_magsqSum(0.0f), m_magsqSum(0.0f),
m_magsqPeak(0.0f), m_magsqPeak(0.0f),
@ -43,14 +47,9 @@ AMDemod::AMDemod() :
{ {
setObjectName("AMDemod"); setObjectName("AMDemod");
m_config.m_inputSampleRate = 96000; m_channelizer = new DownChannelizer(this);
m_config.m_inputFrequencyOffset = 0; m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
m_config.m_rfBandwidth = 5000; m_deviceAPI->addThreadedSink(m_threadedChannelizer);
m_config.m_squelch = -40.0;
m_config.m_volume = 2.0;
m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
apply();
m_audioBuffer.resize(1<<14); m_audioBuffer.resize(1<<14);
m_audioBufferFill = 0; m_audioBufferFill = 0;
@ -60,7 +59,9 @@ AMDemod::AMDemod() :
m_magsq = 0.0; m_magsq = 0.0;
DSPEngine::instance()->addAudioSink(&m_audioFifo); DSPEngine::instance()->addAudioSink(&m_audioFifo);
m_udpBufferAudio = new UDPSink<qint16>(this, m_udpBlockSize, m_config.m_udpPort); m_udpBufferAudio = new UDPSink<qint16>(this, m_udpBlockSize, m_settings.m_udpPort);
applySettings(m_settings, true);
} }
AMDemod::~AMDemod() AMDemod::~AMDemod()
@ -69,29 +70,6 @@ AMDemod::~AMDemod()
delete m_udpBufferAudio; delete m_udpBufferAudio;
} }
void AMDemod::configure(MessageQueue* messageQueue,
Real rfBandwidth,
Real volume,
Real squelch,
bool audioMute,
bool bandpassEnable,
bool copyAudioToUDP,
const QString& udpAddress,
quint16 udpPort,
bool force)
{
Message* cmd = MsgConfigureAMDemod::create(rfBandwidth,
volume,
squelch,
audioMute,
bandpassEnable,
copyAudioToUDP,
udpAddress,
udpPort,
force);
messageQueue->push(cmd);
}
void AMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst __attribute__((unused))) void AMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst __attribute__((unused)))
{ {
Complex ci; Complex ci;
@ -142,8 +120,8 @@ void AMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector
void AMDemod::start() void AMDemod::start()
{ {
qDebug() << "AMDemod::start: m_inputSampleRate: " << m_config.m_inputSampleRate qDebug() << "AMDemod::start: m_inputSampleRate: " << m_settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset; << " m_inputFrequencyOffset: " << m_settings.m_inputFrequencyOffset;
m_squelchCount = 0; m_squelchCount = 0;
m_audioFifo.clear(); m_audioFifo.clear();
@ -161,41 +139,51 @@ bool AMDemod::handleMessage(const Message& cmd)
{ {
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
m_config.m_inputSampleRate = notif.getSampleRate(); AMDemodSettings settings = m_settings;
m_config.m_inputFrequencyOffset = notif.getFrequencyOffset();
apply(); settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
qDebug() << "AMDemod::handleMessage: MsgChannelizerNotification:" applySettings(settings);
<< " m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset; qDebug() << "AMDemod::handleMessage: MsgChannelizerNotification:"
<< " m_inputSampleRate: " << settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset;
return true; return true;
} }
else if (MsgConfigureChannelizer::match(cmd))
{
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(),
cfg.getCenterFrequency());
return true;
}
else if (MsgConfigureAMDemod::match(cmd)) else if (MsgConfigureAMDemod::match(cmd))
{ {
MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd; MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd;
m_config.m_rfBandwidth = cfg.getRFBandwidth(); AMDemodSettings settings = cfg.getSettings();
m_config.m_volume = cfg.getVolume();
m_config.m_squelch = cfg.getSquelch();
m_config.m_audioMute = cfg.getAudioMute();
m_config.m_bandpassEnable = cfg.getBandpassEnable();
m_config.m_copyAudioToUDP = cfg.getCopyAudioToUDP();
m_config.m_udpAddress = cfg.getUDPAddress();
m_config.m_udpPort = cfg.getUDPPort();
apply(cfg.getForce()); // These settings are set with DownChannelizer::MsgChannelizerNotification
settings.m_inputSampleRate = m_settings.m_inputSampleRate;
settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset;
qDebug() << "AMDemod::handleMessage: MsgConfigureAMDemod:" applySettings(settings, cfg.getForce());
<< " m_rfBandwidth: " << m_config.m_rfBandwidth
<< " m_volume: " << m_config.m_volume qDebug() << "AMDemod::handleMessage: MsgConfigureAMDemod:"
<< " m_squelch: " << m_config.m_squelch << " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_audioMute: " << m_config.m_audioMute << " m_volume: " << settings.m_volume
<< " m_bandpassEnable: " << m_config.m_bandpassEnable << " m_squelch: " << settings.m_squelch
<< " m_copyAudioToUDP: " << m_config.m_copyAudioToUDP << " m_audioMute: " << settings.m_audioMute
<< " m_udpAddress: " << m_config.m_udpAddress << " m_bandpassEnable: " << settings.m_bandpassEnable
<< " m_udpPort: " << m_config.m_udpPort; << " m_copyAudioToUDP: " << settings.m_copyAudioToUDP
<< " m_udpAddress: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " force: " << cfg.getForce();
return true; return true;
} }
@ -205,40 +193,38 @@ bool AMDemod::handleMessage(const Message& cmd)
} }
} }
void AMDemod::apply(bool force) void AMDemod::applySettings(const AMDemodSettings& settings, bool force)
{ {
if ((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) ||
if ((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || (m_settings.m_inputSampleRate != settings.m_inputSampleRate) || force)
(m_config.m_inputSampleRate != m_running.m_inputSampleRate) || force)
{
m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate);
}
if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth) ||
(m_config.m_audioSampleRate != m_running.m_audioSampleRate) ||
(m_config.m_bandpassEnable != m_running.m_bandpassEnable) || force)
{
m_settingsMutex.lock();
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2f);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate;
m_bandpass.create(301, m_config.m_audioSampleRate, 300.0, m_config.m_rfBandwidth / 2.0f);
m_settingsMutex.unlock();
}
if ((m_config.m_squelch != m_running.m_squelch) || force)
{
m_squelchLevel = pow(10.0, m_config.m_squelch / 20.0);
m_squelchLevel *= m_squelchLevel;
}
if ((m_config.m_udpAddress != m_running.m_udpAddress)
|| (m_config.m_udpPort != m_running.m_udpPort) || force)
{ {
m_udpBufferAudio->setAddress(m_config.m_udpAddress); m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate);
m_udpBufferAudio->setPort(m_config.m_udpPort);
} }
m_running = m_config; if((m_settings.m_inputSampleRate != settings.m_inputSampleRate) ||
(m_settings.m_rfBandwidth != settings.m_rfBandwidth) ||
(m_settings.m_audioSampleRate != settings.m_audioSampleRate) ||
(m_settings.m_bandpassEnable != settings.m_bandpassEnable) || force)
{
m_settingsMutex.lock();
m_interpolator.create(16, settings.m_inputSampleRate, settings.m_rfBandwidth / 2.2f);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate;
m_bandpass.create(301, settings.m_audioSampleRate, 300.0, settings.m_rfBandwidth / 2.0f);
m_settingsMutex.unlock();
}
if ((m_settings.m_squelch != settings.m_squelch) || force)
{
m_squelchLevel = pow(10.0, settings.m_squelch / 10.0);
}
if ((m_settings.m_udpAddress != settings.m_udpAddress)
|| (m_settings.m_udpPort != settings.m_udpPort) || force)
{
m_udpBufferAudio->setAddress(const_cast<QString&>(settings.m_udpAddress));
m_udpBufferAudio->setPort(settings.m_udpPort);
}
m_settings = settings;
} }

View File

@ -27,23 +27,63 @@
#include "dsp/bandpass.h" #include "dsp/bandpass.h"
#include "audio/audiofifo.h" #include "audio/audiofifo.h"
#include "util/message.h" #include "util/message.h"
#include "amdemodsettings.h"
class DeviceSourceAPI;
class DownChannelizer;
class ThreadedBasebandSampleSink;
class AMDemod : public BasebandSampleSink { class AMDemod : public BasebandSampleSink {
Q_OBJECT Q_OBJECT
public: public:
AMDemod(); class MsgConfigureAMDemod : public Message {
~AMDemod(); MESSAGE_CLASS_DECLARATION
void configure(MessageQueue* messageQueue, public:
Real rfBandwidth, const AMDemodSettings& getSettings() const { return m_settings; }
Real volume, bool getForce() const { return m_force; }
Real squelch,
bool audioMute, static MsgConfigureAMDemod* create(const AMDemodSettings& settings, bool force)
bool bandpassEnable, {
bool copyAudioToUDP, return new MsgConfigureAMDemod(settings, force);
const QString& udpAddress, }
quint16 udpPort,
bool force); private:
AMDemodSettings m_settings;
bool m_force;
MsgConfigureAMDemod(const AMDemodSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
class MsgConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
{
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
}
private:
int m_sampleRate;
int m_centerFrequency;
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
Message(),
m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency)
{ }
};
AMDemod(DeviceSourceAPI *deviceAPI);
~AMDemod();
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
virtual void start(); virtual void start();
@ -64,109 +104,16 @@ public:
} }
private: private:
class MsgConfigureAMDemod : public Message {
MESSAGE_CLASS_DECLARATION
public:
Real getRFBandwidth() const { return m_rfBandwidth; }
Real getVolume() const { return m_volume; }
Real getSquelch() const { return m_squelch; }
bool getAudioMute() const { return m_audioMute; }
bool getBandpassEnable() const { return m_bandpassEnable; }
bool getCopyAudioToUDP() const { return m_copyAudioToUDP; }
const QString& getUDPAddress() const { return m_udpAddress; }
quint16 getUDPPort() const { return m_udpPort; }
bool getForce() const { return m_force; }
static MsgConfigureAMDemod* create(Real rfBandwidth,
Real volume,
Real squelch,
bool audioMute,
bool bandpassEnable,
bool copyAudioToUDP,
const QString& udpAddress,
quint16 udpPort,
bool force)
{
return new MsgConfigureAMDemod(rfBandwidth,
volume,
squelch,
audioMute,
bandpassEnable,
copyAudioToUDP,
udpAddress,
udpPort,
force);
}
private:
Real m_rfBandwidth;
Real m_volume;
Real m_squelch;
bool m_audioMute;
bool m_bandpassEnable;
bool m_copyAudioToUDP;
QString m_udpAddress;
quint16 m_udpPort;
bool m_force;
MsgConfigureAMDemod(Real rfBandwidth,
Real volume,
Real squelch,
bool audioMute,
bool bandpassEnable,
bool copyAudioToUDP,
const QString& udpAddress,
quint16 udpPort,
bool force) :
Message(),
m_rfBandwidth(rfBandwidth),
m_volume(volume),
m_squelch(squelch),
m_audioMute(audioMute),
m_bandpassEnable(bandpassEnable),
m_copyAudioToUDP(copyAudioToUDP),
m_udpAddress(udpAddress),
m_udpPort(udpPort),
m_force(force)
{ }
};
enum RateState { enum RateState {
RSInitialFill, RSInitialFill,
RSRunning RSRunning
}; };
struct Config { DeviceSourceAPI *m_deviceAPI;
int m_inputSampleRate; ThreadedBasebandSampleSink* m_threadedChannelizer;
qint64 m_inputFrequencyOffset; DownChannelizer* m_channelizer;
Real m_rfBandwidth;
Real m_squelch;
Real m_volume;
quint32 m_audioSampleRate;
bool m_audioMute;
bool m_bandpassEnable;
bool m_copyAudioToUDP;
QString m_udpAddress;
quint16 m_udpPort;
Config() : AMDemodSettings m_settings;
m_inputSampleRate(-1),
m_inputFrequencyOffset(0),
m_rfBandwidth(-1),
m_squelch(0),
m_volume(0),
m_audioSampleRate(0),
m_audioMute(false),
m_bandpassEnable(false),
m_copyAudioToUDP(false),
m_udpAddress("127.0.0.1"),
m_udpPort(9999)
{ }
};
Config m_config;
Config m_running;
NCO m_nco; NCO m_nco;
Interpolator m_interpolator; Interpolator m_interpolator;
@ -194,7 +141,8 @@ private:
QMutex m_settingsMutex; QMutex m_settingsMutex;
void apply(bool force = false); // void apply(bool force = false);
void applySettings(const AMDemodSettings& settings, bool force = false);
void processOneSample(Complex &ci) void processOneSample(Complex &ci)
{ {
@ -213,9 +161,9 @@ private:
if (m_magsq >= m_squelchLevel) if (m_magsq >= m_squelchLevel)
{ {
if (m_squelchCount <= m_running.m_audioSampleRate / 10) if (m_squelchCount <= m_settings.m_audioSampleRate / 10)
{ {
if (m_squelchCount == m_running.m_audioSampleRate / 20) { if (m_squelchCount == m_settings.m_audioSampleRate / 20) {
m_volumeAGC.fill(1.0); m_volumeAGC.fill(1.0);
} }
@ -232,28 +180,28 @@ private:
qint16 sample; qint16 sample;
if ((m_squelchCount >= m_running.m_audioSampleRate / 20) && !m_running.m_audioMute) if ((m_squelchCount >= m_settings.m_audioSampleRate / 20) && !m_settings.m_audioMute)
{ {
Real demod = sqrt(magsq); Real demod = sqrt(magsq);
m_volumeAGC.feed(demod); m_volumeAGC.feed(demod);
demod = (demod - m_volumeAGC.getValue()) / m_volumeAGC.getValue(); demod = (demod - m_volumeAGC.getValue()) / m_volumeAGC.getValue();
if (m_running.m_bandpassEnable) if (m_settings.m_bandpassEnable)
{ {
demod = m_bandpass.filter(demod); demod = m_bandpass.filter(demod);
demod /= 301.0f; demod /= 301.0f;
} }
Real attack = (m_squelchCount - 0.05f * m_running.m_audioSampleRate) / (0.05f * m_running.m_audioSampleRate); Real attack = (m_squelchCount - 0.05f * m_settings.m_audioSampleRate) / (0.05f * m_settings.m_audioSampleRate);
sample = demod * attack * 2048 * m_running.m_volume; sample = demod * attack * 2048 * m_settings.m_volume;
if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(demod * attack * 32768); if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(demod * attack * 32768);
m_squelchOpen = true; m_squelchOpen = true;
} }
else else
{ {
sample = 0; sample = 0;
if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(0); if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(0);
m_squelchOpen = false; m_squelchOpen = false;
} }
@ -273,6 +221,7 @@ private:
m_audioBufferFill = 0; m_audioBufferFill = 0;
} }
} }
}; };
#endif // INCLUDE_AMDEMOD_H #endif // INCLUDE_AMDEMOD_H

View File

@ -68,83 +68,27 @@ void AMDemodGUI::setCenterFrequency(qint64 centerFrequency)
void AMDemodGUI::resetToDefaults() void AMDemodGUI::resetToDefaults()
{ {
blockApplySettings(true); m_settings.resetToDefaults();
displaySettings();
ui->rfBW->setValue(50); applySettings(true);
ui->volume->setValue(20);
ui->squelch->setValue(-40);
ui->deltaFrequency->setValue(0);
blockApplySettings(false);
applySettings();
} }
QByteArray AMDemodGUI::serialize() const QByteArray AMDemodGUI::serialize() const
{ {
SimpleSerializer s(1); return m_settings.serialize();
s.writeS32(1, m_channelMarker.getCenterFrequency());
s.writeS32(2, ui->rfBW->value());
s.writeS32(4, ui->volume->value());
s.writeS32(5, ui->squelch->value());
s.writeBlob(6, m_channelMarker.serialize());
s.writeU32(7, m_channelMarker.getColor().rgb());
s.writeBool(8, ui->bandpassEnable->isChecked());
return s.final();
} }
bool AMDemodGUI::deserialize(const QByteArray& data) bool AMDemodGUI::deserialize(const QByteArray& data)
{ {
SimpleDeserializer d(data); if(m_settings.deserialize(data)) {
updateChannelMarker();
if(!d.isValid()) displaySettings();
{ applySettings(true);
resetToDefaults(); return true;
return false; } else {
} resetToDefaults();
return false;
if(d.getVersion() == 1) }
{
QByteArray bytetmp;
quint32 u32tmp;
qint32 tmp;
bool boolTmp;
QString strtmp;
blockApplySettings(true);
m_channelMarker.blockSignals(true);
d.readBlob(6, &bytetmp);
m_channelMarker.deserialize(bytetmp);
d.readS32(1, &tmp, 0);
m_channelMarker.setCenterFrequency(tmp);
d.readS32(2, &tmp, 4);
ui->rfBW->setValue(tmp);
d.readS32(3, &tmp, 3);
//ui->afBW->setValue(tmp);
d.readS32(4, &tmp, 20);
ui->volume->setValue(tmp);
d.readS32(5, &tmp, -40);
ui->squelch->setValue(tmp);
if(d.readU32(7, &u32tmp)) {
m_channelMarker.setColor(u32tmp);
}
d.readBool(8, &boolTmp, false);
ui->bandpassEnable->setChecked(boolTmp);
this->setWindowTitle(m_channelMarker.getTitle());
displayUDPAddress();
blockApplySettings(false);
m_channelMarker.blockSignals(false);
applySettings(true);
return true;
}
else
{
resetToDefaults();
return false;
}
} }
bool AMDemodGUI::handleMessage(const Message& message __attribute__((unused))) bool AMDemodGUI::handleMessage(const Message& message __attribute__((unused)))
@ -155,17 +99,25 @@ bool AMDemodGUI::handleMessage(const Message& message __attribute__((unused)))
void AMDemodGUI::channelMarkerChanged() void AMDemodGUI::channelMarkerChanged()
{ {
this->setWindowTitle(m_channelMarker.getTitle()); this->setWindowTitle(m_channelMarker.getTitle());
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
m_settings.m_udpAddress = m_channelMarker.getUDPAddress(),
m_settings.m_udpPort = m_channelMarker.getUDPSendPort(),
m_settings.m_rgbColor = m_channelMarker.getColor().rgb();
displayUDPAddress(); displayUDPAddress();
//m_settings.m_channelMarkerBytes = m_channelMarker.serialize();
applySettings(); applySettings();
} }
void AMDemodGUI::on_deltaFrequency_changed(qint64 value) void AMDemodGUI::on_deltaFrequency_changed(qint64 value)
{ {
m_channelMarker.setCenterFrequency(value); m_channelMarker.setCenterFrequency(value);
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
applySettings();
} }
void AMDemodGUI::on_bandpassEnable_toggled(bool checked __attribute__((unused))) void AMDemodGUI::on_bandpassEnable_toggled(bool checked)
{ {
m_settings.m_bandpassEnable = checked;
applySettings(); applySettings();
} }
@ -173,28 +125,33 @@ void AMDemodGUI::on_rfBW_valueChanged(int value)
{ {
ui->rfBWText->setText(QString("%1 kHz").arg(value / 10.0, 0, 'f', 1)); ui->rfBWText->setText(QString("%1 kHz").arg(value / 10.0, 0, 'f', 1));
m_channelMarker.setBandwidth(value * 100); m_channelMarker.setBandwidth(value * 100);
m_settings.m_rfBandwidth = value * 100;
applySettings(); applySettings();
} }
void AMDemodGUI::on_volume_valueChanged(int value) void AMDemodGUI::on_volume_valueChanged(int value)
{ {
ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
m_settings.m_volume = value / 10.0;
applySettings(); applySettings();
} }
void AMDemodGUI::on_squelch_valueChanged(int value) void AMDemodGUI::on_squelch_valueChanged(int value)
{ {
ui->squelchText->setText(QString("%1 dB").arg(value)); ui->squelchText->setText(QString("%1 dB").arg(value));
m_settings.m_squelch = value;
applySettings(); applySettings();
} }
void AMDemodGUI::on_audioMute_toggled(bool checked __attribute__((unused))) void AMDemodGUI::on_audioMute_toggled(bool checked)
{ {
m_settings.m_audioMute = checked;
applySettings(); applySettings();
} }
void AMDemodGUI::on_copyAudioToUDP_toggled(bool checked __attribute__((unused))) void AMDemodGUI::on_copyAudioToUDP_toggled(bool checked)
{ {
m_settings.m_copyAudioToUDP = checked;
applySettings(); applySettings();
} }
@ -228,11 +185,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
m_amDemod = new AMDemod(); m_amDemod = new AMDemod(m_deviceAPI);
m_channelizer = new DownChannelizer(m_amDemod);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
//m_pluginAPI->addThreadedSink(m_threadedChannelizer);
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
@ -241,7 +194,6 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue); ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue);
//m_channelMarker = new ChannelMarker(this);
m_channelMarker.setColor(Qt::yellow); m_channelMarker.setColor(Qt::yellow);
m_channelMarker.setBandwidth(5000); m_channelMarker.setBandwidth(5000);
m_channelMarker.setCenterFrequency(0); m_channelMarker.setCenterFrequency(0);
@ -250,6 +202,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget
m_channelMarker.setUDPSendPort(9999); m_channelMarker.setUDPSendPort(9999);
m_channelMarker.setVisible(true); m_channelMarker.setVisible(true);
setTitleColor(m_channelMarker.getColor()); setTitleColor(m_channelMarker.getColor());
m_settings.setChannelMarker(&m_channelMarker);
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
@ -257,17 +210,14 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget
m_deviceAPI->addChannelMarker(&m_channelMarker); m_deviceAPI->addChannelMarker(&m_channelMarker);
m_deviceAPI->addRollupWidget(this); m_deviceAPI->addRollupWidget(this);
displaySettings();
applySettings(true); applySettings(true);
} }
AMDemodGUI::~AMDemodGUI() AMDemodGUI::~AMDemodGUI()
{ {
m_deviceAPI->removeChannelInstance(this); m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
delete m_amDemod; delete m_amDemod;
//delete m_channelMarker;
delete ui; delete ui;
} }
@ -282,30 +232,62 @@ void AMDemodGUI::applySettings(bool force)
{ {
setTitleColor(m_channelMarker.getColor()); setTitleColor(m_channelMarker.getColor());
m_channelizer->configure(m_channelizer->getInputMessageQueue(), AMDemod::MsgConfigureChannelizer* channelConfigMsg = AMDemod::MsgConfigureChannelizer::create(
48000, 48000, m_channelMarker.getCenterFrequency());
m_channelMarker.getCenterFrequency()); m_amDemod->getInputMessageQueue()->push(channelConfigMsg);
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_amDemod->configure(m_amDemod->getInputMessageQueue(), AMDemod::MsgConfigureAMDemod* message = AMDemod::MsgConfigureAMDemod::create( m_settings, force);
ui->rfBW->value() * 100.0, m_amDemod->getInputMessageQueue()->push(message);
ui->volume->value() / 10.0,
ui->squelch->value(),
ui->audioMute->isChecked(),
ui->bandpassEnable->isChecked(),
ui->copyAudioToUDP->isChecked(),
m_channelMarker.getUDPAddress(),
m_channelMarker.getUDPSendPort(),
force);
} }
} }
void AMDemodGUI::displaySettings()
{
blockApplySettings(true);
int displayValue = m_settings.m_rfBandwidth/100.0;
ui->rfBW->setValue(displayValue);
ui->rfBWText->setText(QString("%1 kHz").arg(displayValue / 10.0, 0, 'f', 1));
m_channelMarker.setBandwidth(m_settings.m_rfBandwidth);
ui->volume->setValue(m_settings.m_volume * 10.0);
ui->volumeText->setText(QString("%1").arg(m_settings.m_volume, 0, 'f', 1));
ui->squelch->setValue(m_settings.m_squelch);
ui->squelchText->setText(QString("%1 dB").arg(m_settings.m_squelch));
ui->audioMute->setChecked(m_settings.m_audioMute);
ui->bandpassEnable->setChecked(m_settings.m_bandpassEnable);
ui->copyAudioToUDP->setChecked(m_settings.m_copyAudioToUDP);
m_channelMarker.blockSignals(true);
m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
m_channelMarker.setUDPAddress(m_settings.m_udpAddress);
m_channelMarker.setUDPSendPort(m_settings.m_udpPort);
m_channelMarker.setColor(m_settings.m_rgbColor);
setTitleColor(m_settings.m_rgbColor);
m_channelMarker.blockSignals(false);
blockApplySettings(false);
}
void AMDemodGUI::displayUDPAddress() void AMDemodGUI::displayUDPAddress()
{ {
ui->copyAudioToUDP->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort())); ui->copyAudioToUDP->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort()));
} }
void AMDemodGUI::updateChannelMarker()
{
m_channelMarker.blockSignals(true);
//m_channelMarker.deserialize(m_settings.m_channelMarkerBytes);
this->setWindowTitle(m_channelMarker.getTitle());
m_channelMarker.blockSignals(false);
}
void AMDemodGUI::leaveEvent(QEvent*) void AMDemodGUI::leaveEvent(QEvent*)
{ {
blockApplySettings(true); blockApplySettings(true);

View File

@ -1,11 +1,12 @@
#ifndef INCLUDE_AMDEMODGUI_H #ifndef INCLUDE_AMDEMODGUI_H
#define INCLUDE_AMDEMODGUI_H #define INCLUDE_AMDEMODGUI_H
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
#include "amdemodsettings.h"
class PluginAPI; class PluginAPI;
class DeviceSourceAPI; class DeviceSourceAPI;
@ -18,7 +19,7 @@ namespace Ui {
class AMDemodGUI; class AMDemodGUI;
} }
class AMDemodGUI : public RollupWidget, public PluginInstanceUI { class AMDemodGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:
@ -56,10 +57,11 @@ private:
PluginAPI* m_pluginAPI; PluginAPI* m_pluginAPI;
DeviceSourceAPI* m_deviceAPI; DeviceSourceAPI* m_deviceAPI;
ChannelMarker m_channelMarker; ChannelMarker m_channelMarker;
AMDemodSettings m_settings;
bool m_doApplySettings; bool m_doApplySettings;
ThreadedBasebandSampleSink* m_threadedChannelizer; // ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer; // DownChannelizer* m_channelizer;
AMDemod* m_amDemod; AMDemod* m_amDemod;
bool m_squelchOpen; bool m_squelchOpen;
uint32_t m_tickCount; uint32_t m_tickCount;
@ -70,7 +72,9 @@ private:
void blockApplySettings(bool block); void blockApplySettings(bool block);
void applySettings(bool force = false); void applySettings(bool force = false);
void displaySettings();
void displayUDPAddress(); void displayUDPAddress();
void updateChannelMarker();
void leaveEvent(QEvent*); void leaveEvent(QEvent*);
void enterEvent(QEvent*); void enterEvent(QEvent*);

View File

@ -7,7 +7,7 @@
const PluginDescriptor AMDemodPlugin::m_pluginDescriptor = { const PluginDescriptor AMDemodPlugin::m_pluginDescriptor = {
QString("AM Demodulator"), QString("AM Demodulator"),
QString("3.6.1"), QString("3.7.3"),
QString("(c) Edouard Griffiths, F4EXB"), QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"), QString("https://github.com/f4exb/sdrangel"),
true, true,
@ -33,7 +33,7 @@ void AMDemodPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerRxChannel(AMDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(AMDemodGUI::m_channelID, this);
} }
PluginInstanceUI* AMDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) PluginInstanceGUI* AMDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{ {
if(channelName == AMDemodGUI::m_channelID) if(channelName == AMDemodGUI::m_channelID)
{ {

View File

@ -33,7 +33,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -0,0 +1,100 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "dsp/dspengine.h"
#include "util/simpleserializer.h"
#include "settings/serializable.h"
#include "amdemodsettings.h"
AMDemodSettings::AMDemodSettings() :
m_channelMarker(0)
{
resetToDefaults();
}
void AMDemodSettings::resetToDefaults()
{
m_inputSampleRate = 96000;
m_inputFrequencyOffset = 0;
m_rfBandwidth = 5000;
m_squelch = -40.0;
m_volume = 2.0;
m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
m_audioMute = false;
m_bandpassEnable = false;
m_copyAudioToUDP = false;
m_udpAddress = "127.0.0.1";
m_udpPort = 9999;
}
QByteArray AMDemodSettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_inputFrequencyOffset);
s.writeS32(2, m_rfBandwidth/100);
s.writeS32(4, m_volume*10);
s.writeS32(5, m_squelch);
if (m_channelMarker) {
s.writeBlob(6, m_channelMarker->serialize());
}
s.writeU32(7, m_rgbColor);
s.writeBool(8, m_bandpassEnable);
return s.final();
}
bool AMDemodSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1)
{
QByteArray bytetmp;
qint32 tmp;
QString strtmp;
d.readS32(1, &m_inputFrequencyOffset, 0);
d.readS32(2, &tmp, 4);
m_rfBandwidth = 100 * tmp;
d.readS32(4, &tmp, 20);
m_volume = tmp * 0.1;
d.readS32(5, &tmp, -40);
m_squelch = tmp;
d.readBlob(6, &bytetmp);
if (m_channelMarker) {
m_channelMarker->deserialize(bytetmp);
}
d.readU32(7, &m_rgbColor);
d.readBool(8, &m_bandpassEnable, false);
return true;
}
else
{
resetToDefaults();
return false;
}
}

View File

@ -0,0 +1,49 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_CHANNELRX_DEMODAM_AMDEMODSETTINGS_H_
#define PLUGINS_CHANNELRX_DEMODAM_AMDEMODSETTINGS_H_
#include <QByteArray>
class Serializable;
struct AMDemodSettings
{
int m_inputSampleRate;
qint32 m_inputFrequencyOffset;
Real m_rfBandwidth;
Real m_squelch;
Real m_volume;
quint32 m_audioSampleRate;
bool m_audioMute;
bool m_bandpassEnable;
bool m_copyAudioToUDP;
QString m_udpAddress;
quint16 m_udpPort;
quint32 m_rgbColor;
Serializable *m_channelMarker;
AMDemodSettings();
void resetToDefaults();
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif /* PLUGINS_CHANNELRX_DEMODAM_AMDEMODSETTINGS_H_ */

View File

@ -25,11 +25,13 @@ CONFIG(Debug):build_subdir = debug
SOURCES += amdemod.cpp\ SOURCES += amdemod.cpp\
amdemodgui.cpp\ amdemodgui.cpp\
amdemodplugin.cpp amdemodplugin.cpp\
amdemodsettings.cpp
HEADERS += amdemod.h\ HEADERS += amdemod.h\
amdemodgui.h\ amdemodgui.h\
amdemodplugin.h amdemodplugin.h\
amdemodsettings.h
FORMS += amdemodgui.ui FORMS += amdemodgui.ui

View File

@ -31,9 +31,9 @@ MESSAGE_CLASS_DEFINITION(ATVDemod::MsgReportEffectiveSampleRate, Message)
const int ATVDemod::m_ssbFftLen = 1024; const int ATVDemod::m_ssbFftLen = 1024;
ATVDemod::ATVDemod(BasebandSampleSink* objScopeSink) : ATVDemod::ATVDemod(DeviceSourceAPI *deviceAPI) :
m_objScopeSink(objScopeSink), m_deviceAPI(deviceAPI),
m_objRegisteredATVScreen(NULL), m_registeredATVScreen(NULL),
m_intNumberSamplePerTop(0), m_intNumberSamplePerTop(0),
m_intImageIndex(0), m_intImageIndex(0),
m_intSynchroPoints(0), m_intSynchroPoints(0),
@ -70,7 +70,7 @@ ATVDemod::ATVDemod(BasebandSampleSink* objScopeSink) :
m_objMagSqAverage.resize(32, 1.0); m_objMagSqAverage.resize(32, 1.0);
m_DSBFilter = new fftfilt((2.0f * m_objRFConfig.m_fltRFBandwidth) / 1000000, 2 * m_ssbFftLen); // arbitrary 1 MS/s sample rate m_DSBFilter = new fftfilt((2.0f * m_rfConfig.m_fltRFBandwidth) / 1000000, 2 * m_ssbFftLen); // arbitrary 1 MS/s sample rate
m_DSBFilterBuffer = new Complex[m_ssbFftLen]; m_DSBFilterBuffer = new Complex[m_ssbFftLen];
memset(m_DSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen)); memset(m_DSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen));
@ -88,7 +88,7 @@ ATVDemod::~ATVDemod()
void ATVDemod::setATVScreen(ATVScreen *objScreen) void ATVDemod::setATVScreen(ATVScreen *objScreen)
{ {
m_objRegisteredATVScreen = objScreen; m_registeredATVScreen = objScreen;
} }
void ATVDemod::configure( void ATVDemod::configure(
@ -188,12 +188,12 @@ void ATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
#endif #endif
Complex c(fltI, fltQ); Complex c(fltI, fltQ);
if (m_objRFRunning.m_intFrequencyOffset != 0) if (m_rfRunning.m_intFrequencyOffset != 0)
{ {
c *= m_nco.nextIQ(); c *= m_nco.nextIQ();
} }
if (m_objRFRunning.m_blndecimatorEnable) if (m_rfRunning.m_blndecimatorEnable)
{ {
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci)) if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci))
{ {
@ -207,10 +207,10 @@ void ATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
} }
} }
if ((m_objRunning.m_intVideoTabIndex == 1) && (m_objScopeSink != 0)) // do only if scope tab is selected and scope is available if ((m_running.m_intVideoTabIndex == 1) && (m_scopeSink != 0)) // do only if scope tab is selected and scope is available
{ {
m_objScopeSink->feed(m_objScopeSampleBuffer.begin(), m_objScopeSampleBuffer.end(), false); // m_ssb = positive only m_scopeSink->feed(m_scopeSampleBuffer.begin(), m_scopeSampleBuffer.end(), false); // m_ssb = positive only
m_objScopeSampleBuffer.clear(); m_scopeSampleBuffer.clear();
} }
if (ptrBufferToRelease != 0) if (ptrBufferToRelease != 0)
@ -223,7 +223,7 @@ void ATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
void ATVDemod::demod(Complex& c) void ATVDemod::demod(Complex& c)
{ {
float fltDivSynchroBlack = 1.0f - m_objRunning.m_fltVoltLevelSynchroBlack; float fltDivSynchroBlack = 1.0f - m_running.m_fltVoltLevelSynchroBlack;
float fltNormI; float fltNormI;
float fltNormQ; float fltNormQ;
float fltNorm; float fltNorm;
@ -232,12 +232,12 @@ void ATVDemod::demod(Complex& c)
//********** FFT filtering ********** //********** FFT filtering **********
if (m_objRFRunning.m_blnFFTFiltering) if (m_rfRunning.m_blnFFTFiltering)
{ {
int n_out; int n_out;
fftfilt::cmplx *filtered; fftfilt::cmplx *filtered;
n_out = m_DSBFilter->runAsym(c, &filtered, m_objRFRunning.m_enmModulation != ATV_LSB); // all usb except explicitely lsb n_out = m_DSBFilter->runAsym(c, &filtered, m_rfRunning.m_enmModulation != ATV_LSB); // all usb except explicitely lsb
if (n_out > 0) if (n_out > 0)
{ {
@ -250,11 +250,11 @@ void ATVDemod::demod(Complex& c)
//********** demodulation ********** //********** demodulation **********
const float& fltI = m_objRFRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].real() : c.real(); const float& fltI = m_rfRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].real() : c.real();
const float& fltQ = m_objRFRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].imag() : c.imag(); const float& fltQ = m_rfRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].imag() : c.imag();
double magSq; double magSq;
if ((m_objRFRunning.m_enmModulation == ATV_FM1) || (m_objRFRunning.m_enmModulation == ATV_FM2)) if ((m_rfRunning.m_enmModulation == ATV_FM1) || (m_rfRunning.m_enmModulation == ATV_FM2))
{ {
//Amplitude FM //Amplitude FM
magSq = fltI*fltI + fltQ*fltQ; magSq = fltI*fltI + fltQ*fltQ;
@ -266,7 +266,7 @@ void ATVDemod::demod(Complex& c)
//-2 > 2 : 0 -> 1 volt //-2 > 2 : 0 -> 1 volt
//0->0.3 synchro 0.3->1 image //0->0.3 synchro 0.3->1 image
if (m_objRFRunning.m_enmModulation == ATV_FM1) if (m_rfRunning.m_enmModulation == ATV_FM1)
{ {
//YDiff Cd //YDiff Cd
fltVal = m_fltBufferI[0]*(fltNormQ - m_fltBufferQ[1]); fltVal = m_fltBufferI[0]*(fltNormQ - m_fltBufferQ[1]);
@ -304,12 +304,12 @@ void ATVDemod::demod(Complex& c)
m_fltBufferI[0]=fltNormI; m_fltBufferI[0]=fltNormI;
m_fltBufferQ[0]=fltNormQ; m_fltBufferQ[0]=fltNormQ;
if (m_objRFRunning.m_fmDeviation != 1.0f) if (m_rfRunning.m_fmDeviation != 1.0f)
{ {
fltVal = ((fltVal - 0.5f) / m_objRFRunning.m_fmDeviation) + 0.5f; fltVal = ((fltVal - 0.5f) / m_rfRunning.m_fmDeviation) + 0.5f;
} }
} }
else if (m_objRFRunning.m_enmModulation == ATV_AM) else if (m_rfRunning.m_enmModulation == ATV_AM)
{ {
//Amplitude AM //Amplitude AM
magSq = fltI*fltI + fltQ*fltQ; magSq = fltI*fltI + fltQ*fltQ;
@ -334,7 +334,7 @@ void ATVDemod::demod(Complex& c)
fltVal -= m_fltAmpMin; fltVal -= m_fltAmpMin;
fltVal /=m_fltAmpDelta; fltVal /=m_fltAmpDelta;
} }
else if ((m_objRFRunning.m_enmModulation == ATV_USB) || (m_objRFRunning.m_enmModulation == ATV_LSB)) else if ((m_rfRunning.m_enmModulation == ATV_USB) || (m_rfRunning.m_enmModulation == ATV_LSB))
{ {
magSq = fltI*fltI + fltQ*fltQ; magSq = fltI*fltI + fltQ*fltQ;
m_objMagSqAverage.feed(magSq); m_objMagSqAverage.feed(magSq);
@ -349,7 +349,7 @@ void ATVDemod::demod(Complex& c)
float mixI = fltI * bfoValues[0] - fltQ * bfoValues[1]; float mixI = fltI * bfoValues[0] - fltQ * bfoValues[1];
float mixQ = fltI * bfoValues[1] + fltQ * bfoValues[0]; float mixQ = fltI * bfoValues[1] + fltQ * bfoValues[0];
if (m_objRFRunning.m_enmModulation == ATV_USB) { if (m_rfRunning.m_enmModulation == ATV_USB) {
fltVal = (mixI + mixQ); fltVal = (mixI + mixQ);
} else { } else {
fltVal = (mixI - mixQ); fltVal = (mixI - mixQ);
@ -371,7 +371,7 @@ void ATVDemod::demod(Complex& c)
fltVal -= m_fltAmpMin; fltVal -= m_fltAmpMin;
fltVal /=m_fltAmpDelta; fltVal /=m_fltAmpDelta;
} }
else if (m_objRFRunning.m_enmModulation == ATV_FM3) else if (m_rfRunning.m_enmModulation == ATV_FM3)
{ {
float rawDeviation; float rawDeviation;
fltVal = m_objPhaseDiscri.phaseDiscriminatorDelta(c, magSq, rawDeviation) + 0.5f; fltVal = m_objPhaseDiscri.phaseDiscriminatorDelta(c, magSq, rawDeviation) + 0.5f;
@ -387,18 +387,18 @@ void ATVDemod::demod(Complex& c)
fltVal = 0.0f; fltVal = 0.0f;
} }
fltVal = m_objRunning.m_blnInvertVideo ? 1.0f - fltVal : fltVal; fltVal = m_running.m_blnInvertVideo ? 1.0f - fltVal : fltVal;
fltVal = (fltVal < -1.0f) ? -1.0f : (fltVal > 1.0f) ? 1.0f : fltVal; fltVal = (fltVal < -1.0f) ? -1.0f : (fltVal > 1.0f) ? 1.0f : fltVal;
if ((m_objRunning.m_intVideoTabIndex == 1) && (m_objScopeSink != 0)) { // feed scope buffer only if scope is present and visible if ((m_running.m_intVideoTabIndex == 1) && (m_scopeSink != 0)) { // feed scope buffer only if scope is present and visible
m_objScopeSampleBuffer.push_back(Sample(fltVal*32767.0f, 0.0f)); m_scopeSampleBuffer.push_back(Sample(fltVal*32767.0f, 0.0f));
} }
m_fltAmpLineAverage += fltVal; m_fltAmpLineAverage += fltVal;
//********** gray level ********** //********** gray level **********
//-0.3 -> 0.7 //-0.3 -> 0.7
intVal = (int) 255.0*(fltVal - m_objRunning.m_fltVoltLevelSynchroBlack) / fltDivSynchroBlack; intVal = (int) 255.0*(fltVal - m_running.m_fltVoltLevelSynchroBlack) / fltDivSynchroBlack;
//0 -> 255 //0 -> 255
if(intVal<0) if(intVal<0)
@ -412,7 +412,7 @@ void ATVDemod::demod(Complex& c)
//********** process video sample ********** //********** process video sample **********
if (m_objRunning.m_enmATVStandard == ATVStdHSkip) if (m_running.m_enmATVStandard == ATVStdHSkip)
{ {
processHSkip(fltVal, intVal); processHSkip(fltVal, intVal);
} }
@ -438,12 +438,12 @@ bool ATVDemod::handleMessage(const Message& cmd)
if (DownChannelizer::MsgChannelizerNotification::match(cmd)) if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{ {
DownChannelizer::MsgChannelizerNotification& objNotif = (DownChannelizer::MsgChannelizerNotification&) cmd; DownChannelizer::MsgChannelizerNotification& objNotif = (DownChannelizer::MsgChannelizerNotification&) cmd;
m_objConfig.m_intSampleRate = objNotif.getSampleRate(); m_config.m_intSampleRate = objNotif.getSampleRate();
m_objRFConfig.m_intFrequencyOffset = objNotif.getFrequencyOffset(); m_rfConfig.m_intFrequencyOffset = objNotif.getFrequencyOffset();
qDebug() << "ATVDemod::handleMessage: MsgChannelizerNotification:" qDebug() << "ATVDemod::handleMessage: MsgChannelizerNotification:"
<< " m_intSampleRate: " << m_objConfig.m_intSampleRate << " m_intSampleRate: " << m_config.m_intSampleRate
<< " m_intFrequencyOffset: " << m_objRFConfig.m_intFrequencyOffset; << " m_intFrequencyOffset: " << m_rfConfig.m_intFrequencyOffset;
applySettings(); applySettings();
@ -453,17 +453,17 @@ bool ATVDemod::handleMessage(const Message& cmd)
{ {
MsgConfigureATVDemod& objCfg = (MsgConfigureATVDemod&) cmd; MsgConfigureATVDemod& objCfg = (MsgConfigureATVDemod&) cmd;
m_objConfig = objCfg.m_objMsgConfig; m_config = objCfg.m_objMsgConfig;
qDebug() << "ATVDemod::handleMessage: MsgConfigureATVDemod:" qDebug() << "ATVDemod::handleMessage: MsgConfigureATVDemod:"
<< " m_fltVoltLevelSynchroBlack:" << m_objConfig.m_fltVoltLevelSynchroBlack << " m_fltVoltLevelSynchroBlack:" << m_config.m_fltVoltLevelSynchroBlack
<< " m_fltVoltLevelSynchroTop:" << m_objConfig.m_fltVoltLevelSynchroTop << " m_fltVoltLevelSynchroTop:" << m_config.m_fltVoltLevelSynchroTop
<< " m_fltFramePerS:" << m_objConfig.m_fltFramePerS << " m_fltFramePerS:" << m_config.m_fltFramePerS
<< " m_fltLineDurationUs:" << m_objConfig.m_fltLineDuration << " m_fltLineDurationUs:" << m_config.m_fltLineDuration
<< " m_fltRatioOfRowsToDisplay:" << m_objConfig.m_fltRatioOfRowsToDisplay << " m_fltRatioOfRowsToDisplay:" << m_config.m_fltRatioOfRowsToDisplay
<< " m_fltTopDurationUs:" << m_objConfig.m_fltTopDuration << " m_fltTopDurationUs:" << m_config.m_fltTopDuration
<< " m_blnHSync:" << m_objConfig.m_blnHSync << " m_blnHSync:" << m_config.m_blnHSync
<< " m_blnVSync:" << m_objConfig.m_blnVSync; << " m_blnVSync:" << m_config.m_blnVSync;
applySettings(); applySettings();
@ -473,16 +473,16 @@ bool ATVDemod::handleMessage(const Message& cmd)
{ {
MsgConfigureRFATVDemod& objCfg = (MsgConfigureRFATVDemod&) cmd; MsgConfigureRFATVDemod& objCfg = (MsgConfigureRFATVDemod&) cmd;
m_objRFConfig = objCfg.m_objMsgConfig; m_rfConfig = objCfg.m_objMsgConfig;
qDebug() << "ATVDemod::handleMessage: MsgConfigureRFATVDemod:" qDebug() << "ATVDemod::handleMessage: MsgConfigureRFATVDemod:"
<< " m_enmModulation:" << m_objRFConfig.m_enmModulation << " m_enmModulation:" << m_rfConfig.m_enmModulation
<< " m_fltRFBandwidth:" << m_objRFConfig.m_fltRFBandwidth << " m_fltRFBandwidth:" << m_rfConfig.m_fltRFBandwidth
<< " m_fltRFOppBandwidth:" << m_objRFConfig.m_fltRFOppBandwidth << " m_fltRFOppBandwidth:" << m_rfConfig.m_fltRFOppBandwidth
<< " m_blnFFTFiltering:" << m_objRFConfig.m_blnFFTFiltering << " m_blnFFTFiltering:" << m_rfConfig.m_blnFFTFiltering
<< " m_blnDecimatorEnable:" << m_objRFConfig.m_blndecimatorEnable << " m_blnDecimatorEnable:" << m_rfConfig.m_blndecimatorEnable
<< " m_fltBFOFrequency:" << m_objRFConfig.m_fltBFOFrequency << " m_fltBFOFrequency:" << m_rfConfig.m_fltBFOFrequency
<< " m_fmDeviation:" << m_objRFConfig.m_fmDeviation; << " m_fmDeviation:" << m_rfConfig.m_fmDeviation;
applySettings(); applySettings();
@ -490,9 +490,9 @@ bool ATVDemod::handleMessage(const Message& cmd)
} }
else else
{ {
if (m_objScopeSink != 0) if (m_scopeSink != 0)
{ {
return m_objScopeSink->handleMessage(cmd); return m_scopeSink->handleMessage(cmd);
} }
else else
{ {
@ -504,30 +504,30 @@ bool ATVDemod::handleMessage(const Message& cmd)
void ATVDemod::applySettings() void ATVDemod::applySettings()
{ {
if (m_objConfig.m_intSampleRate == 0) if (m_config.m_intSampleRate == 0)
{ {
return; return;
} }
bool forwardSampleRateChange = false; bool forwardSampleRateChange = false;
if((m_objRFConfig.m_intFrequencyOffset != m_objRFRunning.m_intFrequencyOffset) if((m_rfConfig.m_intFrequencyOffset != m_rfRunning.m_intFrequencyOffset)
|| (m_objRFConfig.m_enmModulation != m_objRFRunning.m_enmModulation) || (m_rfConfig.m_enmModulation != m_rfRunning.m_enmModulation)
|| (m_objConfig.m_intSampleRate != m_objRunning.m_intSampleRate)) || (m_config.m_intSampleRate != m_running.m_intSampleRate))
{ {
m_nco.setFreq(-m_objRFConfig.m_intFrequencyOffset, m_objConfig.m_intSampleRate); m_nco.setFreq(-m_rfConfig.m_intFrequencyOffset, m_config.m_intSampleRate);
} }
if ((m_objConfig.m_intSampleRate != m_objRunning.m_intSampleRate) if ((m_config.m_intSampleRate != m_running.m_intSampleRate)
|| (m_objRFConfig.m_fltRFBandwidth != m_objRFRunning.m_fltRFBandwidth) || (m_rfConfig.m_fltRFBandwidth != m_rfRunning.m_fltRFBandwidth)
|| (m_objConfig.m_fltFramePerS != m_objRunning.m_fltFramePerS) || (m_config.m_fltFramePerS != m_running.m_fltFramePerS)
|| (m_objConfig.m_intNumberOfLines != m_objRunning.m_intNumberOfLines)) || (m_config.m_intNumberOfLines != m_running.m_intNumberOfLines))
{ {
m_objSettingsMutex.lock(); m_objSettingsMutex.lock();
int linesPerSecond = m_objConfig.m_intNumberOfLines * m_objConfig.m_fltFramePerS; int linesPerSecond = m_config.m_intNumberOfLines * m_config.m_fltFramePerS;
int maxPoints = m_objConfig.m_intSampleRate / linesPerSecond; int maxPoints = m_config.m_intSampleRate / linesPerSecond;
int i = maxPoints; int i = maxPoints;
for (; i > 0; i--) for (; i > 0; i--)
@ -537,53 +537,53 @@ void ATVDemod::applySettings()
} }
int nbPointsPerRateUnit = i == 0 ? maxPoints : i; int nbPointsPerRateUnit = i == 0 ? maxPoints : i;
m_objConfigPrivate.m_intTVSampleRate = nbPointsPerRateUnit * linesPerSecond; m_configPrivate.m_intTVSampleRate = nbPointsPerRateUnit * linesPerSecond;
if (m_objConfigPrivate.m_intTVSampleRate > 0) if (m_configPrivate.m_intTVSampleRate > 0)
{ {
m_interpolatorDistance = (Real) m_objConfigPrivate.m_intTVSampleRate / (Real) m_objConfig.m_intSampleRate; m_interpolatorDistance = (Real) m_configPrivate.m_intTVSampleRate / (Real) m_config.m_intSampleRate;
} }
else else
{ {
m_objConfigPrivate.m_intTVSampleRate = m_objConfig.m_intSampleRate; m_configPrivate.m_intTVSampleRate = m_config.m_intSampleRate;
m_interpolatorDistance = 1.0f; m_interpolatorDistance = 1.0f;
} }
m_interpolatorDistanceRemain = 0; m_interpolatorDistanceRemain = 0;
m_interpolator.create(24, m_interpolator.create(24,
m_objConfigPrivate.m_intTVSampleRate, m_configPrivate.m_intTVSampleRate,
m_objRFConfig.m_fltRFBandwidth / getRFBandwidthDivisor(m_objRFConfig.m_enmModulation), m_rfConfig.m_fltRFBandwidth / getRFBandwidthDivisor(m_rfConfig.m_enmModulation),
3.0); 3.0);
m_objSettingsMutex.unlock(); m_objSettingsMutex.unlock();
} }
if((m_objConfig.m_fltFramePerS != m_objRunning.m_fltFramePerS) if((m_config.m_fltFramePerS != m_running.m_fltFramePerS)
|| (m_objConfig.m_fltLineDuration != m_objRunning.m_fltLineDuration) || (m_config.m_fltLineDuration != m_running.m_fltLineDuration)
|| (m_objConfig.m_intSampleRate != m_objRunning.m_intSampleRate) || (m_config.m_intSampleRate != m_running.m_intSampleRate)
|| (m_objConfig.m_fltTopDuration != m_objRunning.m_fltTopDuration) || (m_config.m_fltTopDuration != m_running.m_fltTopDuration)
|| (m_objConfig.m_fltRatioOfRowsToDisplay != m_objRunning.m_fltRatioOfRowsToDisplay) || (m_config.m_fltRatioOfRowsToDisplay != m_running.m_fltRatioOfRowsToDisplay)
|| (m_objConfig.m_enmATVStandard != m_objRunning.m_enmATVStandard) || (m_config.m_enmATVStandard != m_running.m_enmATVStandard)
|| (m_objConfig.m_intNumberOfLines != m_objRunning.m_intNumberOfLines)) || (m_config.m_intNumberOfLines != m_running.m_intNumberOfLines))
{ {
m_objSettingsMutex.lock(); m_objSettingsMutex.lock();
m_intNumberOfLines = m_objConfig.m_intNumberOfLines; m_intNumberOfLines = m_config.m_intNumberOfLines;
applyStandard(); applyStandard();
m_objConfigPrivate.m_intNumberSamplePerLine = (int) (m_objConfig.m_fltLineDuration * m_objConfig.m_intSampleRate); m_configPrivate.m_intNumberSamplePerLine = (int) (m_config.m_fltLineDuration * m_config.m_intSampleRate);
m_intNumberSamplePerTop = (int) (m_objConfig.m_fltTopDuration * m_objConfig.m_intSampleRate); m_intNumberSamplePerTop = (int) (m_config.m_fltTopDuration * m_config.m_intSampleRate);
m_objRegisteredATVScreen->setRenderImmediate(!(m_objConfig.m_fltFramePerS > 25.0f)); m_registeredATVScreen->setRenderImmediate(!(m_config.m_fltFramePerS > 25.0f));
m_objRegisteredATVScreen->resizeATVScreen( m_registeredATVScreen->resizeATVScreen(
m_objConfigPrivate.m_intNumberSamplePerLine - m_intNumberSamplePerLineSignals, m_configPrivate.m_intNumberSamplePerLine - m_intNumberSamplePerLineSignals,
m_intNumberOfLines - m_intNumberOfBlackLines); m_intNumberOfLines - m_intNumberOfBlackLines);
qDebug() << "ATVDemod::applySettings:" qDebug() << "ATVDemod::applySettings:"
<< " m_fltLineDuration: " << m_objConfig.m_fltLineDuration << " m_fltLineDuration: " << m_config.m_fltLineDuration
<< " m_fltFramePerS: " << m_objConfig.m_fltFramePerS << " m_fltFramePerS: " << m_config.m_fltFramePerS
<< " m_intNumberOfLines: " << m_intNumberOfLines << " m_intNumberOfLines: " << m_intNumberOfLines
<< " m_intNumberSamplePerLine: " << m_objConfigPrivate.m_intNumberSamplePerLine << " m_intNumberSamplePerLine: " << m_configPrivate.m_intNumberSamplePerLine
<< " m_intNumberOfBlackLines: " << m_intNumberOfBlackLines; << " m_intNumberOfBlackLines: " << m_intNumberOfBlackLines;
m_intImageIndex = 0; m_intImageIndex = 0;
@ -593,56 +593,56 @@ void ATVDemod::applySettings()
m_objSettingsMutex.unlock(); m_objSettingsMutex.unlock();
} }
if ((m_objConfigPrivate.m_intTVSampleRate != m_objRunningPrivate.m_intTVSampleRate) if ((m_configPrivate.m_intTVSampleRate != m_runningPrivate.m_intTVSampleRate)
|| (m_objConfigPrivate.m_intNumberSamplePerLine != m_objRunningPrivate.m_intNumberSamplePerLine) || (m_configPrivate.m_intNumberSamplePerLine != m_runningPrivate.m_intNumberSamplePerLine)
|| (m_objConfig.m_intSampleRate != m_objRunning.m_intSampleRate) || (m_config.m_intSampleRate != m_running.m_intSampleRate)
|| (m_objRFConfig.m_blndecimatorEnable != m_objRFRunning.m_blndecimatorEnable)) || (m_rfConfig.m_blndecimatorEnable != m_rfRunning.m_blndecimatorEnable))
{ {
forwardSampleRateChange = true; forwardSampleRateChange = true;
} }
if ((m_objConfigPrivate.m_intTVSampleRate != m_objRunningPrivate.m_intTVSampleRate) if ((m_configPrivate.m_intTVSampleRate != m_runningPrivate.m_intTVSampleRate)
|| (m_objRFConfig.m_fltRFBandwidth != m_objRFRunning.m_fltRFBandwidth) || (m_rfConfig.m_fltRFBandwidth != m_rfRunning.m_fltRFBandwidth)
|| (m_objRFConfig.m_fltRFOppBandwidth != m_objRFRunning.m_fltRFOppBandwidth)) || (m_rfConfig.m_fltRFOppBandwidth != m_rfRunning.m_fltRFOppBandwidth))
{ {
m_objSettingsMutex.lock(); m_objSettingsMutex.lock();
m_DSBFilter->create_asym_filter(m_objRFConfig.m_fltRFOppBandwidth / m_objConfigPrivate.m_intTVSampleRate, m_DSBFilter->create_asym_filter(m_rfConfig.m_fltRFOppBandwidth / m_configPrivate.m_intTVSampleRate,
m_objRFConfig.m_fltRFBandwidth / m_objConfigPrivate.m_intTVSampleRate); m_rfConfig.m_fltRFBandwidth / m_configPrivate.m_intTVSampleRate);
memset(m_DSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen)); memset(m_DSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen));
m_DSBFilterBufferIndex = 0; m_DSBFilterBufferIndex = 0;
m_objSettingsMutex.unlock(); m_objSettingsMutex.unlock();
} }
if ((m_objConfigPrivate.m_intTVSampleRate != m_objRunningPrivate.m_intTVSampleRate) if ((m_configPrivate.m_intTVSampleRate != m_runningPrivate.m_intTVSampleRate)
|| (m_objRFConfig.m_fltBFOFrequency != m_objRFRunning.m_fltBFOFrequency)) || (m_rfConfig.m_fltBFOFrequency != m_rfRunning.m_fltBFOFrequency))
{ {
m_bfoPLL.configure(m_objRFConfig.m_fltBFOFrequency / m_objConfigPrivate.m_intTVSampleRate, m_bfoPLL.configure(m_rfConfig.m_fltBFOFrequency / m_configPrivate.m_intTVSampleRate,
100.0 / m_objConfigPrivate.m_intTVSampleRate, 100.0 / m_configPrivate.m_intTVSampleRate,
0.01); 0.01);
m_bfoFilter.setFrequencies(m_objRFConfig.m_fltBFOFrequency, m_objConfigPrivate.m_intTVSampleRate); m_bfoFilter.setFrequencies(m_rfConfig.m_fltBFOFrequency, m_configPrivate.m_intTVSampleRate);
} }
if (m_objRFConfig.m_fmDeviation != m_objRFRunning.m_fmDeviation) if (m_rfConfig.m_fmDeviation != m_rfRunning.m_fmDeviation)
{ {
m_objPhaseDiscri.setFMScaling(1.0f / m_objRFConfig.m_fmDeviation); m_objPhaseDiscri.setFMScaling(1.0f / m_rfConfig.m_fmDeviation);
} }
m_objRunning = m_objConfig; m_running = m_config;
m_objRFRunning = m_objRFConfig; m_rfRunning = m_rfConfig;
m_objRunningPrivate = m_objConfigPrivate; m_runningPrivate = m_configPrivate;
if (forwardSampleRateChange) if (forwardSampleRateChange)
{ {
int sampleRate = m_objRFRunning.m_blndecimatorEnable ? m_objRunningPrivate.m_intTVSampleRate : m_objRunning.m_intSampleRate; int sampleRate = m_rfRunning.m_blndecimatorEnable ? m_runningPrivate.m_intTVSampleRate : m_running.m_intSampleRate;
MsgReportEffectiveSampleRate *report; MsgReportEffectiveSampleRate *report;
report = MsgReportEffectiveSampleRate::create(sampleRate, m_objRunningPrivate.m_intNumberSamplePerLine); report = MsgReportEffectiveSampleRate::create(sampleRate, m_runningPrivate.m_intNumberSamplePerLine);
getOutputMessageQueue()->push(report); getMessageQueueToGUI()->push(report);
} }
} }
void ATVDemod::applyStandard() void ATVDemod::applyStandard()
{ {
switch(m_objConfig.m_enmATVStandard) switch(m_config.m_enmATVStandard)
{ {
case ATVStdHSkip: case ATVStdHSkip:
// what is left in a line for the image // what is left in a line for the image
@ -689,23 +689,23 @@ void ATVDemod::applyStandard()
} }
// for now all standards apply this // for now all standards apply this
m_intNumberSamplePerLineSignals = (int) ((12.0f/64.0f)*m_objConfig.m_fltLineDuration * m_objConfig.m_intSampleRate); // 12.0 = 7.3 + 4.7 m_intNumberSamplePerLineSignals = (int) ((12.0f/64.0f)*m_config.m_fltLineDuration * m_config.m_intSampleRate); // 12.0 = 7.3 + 4.7
m_intNumberSaplesPerHSync = (int) ((9.6f/64.0f)*m_objConfig.m_fltLineDuration * m_objConfig.m_intSampleRate); // 9.4 = 4.7 + 4.7 m_intNumberSaplesPerHSync = (int) ((9.6f/64.0f)*m_config.m_fltLineDuration * m_config.m_intSampleRate); // 9.4 = 4.7 + 4.7
} }
int ATVDemod::getSampleRate() int ATVDemod::getSampleRate()
{ {
return m_objRunning.m_intSampleRate; return m_running.m_intSampleRate;
} }
int ATVDemod::getEffectiveSampleRate() int ATVDemod::getEffectiveSampleRate()
{ {
return m_objRFRunning.m_blndecimatorEnable ? m_objRunningPrivate.m_intTVSampleRate : m_objRunning.m_intSampleRate; return m_rfRunning.m_blndecimatorEnable ? m_runningPrivate.m_intTVSampleRate : m_running.m_intSampleRate;
} }
bool ATVDemod::getBFOLocked() bool ATVDemod::getBFOLocked()
{ {
if ((m_objRFRunning.m_enmModulation == ATV_USB) || (m_objRFRunning.m_enmModulation == ATV_LSB)) if ((m_rfRunning.m_enmModulation == ATV_USB) || (m_rfRunning.m_enmModulation == ATV_LSB))
{ {
return m_bfoPLL.locked(); return m_bfoPLL.locked();
} }

View File

@ -38,6 +38,7 @@
#include "util/message.h" #include "util/message.h"
#include "atvscreen.h" #include "atvscreen.h"
class DeviceSourceAPI;
class ATVDemod : public BasebandSampleSink class ATVDemod : public BasebandSampleSink
{ {
@ -146,8 +147,9 @@ public:
{ } { }
}; };
ATVDemod(BasebandSampleSink* objScopeSink); ATVDemod(DeviceSourceAPI *deviceAPI);
~ATVDemod(); ~ATVDemod();
void setScopeSink(BasebandSampleSink* scopeSink) { m_scopeSink = scopeSink; }
void configure(MessageQueue* objMessageQueue, void configure(MessageQueue* objMessageQueue,
float fltLineDurationUs, float fltLineDurationUs,
@ -339,13 +341,15 @@ private:
bool m_start; bool m_start;
}; };
DeviceSourceAPI* m_deviceAPI;
//*************** SCOPE *************** //*************** SCOPE ***************
BasebandSampleSink* m_objScopeSink; BasebandSampleSink* m_scopeSink;
SampleVector m_objScopeSampleBuffer; SampleVector m_scopeSampleBuffer;
//*************** ATV PARAMETERS *************** //*************** ATV PARAMETERS ***************
ATVScreen * m_objRegisteredATVScreen; ATVScreen * m_registeredATVScreen;
//int m_intNumberSamplePerLine; //int m_intNumberSamplePerLine;
int m_intNumberSamplePerTop; int m_intNumberSamplePerTop;
@ -411,14 +415,14 @@ private:
//QElapsedTimer m_objTimer; //QElapsedTimer m_objTimer;
ATVConfig m_objRunning; ATVConfig m_running;
ATVConfig m_objConfig; ATVConfig m_config;
ATVRFConfig m_objRFRunning; ATVRFConfig m_rfRunning;
ATVRFConfig m_objRFConfig; ATVRFConfig m_rfConfig;
ATVConfigPrivate m_objRunningPrivate; ATVConfigPrivate m_runningPrivate;
ATVConfigPrivate m_objConfigPrivate; ATVConfigPrivate m_configPrivate;
QMutex m_objSettingsMutex; QMutex m_objSettingsMutex;
@ -429,17 +433,17 @@ private:
inline void processHSkip(float& fltVal, int& intVal) inline void processHSkip(float& fltVal, int& intVal)
{ {
m_objRegisteredATVScreen->setDataColor(m_intColIndex - m_intNumberSaplesPerHSync + m_intNumberSamplePerTop, intVal, intVal, intVal); m_registeredATVScreen->setDataColor(m_intColIndex - m_intNumberSaplesPerHSync + m_intNumberSamplePerTop, intVal, intVal, intVal);
// Horizontal Synchro detection // Horizontal Synchro detection
// Floor Detection 0 // Floor Detection 0
if (fltVal < m_objRunning.m_fltVoltLevelSynchroTop) if (fltVal < m_running.m_fltVoltLevelSynchroTop)
{ {
m_intSynchroPoints++; m_intSynchroPoints++;
} }
// Black detection 0.3 // Black detection 0.3
else if (fltVal > m_objRunning.m_fltVoltLevelSynchroBlack) else if (fltVal > m_running.m_fltVoltLevelSynchroBlack)
{ {
m_intSynchroPoints = 0; m_intSynchroPoints = 0;
} }
@ -450,11 +454,11 @@ private:
if (m_blnSynchroDetected) if (m_blnSynchroDetected)
{ {
if (m_intSampleIndex >= (3 * m_objRunningPrivate.m_intNumberSamplePerLine)/2) // first after skip if (m_intSampleIndex >= (3 * m_runningPrivate.m_intNumberSamplePerLine)/2) // first after skip
{ {
//qDebug("VSync: %d %d %d", m_intColIndex, m_intSampleIndex, m_intLineIndex); //qDebug("VSync: %d %d %d", m_intColIndex, m_intSampleIndex, m_intLineIndex);
m_intAvgColIndex = m_intColIndex; m_intAvgColIndex = m_intColIndex;
m_objRegisteredATVScreen->renderImage(0); m_registeredATVScreen->renderImage(0);
m_intImageIndex++; m_intImageIndex++;
m_intLineIndex = 0; m_intLineIndex = 0;
@ -468,25 +472,25 @@ private:
m_intSampleIndex++; m_intSampleIndex++;
} }
if (m_intColIndex < m_objRunningPrivate.m_intNumberSamplePerLine + m_intNumberSamplePerTop - 1) if (m_intColIndex < m_runningPrivate.m_intNumberSamplePerLine + m_intNumberSamplePerTop - 1)
{ {
m_intColIndex++; m_intColIndex++;
} }
else else
{ {
if (m_objRunning.m_blnHSync && (m_intLineIndex == 0)) if (m_running.m_blnHSync && (m_intLineIndex == 0))
{ {
//qDebug("HCorr: %d", m_intAvgColIndex); //qDebug("HCorr: %d", m_intAvgColIndex);
m_intColIndex = m_intNumberSamplePerTop + (m_objRunningPrivate.m_intNumberSamplePerLine - m_intAvgColIndex)/2; // amortizing factor 1/2 m_intColIndex = m_intNumberSamplePerTop + (m_runningPrivate.m_intNumberSamplePerLine - m_intAvgColIndex)/2; // amortizing factor 1/2
} }
else else
{ {
m_intColIndex = m_intNumberSamplePerTop; m_intColIndex = m_intNumberSamplePerTop;
} }
if ((m_objRFRunning.m_enmModulation == ATV_AM) if ((m_rfRunning.m_enmModulation == ATV_AM)
|| (m_objRFRunning.m_enmModulation == ATV_USB) || (m_rfRunning.m_enmModulation == ATV_USB)
|| (m_objRFRunning.m_enmModulation == ATV_LSB)) || (m_rfRunning.m_enmModulation == ATV_LSB))
{ {
m_fltAmpMin = m_fltEffMin; m_fltAmpMin = m_fltEffMin;
m_fltAmpMax = m_fltEffMax; m_fltAmpMax = m_fltEffMax;
@ -502,7 +506,7 @@ private:
m_fltEffMax = -2000000.0f; m_fltEffMax = -2000000.0f;
} }
m_objRegisteredATVScreen->selectRow(m_intRowIndex); m_registeredATVScreen->selectRow(m_intRowIndex);
m_intLineIndex++; m_intLineIndex++;
m_intRowIndex++; m_intRowIndex++;
} }
@ -510,18 +514,18 @@ private:
inline void processClassic(float& fltVal, int& intVal) inline void processClassic(float& fltVal, int& intVal)
{ {
int intSynchroTimeSamples= (3 * m_objRunningPrivate.m_intNumberSamplePerLine)/4; int intSynchroTimeSamples= (3 * m_runningPrivate.m_intNumberSamplePerLine)/4;
float fltSynchroTrameLevel = 0.5f*((float)intSynchroTimeSamples) * m_objRunning.m_fltVoltLevelSynchroBlack; float fltSynchroTrameLevel = 0.5f*((float)intSynchroTimeSamples) * m_running.m_fltVoltLevelSynchroBlack;
// Horizontal Synchro detection // Horizontal Synchro detection
// Floor Detection 0 // Floor Detection 0
if (fltVal < m_objRunning.m_fltVoltLevelSynchroTop) if (fltVal < m_running.m_fltVoltLevelSynchroTop)
{ {
m_intSynchroPoints++; m_intSynchroPoints++;
} }
// Black detection 0.3 // Black detection 0.3
else if (fltVal > m_objRunning.m_fltVoltLevelSynchroBlack) else if (fltVal > m_running.m_fltVoltLevelSynchroBlack)
{ {
m_intSynchroPoints = 0; m_intSynchroPoints = 0;
} }
@ -534,7 +538,7 @@ private:
if (m_blnSynchroDetected) if (m_blnSynchroDetected)
{ {
m_intAvgColIndex = m_intSampleIndex - m_intColIndex - (m_intColIndex < m_objRunningPrivate.m_intNumberSamplePerLine/2 ? 150 : 0); m_intAvgColIndex = m_intSampleIndex - m_intColIndex - (m_intColIndex < m_runningPrivate.m_intNumberSamplePerLine/2 ? 150 : 0);
//qDebug("HSync: %d %d %d", m_intSampleIndex, m_intColIndex, m_intAvgColIndex); //qDebug("HSync: %d %d %d", m_intSampleIndex, m_intColIndex, m_intAvgColIndex);
m_intSampleIndex = 0; m_intSampleIndex = 0;
} }
@ -543,14 +547,14 @@ private:
m_intSampleIndex++; m_intSampleIndex++;
} }
if (!m_objRunning.m_blnHSync && (m_intColIndex >= m_objRunningPrivate.m_intNumberSamplePerLine)) // H Sync not active if (!m_running.m_blnHSync && (m_intColIndex >= m_runningPrivate.m_intNumberSamplePerLine)) // H Sync not active
{ {
m_intColIndex = 0; m_intColIndex = 0;
blnNewLine = true; blnNewLine = true;
} }
else if (m_intColIndex >= m_objRunningPrivate.m_intNumberSamplePerLine + m_intNumberSamplePerTop) // No valid H sync else if (m_intColIndex >= m_runningPrivate.m_intNumberSamplePerLine + m_intNumberSamplePerTop) // No valid H sync
{ {
if (m_objRunning.m_blnHSync && (m_intLineIndex == 0)) if (m_running.m_blnHSync && (m_intLineIndex == 0))
{ {
//qDebug("HSync: %d %d", m_intColIndex, m_intAvgColIndex); //qDebug("HSync: %d %d", m_intColIndex, m_intAvgColIndex);
m_intColIndex = m_intNumberSamplePerTop + m_intAvgColIndex/4; // amortizing 1/4 m_intColIndex = m_intNumberSamplePerTop + m_intAvgColIndex/4; // amortizing 1/4
@ -565,9 +569,9 @@ private:
if (blnNewLine) if (blnNewLine)
{ {
if ((m_objRFRunning.m_enmModulation == ATV_AM) if ((m_rfRunning.m_enmModulation == ATV_AM)
|| (m_objRFRunning.m_enmModulation == ATV_USB) || (m_rfRunning.m_enmModulation == ATV_USB)
|| (m_objRFRunning.m_enmModulation == ATV_LSB)) || (m_rfRunning.m_enmModulation == ATV_LSB))
{ {
m_fltAmpMin = m_fltEffMin; m_fltAmpMin = m_fltEffMin;
m_fltAmpMax = m_fltEffMax; m_fltAmpMax = m_fltEffMax;
@ -590,7 +594,7 @@ private:
if (m_intRowIndex < m_intNumberOfLines) if (m_intRowIndex < m_intNumberOfLines)
{ {
m_objRegisteredATVScreen->selectRow(m_intRowIndex - m_intNumberOfSyncLines); m_registeredATVScreen->selectRow(m_intRowIndex - m_intNumberOfSyncLines);
} }
m_intLineIndex++; m_intLineIndex++;
@ -599,12 +603,12 @@ private:
// Filling pixels // Filling pixels
// +4 is to compensate shift due to hsync amortizing factor of 1/4 // +4 is to compensate shift due to hsync amortizing factor of 1/4
m_objRegisteredATVScreen->setDataColor(m_intColIndex - m_intNumberSaplesPerHSync + m_intNumberSamplePerTop + 4, intVal, intVal, intVal); m_registeredATVScreen->setDataColor(m_intColIndex - m_intNumberSaplesPerHSync + m_intNumberSamplePerTop + 4, intVal, intVal, intVal);
m_intColIndex++; m_intColIndex++;
// Vertical sync and image rendering // Vertical sync and image rendering
if ((m_objRunning.m_blnVSync) && (m_intLineIndex < m_intNumberOfLines)) // VSync activated and lines in range if ((m_running.m_blnVSync) && (m_intLineIndex < m_intNumberOfLines)) // VSync activated and lines in range
{ {
if (m_intColIndex >= intSynchroTimeSamples) if (m_intColIndex >= intSynchroTimeSamples)
{ {
@ -618,7 +622,7 @@ private:
if ((m_intLineIndex % 2 == 0) || !m_interleaved) // even => odd image if ((m_intLineIndex % 2 == 0) || !m_interleaved) // even => odd image
{ {
m_objRegisteredATVScreen->renderImage(0); m_registeredATVScreen->renderImage(0);
m_intRowIndex = 1; m_intRowIndex = 1;
} }
else else
@ -626,7 +630,7 @@ private:
m_intRowIndex = 0; m_intRowIndex = 0;
} }
m_objRegisteredATVScreen->selectRow(m_intRowIndex - m_intNumberOfSyncLines); m_registeredATVScreen->selectRow(m_intRowIndex - m_intNumberOfSyncLines);
m_intLineIndex = 0; m_intLineIndex = 0;
m_intImageIndex++; m_intImageIndex++;
} }
@ -643,9 +647,9 @@ private:
{ {
if (m_intImageIndex % 2 == 1) // odd image if (m_intImageIndex % 2 == 1) // odd image
{ {
m_objRegisteredATVScreen->renderImage(0); m_registeredATVScreen->renderImage(0);
if (m_objRFRunning.m_enmModulation == ATV_AM) if (m_rfRunning.m_enmModulation == ATV_AM)
{ {
m_fltAmpMin = m_fltEffMin; m_fltAmpMin = m_fltEffMin;
m_fltAmpMax = m_fltEffMax; m_fltAmpMax = m_fltEffMax;
@ -668,7 +672,7 @@ private:
m_intRowIndex = 0; m_intRowIndex = 0;
} }
m_objRegisteredATVScreen->selectRow(m_intRowIndex - m_intNumberOfSyncLines); m_registeredATVScreen->selectRow(m_intRowIndex - m_intNumberOfSyncLines);
m_intLineIndex = 0; m_intLineIndex = 0;
m_intImageIndex++; m_intImageIndex++;
} }

View File

@ -61,12 +61,12 @@ QString ATVDemodGUI::getName() const
qint64 ATVDemodGUI::getCenterFrequency() const qint64 ATVDemodGUI::getCenterFrequency() const
{ {
return m_objChannelMarker.getCenterFrequency(); return m_channelMarker.getCenterFrequency();
} }
void ATVDemodGUI::setCenterFrequency(qint64 intCenterFrequency) void ATVDemodGUI::setCenterFrequency(qint64 intCenterFrequency)
{ {
m_objChannelMarker.setCenterFrequency(intCenterFrequency); m_channelMarker.setCenterFrequency(intCenterFrequency);
applySettings(); applySettings();
} }
@ -105,8 +105,8 @@ QByteArray ATVDemodGUI::serialize() const
{ {
SimpleSerializer s(1); SimpleSerializer s(1);
s.writeS32(1, m_objChannelMarker.getCenterFrequency()); s.writeS32(1, m_channelMarker.getCenterFrequency());
s.writeU32(2, m_objChannelMarker.getColor().rgb()); s.writeU32(2, m_channelMarker.getColor().rgb());
s.writeS32(3, ui->synchLevel->value()); s.writeS32(3, ui->synchLevel->value());
s.writeS32(4, ui->blackLevel->value()); s.writeS32(4, ui->blackLevel->value());
s.writeS32(5, ui->lineTime->value()); s.writeS32(5, ui->lineTime->value());
@ -144,10 +144,10 @@ bool ATVDemodGUI::deserialize(const QByteArray& arrData)
bool booltmp; bool booltmp;
blockApplySettings(true); blockApplySettings(true);
m_objChannelMarker.blockSignals(true); m_channelMarker.blockSignals(true);
d.readS32(1, &tmp, 0); d.readS32(1, &tmp, 0);
m_objChannelMarker.setCenterFrequency(tmp); m_channelMarker.setCenterFrequency(tmp);
// if (d.readU32(2, &u32tmp)) { // if (d.readU32(2, &u32tmp)) {
// m_objChannelMarker.setColor(u32tmp); // m_objChannelMarker.setColor(u32tmp);
@ -189,7 +189,7 @@ bool ATVDemodGUI::deserialize(const QByteArray& arrData)
ui->standard->setCurrentIndex(tmp); ui->standard->setCurrentIndex(tmp);
blockApplySettings(false); blockApplySettings(false);
m_objChannelMarker.blockSignals(false); m_channelMarker.blockSignals(false);
lineTimeUpdate(); lineTimeUpdate();
topTimeUpdate(); topTimeUpdate();
@ -211,7 +211,7 @@ bool ATVDemodGUI::handleMessage(const Message& objMessage)
int nbPointsPerLine = ((ATVDemod::MsgReportEffectiveSampleRate&)objMessage).getNbPointsPerLine(); int nbPointsPerLine = ((ATVDemod::MsgReportEffectiveSampleRate&)objMessage).getNbPointsPerLine();
ui->channelSampleRateText->setText(tr("%1k").arg(sampleRate/1000.0f, 0, 'f', 2)); ui->channelSampleRateText->setText(tr("%1k").arg(sampleRate/1000.0f, 0, 'f', 2));
ui->nbPointsPerLineText->setText(tr("%1p").arg(nbPointsPerLine)); ui->nbPointsPerLineText->setText(tr("%1p").arg(nbPointsPerLine));
m_objScopeVis->setSampleRate(sampleRate); m_scopeVis->setSampleRate(sampleRate);
setRFFiltersSlidersRange(sampleRate); setRFFiltersSlidersRange(sampleRate);
lineTimeUpdate(); lineTimeUpdate();
topTimeUpdate(); topTimeUpdate();
@ -242,7 +242,7 @@ void ATVDemodGUI::handleSourceMessages()
{ {
Message* message; Message* message;
while ((message = m_objATVDemod->getOutputMessageQueue()->pop()) != 0) while ((message = getInputMessageQueue()->pop()) != 0)
{ {
if (handleMessage(*message)) if (handleMessage(*message))
{ {
@ -261,7 +261,7 @@ void ATVDemodGUI::onMenuDoubleClicked()
{ {
m_blnBasicSettingsShown = true; m_blnBasicSettingsShown = true;
BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget( BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(
&m_objChannelMarker, this); &m_channelMarker, this);
bcsw->show(); bcsw->show();
} }
} }
@ -270,9 +270,9 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI,
QWidget* objParent) : QWidget* objParent) :
RollupWidget(objParent), RollupWidget(objParent),
ui(new Ui::ATVDemodGUI), ui(new Ui::ATVDemodGUI),
m_objPluginAPI(objPluginAPI), m_pluginAPI(objPluginAPI),
m_objDeviceAPI(objDeviceAPI), m_deviceAPI(objDeviceAPI),
m_objChannelMarker(this), m_channelMarker(this),
m_blnBasicSettingsShown(false), m_blnBasicSettingsShown(false),
m_blnDoApplySettings(true), m_blnDoApplySettings(true),
m_objMagSqAverage(40, 0), m_objMagSqAverage(40, 0),
@ -283,42 +283,44 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI,
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked()));
m_objScopeVis = new ScopeVisNG(ui->glScope); m_scopeVis = new ScopeVisNG(ui->glScope);
m_objATVDemod = new ATVDemod(m_objScopeVis); m_atvDemod = new ATVDemod(m_deviceAPI);
m_objATVDemod->setATVScreen(ui->screenTV); m_atvDemod->setScopeSink(m_scopeVis);
m_atvDemod->setMessageQueueToGUI(getInputMessageQueue());
m_atvDemod->setATVScreen(ui->screenTV);
m_objChannelizer = new DownChannelizer(m_objATVDemod); m_channelizer = new DownChannelizer(m_atvDemod);
m_objThreadedChannelizer = new ThreadedBasebandSampleSink(m_objChannelizer, this); m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
m_objDeviceAPI->addThreadedSink(m_objThreadedChannelizer); m_deviceAPI->addThreadedSink(m_threadedChannelizer);
ui->glScope->connectTimer(m_objPluginAPI->getMainWindow()->getMasterTimer()); ui->glScope->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer());
connect(&m_objPluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
connect(m_objChannelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged()));
//m_objPluginAPI->addThreadedSink(m_objThreadedChannelizer); //m_objPluginAPI->addThreadedSink(m_objThreadedChannelizer);
m_objChannelMarker.setColor(Qt::white); m_channelMarker.setColor(Qt::white);
m_objChannelMarker.setMovable(false); m_channelMarker.setMovable(false);
m_objChannelMarker.setBandwidth(6000000); m_channelMarker.setBandwidth(6000000);
m_objChannelMarker.setCenterFrequency(0); m_channelMarker.setCenterFrequency(0);
m_objChannelMarker.setVisible(true); m_channelMarker.setVisible(true);
setTitleColor(m_objChannelMarker.getColor()); setTitleColor(m_channelMarker.getColor());
connect(&m_objChannelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
m_objDeviceAPI->registerChannelInstance(m_strChannelID, this); m_deviceAPI->registerChannelInstance(m_strChannelID, this);
m_objDeviceAPI->addChannelMarker(&m_objChannelMarker); m_deviceAPI->addChannelMarker(&m_channelMarker);
m_objDeviceAPI->addRollupWidget(this); m_deviceAPI->addRollupWidget(this);
//ui->screenTV->connectTimer(m_objPluginAPI->getMainWindow()->getMasterTimer()); //ui->screenTV->connectTimer(m_objPluginAPI->getMainWindow()->getMasterTimer());
m_objMagSqAverage.resize(4, 1.0); m_objMagSqAverage.resize(4, 1.0);
ui->scopeGUI->setBuddies(m_objScopeVis->getInputMessageQueue(), m_objScopeVis, ui->glScope); ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
resetToDefaults(); // does applySettings() resetToDefaults(); // does applySettings()
@ -337,7 +339,7 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI,
ui->scopeGUI->changeTrigger(0, triggerData); ui->scopeGUI->changeTrigger(0, triggerData);
ui->scopeGUI->focusOnTrigger(0); // re-focus to take changes into account in the GUI ui->scopeGUI->focusOnTrigger(0); // re-focus to take changes into account in the GUI
connect(m_objATVDemod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
QChar delta = QChar(0x94, 0x03); QChar delta = QChar(0x94, 0x03);
ui->fmDeviationLabel->setText(delta); ui->fmDeviationLabel->setText(delta);
@ -345,12 +347,12 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI,
ATVDemodGUI::~ATVDemodGUI() ATVDemodGUI::~ATVDemodGUI()
{ {
m_objDeviceAPI->removeChannelInstance(this); m_deviceAPI->removeChannelInstance(this);
m_objDeviceAPI->removeThreadedSink(m_objThreadedChannelizer); m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_objThreadedChannelizer; delete m_threadedChannelizer;
delete m_objChannelizer; delete m_channelizer;
delete m_objATVDemod; delete m_atvDemod;
delete m_objScopeVis; delete m_scopeVis;
delete ui; delete ui;
} }
@ -363,13 +365,13 @@ void ATVDemodGUI::applySettings()
{ {
if (m_blnDoApplySettings) if (m_blnDoApplySettings)
{ {
ui->deltaFrequency->setValue(m_objChannelMarker.getCenterFrequency()); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_objChannelizer->configure(m_objChannelizer->getInputMessageQueue(), m_channelizer->configure(m_channelizer->getInputMessageQueue(),
m_objChannelizer->getInputSampleRate(), // always use maximum available bandwidth m_channelizer->getInputSampleRate(), // always use maximum available bandwidth
m_objChannelMarker.getCenterFrequency()); m_channelMarker.getCenterFrequency());
m_objATVDemod->configure(m_objATVDemod->getInputMessageQueue(), m_atvDemod->configure(m_atvDemod->getInputMessageQueue(),
getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) + ui->lineTime->value() * m_fltLineTimeMultiplier, getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) + ui->lineTime->value() * m_fltLineTimeMultiplier,
getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) * (4.7f / 64.0f) + ui->topTime->value() * m_fltTopTimeMultiplier, getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) * (4.7f / 64.0f) + ui->topTime->value() * m_fltTopTimeMultiplier,
getFps(ui->fps->currentIndex()), getFps(ui->fps->currentIndex()),
@ -384,8 +386,8 @@ void ATVDemodGUI::applySettings()
ui->screenTabWidget->currentIndex()); ui->screenTabWidget->currentIndex());
qDebug() << "ATVDemodGUI::applySettings:" qDebug() << "ATVDemodGUI::applySettings:"
<< " m_objChannelizer.inputSampleRate: " << m_objChannelizer->getInputSampleRate() << " m_objChannelizer.inputSampleRate: " << m_channelizer->getInputSampleRate()
<< " m_objATVDemod.sampleRate: " << m_objATVDemod->getSampleRate(); << " m_objATVDemod.sampleRate: " << m_atvDemod->getSampleRate();
} }
} }
@ -393,7 +395,7 @@ void ATVDemodGUI::applyRFSettings()
{ {
if (m_blnDoApplySettings) if (m_blnDoApplySettings)
{ {
m_objATVDemod->configureRF(m_objATVDemod->getInputMessageQueue(), m_atvDemod->configureRF(m_atvDemod->getInputMessageQueue(),
(ATVDemod::ATVModulation) ui->modulation->currentIndex(), (ATVDemod::ATVModulation) ui->modulation->currentIndex(),
ui->rfBW->value() * m_rfSliderDivisor * 1.0f, ui->rfBW->value() * m_rfSliderDivisor * 1.0f,
ui->rfOppBW->value() * m_rfSliderDivisor * 1.0f, ui->rfOppBW->value() * m_rfSliderDivisor * 1.0f,
@ -410,26 +412,26 @@ void ATVDemodGUI::setChannelMarkerBandwidth()
if (ui->rfFiltering->isChecked()) // FFT filter if (ui->rfFiltering->isChecked()) // FFT filter
{ {
m_objChannelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor); m_channelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor);
m_objChannelMarker.setOppositeBandwidth(ui->rfOppBW->value()*m_rfSliderDivisor); m_channelMarker.setOppositeBandwidth(ui->rfOppBW->value()*m_rfSliderDivisor);
if (ui->modulation->currentIndex() == (int) ATVDemod::ATV_LSB) { if (ui->modulation->currentIndex() == (int) ATVDemod::ATV_LSB) {
m_objChannelMarker.setSidebands(ChannelMarker::vlsb); m_channelMarker.setSidebands(ChannelMarker::vlsb);
} else if (ui->modulation->currentIndex() == (int) ATVDemod::ATV_USB) { } else if (ui->modulation->currentIndex() == (int) ATVDemod::ATV_USB) {
m_objChannelMarker.setSidebands(ChannelMarker::vusb); m_channelMarker.setSidebands(ChannelMarker::vusb);
} else { } else {
m_objChannelMarker.setSidebands(ChannelMarker::vusb); m_channelMarker.setSidebands(ChannelMarker::vusb);
} }
} }
else else
{ {
if (ui->decimatorEnable->isChecked()) { if (ui->decimatorEnable->isChecked()) {
m_objChannelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor); m_channelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor);
} else { } else {
m_objChannelMarker.setBandwidth(m_objChannelizer->getInputSampleRate()); m_channelMarker.setBandwidth(m_channelizer->getInputSampleRate());
} }
m_objChannelMarker.setSidebands(ChannelMarker::dsb); m_channelMarker.setSidebands(ChannelMarker::dsb);
} }
m_blnDoApplySettings = true; m_blnDoApplySettings = true;
@ -463,14 +465,14 @@ void ATVDemodGUI::setRFFiltersSlidersRange(int sampleRate)
void ATVDemodGUI::leaveEvent(QEvent*) void ATVDemodGUI::leaveEvent(QEvent*)
{ {
blockApplySettings(true); blockApplySettings(true);
m_objChannelMarker.setHighlighted(false); m_channelMarker.setHighlighted(false);
blockApplySettings(false); blockApplySettings(false);
} }
void ATVDemodGUI::enterEvent(QEvent*) void ATVDemodGUI::enterEvent(QEvent*)
{ {
blockApplySettings(true); blockApplySettings(true);
m_objChannelMarker.setHighlighted(true); m_channelMarker.setHighlighted(true);
blockApplySettings(false); blockApplySettings(false);
} }
@ -482,13 +484,13 @@ void ATVDemodGUI::tick()
} }
else else
{ {
if (m_objATVDemod) if (m_atvDemod)
{ {
m_objMagSqAverage.feed(m_objATVDemod->getMagSq()); m_objMagSqAverage.feed(m_atvDemod->getMagSq());
double magSqDB = CalcDb::dbPower(m_objMagSqAverage.average() / (1<<30)); double magSqDB = CalcDb::dbPower(m_objMagSqAverage.average() / (1<<30));
ui->channePowerText->setText(tr("%1 dB").arg(magSqDB, 0, 'f', 1)); ui->channePowerText->setText(tr("%1 dB").arg(magSqDB, 0, 'f', 1));
if (m_objATVDemod->getBFOLocked()) { if (m_atvDemod->getBFOLocked()) {
ui->bfoLockedLabel->setStyleSheet("QLabel { background-color : green; }"); ui->bfoLockedLabel->setStyleSheet("QLabel { background-color : green; }");
} else { } else {
ui->bfoLockedLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }"); ui->bfoLockedLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
@ -573,7 +575,7 @@ void ATVDemodGUI::on_reset_clicked(bool checked __attribute__((unused)))
void ATVDemodGUI::on_modulation_currentIndexChanged(int index __attribute__((unused))) void ATVDemodGUI::on_modulation_currentIndexChanged(int index __attribute__((unused)))
{ {
setRFFiltersSlidersRange(m_objATVDemod->getEffectiveSampleRate()); setRFFiltersSlidersRange(m_atvDemod->getEffectiveSampleRate());
setChannelMarkerBandwidth(); setChannelMarkerBandwidth();
applyRFSettings(); applyRFSettings();
} }
@ -594,7 +596,7 @@ void ATVDemodGUI::on_rfOppBW_valueChanged(int value)
void ATVDemodGUI::on_rfFiltering_toggled(bool checked __attribute__((unused))) void ATVDemodGUI::on_rfFiltering_toggled(bool checked __attribute__((unused)))
{ {
setRFFiltersSlidersRange(m_objATVDemod->getEffectiveSampleRate()); setRFFiltersSlidersRange(m_atvDemod->getEffectiveSampleRate());
setChannelMarkerBandwidth(); setChannelMarkerBandwidth();
applyRFSettings(); applyRFSettings();
} }
@ -607,7 +609,7 @@ void ATVDemodGUI::on_decimatorEnable_toggled(bool checked __attribute__((unused)
void ATVDemodGUI::on_deltaFrequency_changed(qint64 value) void ATVDemodGUI::on_deltaFrequency_changed(qint64 value)
{ {
m_objChannelMarker.setCenterFrequency(value); m_channelMarker.setCenterFrequency(value);
} }
void ATVDemodGUI::on_bfo_valueChanged(int value) void ATVDemodGUI::on_bfo_valueChanged(int value)
@ -632,10 +634,10 @@ void ATVDemodGUI::lineTimeUpdate()
float nominalLineTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()); float nominalLineTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex());
int lineTimeScaleFactor = (int) std::log10(nominalLineTime); int lineTimeScaleFactor = (int) std::log10(nominalLineTime);
if (m_objATVDemod->getEffectiveSampleRate() == 0) { if (m_atvDemod->getEffectiveSampleRate() == 0) {
m_fltLineTimeMultiplier = std::pow(10.0, lineTimeScaleFactor-3); m_fltLineTimeMultiplier = std::pow(10.0, lineTimeScaleFactor-3);
} else { } else {
m_fltLineTimeMultiplier = 1.0f / m_objATVDemod->getEffectiveSampleRate(); m_fltLineTimeMultiplier = 1.0f / m_atvDemod->getEffectiveSampleRate();
} }
float lineTime = nominalLineTime + m_fltLineTimeMultiplier * ui->lineTime->value(); float lineTime = nominalLineTime + m_fltLineTimeMultiplier * ui->lineTime->value();
@ -657,10 +659,10 @@ void ATVDemodGUI::topTimeUpdate()
float nominalTopTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) * (4.7f / 64.0f); float nominalTopTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) * (4.7f / 64.0f);
int topTimeScaleFactor = (int) std::log10(nominalTopTime); int topTimeScaleFactor = (int) std::log10(nominalTopTime);
if (m_objATVDemod->getEffectiveSampleRate() == 0) { if (m_atvDemod->getEffectiveSampleRate() == 0) {
m_fltTopTimeMultiplier = std::pow(10.0, topTimeScaleFactor-3); m_fltTopTimeMultiplier = std::pow(10.0, topTimeScaleFactor-3);
} else { } else {
m_fltTopTimeMultiplier = 1.0f / m_objATVDemod->getEffectiveSampleRate(); m_fltTopTimeMultiplier = 1.0f / m_atvDemod->getEffectiveSampleRate();
} }
float topTime = nominalTopTime + m_fltTopTimeMultiplier * ui->topTime->value(); float topTime = nominalTopTime + m_fltTopTimeMultiplier * ui->topTime->value();

View File

@ -18,10 +18,10 @@
#ifndef INCLUDE_ATVDEMODGUI_H #ifndef INCLUDE_ATVDEMODGUI_H
#define INCLUDE_ATVDEMODGUI_H #define INCLUDE_ATVDEMODGUI_H
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
class PluginAPI; class PluginAPI;
@ -37,7 +37,7 @@ namespace Ui
class ATVDemodGUI; class ATVDemodGUI;
} }
class ATVDemodGUI : public RollupWidget, public PluginInstanceUI class ATVDemodGUI : public RollupWidget, public PluginInstanceGUI
{ {
Q_OBJECT Q_OBJECT
@ -89,12 +89,12 @@ private slots:
private: private:
Ui::ATVDemodGUI* ui; Ui::ATVDemodGUI* ui;
PluginAPI* m_objPluginAPI; PluginAPI* m_pluginAPI;
DeviceSourceAPI* m_objDeviceAPI; DeviceSourceAPI* m_deviceAPI;
ChannelMarker m_objChannelMarker; ChannelMarker m_channelMarker;
ThreadedBasebandSampleSink* m_objThreadedChannelizer; ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_objChannelizer; DownChannelizer* m_channelizer;
ATVDemod* m_objATVDemod; ATVDemod* m_atvDemod;
bool m_blnBasicSettingsShown; bool m_blnBasicSettingsShown;
bool m_blnDoApplySettings; bool m_blnDoApplySettings;
@ -102,7 +102,7 @@ private:
MovingAverage<double> m_objMagSqAverage; MovingAverage<double> m_objMagSqAverage;
int m_intTickCount; int m_intTickCount;
ScopeVisNG* m_objScopeVis; ScopeVisNG* m_scopeVis;
float m_fltLineTimeMultiplier; float m_fltLineTimeMultiplier;
float m_fltTopTimeMultiplier; float m_fltTopTimeMultiplier;

View File

@ -26,7 +26,7 @@
const PluginDescriptor ATVDemodPlugin::m_ptrPluginDescriptor = const PluginDescriptor ATVDemodPlugin::m_ptrPluginDescriptor =
{ {
QString("ATV Demodulator"), QString("ATV Demodulator"),
QString("3.5.0"), QString("3.7.3"),
QString("(c) F4HKW for F4EXB / SDRAngel"), QString("(c) F4HKW for F4EXB / SDRAngel"),
QString("https://github.com/f4exb/sdrangel"), QString("https://github.com/f4exb/sdrangel"),
true, true,
@ -53,7 +53,7 @@ void ATVDemodPlugin::initPlugin(PluginAPI* ptrPluginAPI)
m_ptrPluginAPI->registerRxChannel(ATVDemodGUI::m_strChannelID, this); m_ptrPluginAPI->registerRxChannel(ATVDemodGUI::m_strChannelID, this);
} }
PluginInstanceUI* ATVDemodPlugin::createRxChannel(const QString& strChannelName, DeviceSourceAPI *ptrDeviceAPI) PluginInstanceGUI* ATVDemodPlugin::createRxChannel(const QString& strChannelName, DeviceSourceAPI *ptrDeviceAPI)
{ {
if(strChannelName == ATVDemodGUI::m_strChannelID) if(strChannelName == ATVDemodGUI::m_strChannelID)
{ {

View File

@ -35,7 +35,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* ptrPluginAPI); void initPlugin(PluginAPI* ptrPluginAPI);
PluginInstanceUI* createRxChannel(const QString& strChannelName, DeviceSourceAPI *ptrDeviceAPI); PluginInstanceGUI* createRxChannel(const QString& strChannelName, DeviceSourceAPI *ptrDeviceAPI);
private: private:
static const PluginDescriptor m_ptrPluginDescriptor; static const PluginDescriptor m_ptrPluginDescriptor;

View File

@ -3,6 +3,7 @@ project(bfm)
set(bfm_SOURCES set(bfm_SOURCES
bfmdemod.cpp bfmdemod.cpp
bfmdemodgui.cpp bfmdemodgui.cpp
bfmdemodsettings.cpp
bfmplugin.cpp bfmplugin.cpp
rdsdemod.cpp rdsdemod.cpp
rdsdecoder.cpp rdsdecoder.cpp
@ -13,6 +14,7 @@ set(bfm_SOURCES
set(bfm_HEADERS set(bfm_HEADERS
bfmdemod.h bfmdemod.h
bfmdemodgui.h bfmdemodgui.h
bfmdemodsettings.h
bfmplugin.h bfmplugin.h
rdsdemod.h rdsdemod.h
rdsdecoder.h rdsdecoder.h

View File

@ -15,63 +15,77 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#include "../../channelrx/demodbfm/bfmdemod.h"
#include <QTime> #include <QTime>
#include <QDebug> #include <QDebug>
#include <stdio.h> #include <stdio.h>
#include <complex.h> #include <complex.h>
#include "audio/audiooutput.h" #include "audio/audiooutput.h"
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "dsp/pidcontroller.h" #include "dsp/pidcontroller.h"
#include "bfmdemod.h"
#include <dsp/downchannelizer.h> #include <dsp/downchannelizer.h>
#include "dsp/threadedbasebandsamplesink.h"
#include "device/devicesourceapi.h"
#include "rdsparser.h" #include "rdsparser.h"
#include "bfmdemod.h"
MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(BFMDemod::MsgReportChannelSampleRateChanged, Message)
MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureBFMDemod, Message) MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureBFMDemod, Message)
const Real BFMDemod::default_deemphasis = 50.0; // 50 us const Real BFMDemod::default_deemphasis = 50.0; // 50 us
const int BFMDemod::m_udpBlockSize = 512; const int BFMDemod::m_udpBlockSize = 512;
BFMDemod::BFMDemod(BasebandSampleSink* sampleSink, RDSParser *rdsParser) : BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI) :
m_sampleSink(sampleSink), m_deviceAPI(deviceAPI),
m_audioFifo(250000), m_audioFifo(250000),
m_settingsMutex(QMutex::Recursive), m_settingsMutex(QMutex::Recursive),
m_pilotPLL(19000/384000, 50/384000, 0.01), m_pilotPLL(19000/384000, 50/384000, 0.01),
m_rdsParser(rdsParser),
m_deemphasisFilterX(default_deemphasis * 48000 * 1.0e-6), m_deemphasisFilterX(default_deemphasis * 48000 * 1.0e-6),
m_deemphasisFilterY(default_deemphasis * 48000 * 1.0e-6), m_deemphasisFilterY(default_deemphasis * 48000 * 1.0e-6),
m_fmExcursion(default_excursion) m_fmExcursion(default_excursion)
{ {
setObjectName("BFMDemod"); setObjectName("BFMDemod");
m_config.m_inputSampleRate = 384000; m_magsq = 0.0f;
m_config.m_inputFrequencyOffset = 0;
m_config.m_rfBandwidth = 180000;
m_config.m_afBandwidth = 15000;
m_config.m_squelch = -60.0;
m_config.m_volume = 2.0;
m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); // normally 48 kHz
m_deemphasisFilterX.configure(default_deemphasis * m_config.m_audioSampleRate * 1.0e-6);
m_deemphasisFilterY.configure(default_deemphasis * m_config.m_audioSampleRate * 1.0e-6);
m_rfFilter = new fftfilt(-50000.0 / 384000.0, 50000.0 / 384000.0, filtFftLen);
m_phaseDiscri.setFMScaling(384000/m_fmExcursion);
apply();
m_audioBuffer.resize(16384);
m_audioBufferFill = 0;
// m_movingAverage.resize(16, 0);
m_magsq = 0.0f;
m_magsqSum = 0.0f; m_magsqSum = 0.0f;
m_magsqPeak = 0.0f; m_magsqPeak = 0.0f;
m_magsqCount = 0; m_magsqCount = 0;
m_squelchLevel = 0;
m_squelchState = 0;
m_interpolatorDistance = 0.0f;
m_interpolatorDistanceRemain = 0.0f;
m_interpolatorRDSDistance = 0.0f;
m_interpolatorRDSDistanceRemain = 0.0f;
m_interpolatorStereoDistance = 0.0f;
m_interpolatorStereoDistanceRemain = 0.0f;
m_sampleSink = 0;
m_m1Arg = 0;
m_rfFilter = new fftfilt(-50000.0 / 384000.0, 50000.0 / 384000.0, filtFftLen);
m_channelizer = new DownChannelizer(this);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged()));
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
m_deemphasisFilterX.configure(default_deemphasis * m_settings.m_audioSampleRate * 1.0e-6);
m_deemphasisFilterY.configure(default_deemphasis * m_settings.m_audioSampleRate * 1.0e-6);
m_phaseDiscri.setFMScaling(384000/m_fmExcursion);
m_audioBuffer.resize(16384);
m_audioBufferFill = 0;
DSPEngine::instance()->addAudioSink(&m_audioFifo); DSPEngine::instance()->addAudioSink(&m_audioFifo);
m_udpBufferAudio = new UDPSink<AudioSample>(this, m_udpBlockSize, m_config.m_udpPort); m_udpBufferAudio = new UDPSink<AudioSample>(this, m_udpBlockSize, m_settings.m_udpPort);
applySettings(m_settings, true);
} }
BFMDemod::~BFMDemod() BFMDemod::~BFMDemod()
@ -83,35 +97,10 @@ BFMDemod::~BFMDemod()
DSPEngine::instance()->removeAudioSink(&m_audioFifo); DSPEngine::instance()->removeAudioSink(&m_audioFifo);
delete m_udpBufferAudio; delete m_udpBufferAudio;
}
void BFMDemod::configure(MessageQueue* messageQueue, m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
Real rfBandwidth, delete m_threadedChannelizer;
Real afBandwidth, delete m_channelizer;
Real volume,
Real squelch,
bool audioStereo,
bool lsbStereo,
bool showPilot,
bool rdsActive,
bool copyAudioToUDP,
const QString& udpAddress,
quint16 udpPort,
bool force)
{
Message* cmd = MsgConfigureBFMDemod::create(rfBandwidth,
afBandwidth,
volume,
squelch,
audioStereo,
lsbStereo,
showPilot,
rdsActive,
copyAudioToUDP,
udpAddress,
udpPort,
force);
messageQueue->push(cmd);
} }
void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst __attribute__((unused))) void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst __attribute__((unused)))
@ -149,7 +138,7 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
// m_movingAverage.feed(msq); // m_movingAverage.feed(msq);
if(m_magsq >= m_squelchLevel) { if(m_magsq >= m_squelchLevel) {
m_squelchState = m_running.m_rfBandwidth / 20; // decay rate m_squelchState = m_settings.m_rfBandwidth / 20; // decay rate
} }
if(m_squelchState > 0) if(m_squelchState > 0)
@ -164,12 +153,12 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
demod = 0; demod = 0;
} }
if (!m_running.m_showPilot) if (!m_settings.m_showPilot)
{ {
m_sampleBuffer.push_back(Sample(demod * (1<<15), 0.0)); m_sampleBuffer.push_back(Sample(demod * (1<<15), 0.0));
} }
if (m_running.m_rdsActive) if (m_settings.m_rdsActive)
{ {
//Complex r(demod * 2.0 * std::cos(3.0 * m_pilotPLLSamples[3]), 0.0); //Complex r(demod * 2.0 * std::cos(3.0 * m_pilotPLLSamples[3]), 0.0);
Complex r(demod * 2.0 * std::cos(3.0 * m_pilotPLLSamples[3]), 0.0); Complex r(demod * 2.0 * std::cos(3.0 * m_pilotPLLSamples[3]), 0.0);
@ -182,10 +171,7 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
{ {
if (m_rdsDecoder.frameSync(bit)) if (m_rdsDecoder.frameSync(bit))
{ {
if (m_rdsParser) m_rdsParser.parseGroup(m_rdsDecoder.getGroup());
{
m_rdsParser->parseGroup(m_rdsDecoder.getGroup());
}
} }
} }
@ -197,16 +183,16 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
// Process stereo if stereo mode is selected // Process stereo if stereo mode is selected
if (m_running.m_audioStereo) if (m_settings.m_audioStereo)
{ {
m_pilotPLL.process(demod, m_pilotPLLSamples); m_pilotPLL.process(demod, m_pilotPLLSamples);
if (m_running.m_showPilot) if (m_settings.m_showPilot)
{ {
m_sampleBuffer.push_back(Sample(m_pilotPLLSamples[1] * (1<<15), 0.0)); // debug 38 kHz pilot m_sampleBuffer.push_back(Sample(m_pilotPLLSamples[1] * (1<<15), 0.0)); // debug 38 kHz pilot
} }
if (m_running.m_lsbStereo) if (m_settings.m_lsbStereo)
{ {
// 1.17 * 0.7 = 0.819 // 1.17 * 0.7 = 0.819
Complex s(demod * m_pilotPLLSamples[1], demod * m_pilotPLLSamples[2]); Complex s(demod * m_pilotPLLSamples[1], demod * m_pilotPLLSamples[2]);
@ -233,32 +219,32 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, e, &ci)) if (m_interpolator.decimate(&m_interpolatorDistanceRemain, e, &ci))
{ {
if (m_running.m_audioStereo) if (m_settings.m_audioStereo)
{ {
Real deemph_l, deemph_r; // Pre-emphasis is applied on each channel before multiplexing Real deemph_l, deemph_r; // Pre-emphasis is applied on each channel before multiplexing
m_deemphasisFilterX.process(ci.real() + sampleStereo, deemph_l); m_deemphasisFilterX.process(ci.real() + sampleStereo, deemph_l);
m_deemphasisFilterY.process(ci.real() - sampleStereo, deemph_r); m_deemphasisFilterY.process(ci.real() - sampleStereo, deemph_r);
if (m_running.m_lsbStereo) if (m_settings.m_lsbStereo)
{ {
m_audioBuffer[m_audioBufferFill].l = (qint16)(deemph_l * (1<<12) * m_running.m_volume); m_audioBuffer[m_audioBufferFill].l = (qint16)(deemph_l * (1<<12) * m_settings.m_volume);
m_audioBuffer[m_audioBufferFill].r = (qint16)(deemph_r * (1<<12) * m_running.m_volume); m_audioBuffer[m_audioBufferFill].r = (qint16)(deemph_r * (1<<12) * m_settings.m_volume);
if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]); if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]);
} }
else else
{ {
m_audioBuffer[m_audioBufferFill].l = (qint16)(deemph_l * (1<<12) * m_running.m_volume); m_audioBuffer[m_audioBufferFill].l = (qint16)(deemph_l * (1<<12) * m_settings.m_volume);
m_audioBuffer[m_audioBufferFill].r = (qint16)(deemph_r * (1<<12) * m_running.m_volume); m_audioBuffer[m_audioBufferFill].r = (qint16)(deemph_r * (1<<12) * m_settings.m_volume);
if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]); if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]);
} }
} }
else else
{ {
Real deemph; Real deemph;
m_deemphasisFilterX.process(ci.real(), deemph); m_deemphasisFilterX.process(ci.real(), deemph);
quint16 sample = (qint16)(deemph * (1<<12) * m_running.m_volume); quint16 sample = (qint16)(deemph * (1<<12) * m_settings.m_volume);
m_audioBuffer[m_audioBufferFill].l = sample; m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample; m_audioBuffer[m_audioBufferFill].r = sample;
if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]); if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]);
} }
++m_audioBufferFill; ++m_audioBufferFill;
@ -313,54 +299,58 @@ void BFMDemod::stop()
{ {
} }
void BFMDemod::channelSampleRateChanged()
{
MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create(getSampleRate());
getMessageQueueToGUI()->push(msg);
}
bool BFMDemod::handleMessage(const Message& cmd) bool BFMDemod::handleMessage(const Message& cmd)
{ {
if (DownChannelizer::MsgChannelizerNotification::match(cmd)) if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{ {
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
m_config.m_inputSampleRate = notif.getSampleRate(); BFMDemodSettings settings = m_settings;
m_config.m_inputFrequencyOffset = notif.getFrequencyOffset();
apply(); settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
qDebug() << "BFMDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << m_config.m_inputSampleRate applySettings(settings);
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset;
qDebug() << "BFMDemod::handleMessage: MsgChannelizerNotification:"
<< " m_inputSampleRate: " << settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset;
return true; return true;
} }
else if (MsgConfigureBFMDemod::match(cmd)) else if (MsgConfigureBFMDemod::match(cmd))
{ {
MsgConfigureBFMDemod& cfg = (MsgConfigureBFMDemod&) cmd; MsgConfigureBFMDemod& cfg = (MsgConfigureBFMDemod&) cmd;
m_config.m_rfBandwidth = cfg.getRFBandwidth(); BFMDemodSettings settings = cfg.getSettings();
m_config.m_afBandwidth = cfg.getAFBandwidth();
m_config.m_volume = cfg.getVolume();
m_config.m_squelch = cfg.getSquelch();
m_config.m_audioStereo = cfg.getAudioStereo();
m_config.m_lsbStereo = cfg.getLsbStereo();
m_config.m_showPilot = cfg.getShowPilot();
m_config.m_rdsActive = cfg.getRDSActive();
m_config.m_copyAudioToUDP= cfg.getCopyAudioToUDP();
m_config.m_udpAddress = cfg.getUDPAddress();
m_config.m_udpPort = cfg.getUDPPort();
apply(cfg.getForce()); // These settings are set with DownChannelizer::MsgChannelizerNotification
settings.m_inputSampleRate = m_settings.m_inputSampleRate;
settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset;
qDebug() << "BFMDemod::handleMessage: MsgConfigureBFMDemod: m_rfBandwidth: " << m_config.m_rfBandwidth applySettings(settings, cfg.getForce());
<< " m_afBandwidth: " << m_config.m_afBandwidth
<< " m_volume: " << m_config.m_volume
<< " m_squelch: " << m_config.m_squelch
<< " m_audioStereo: " << m_config.m_audioStereo
<< " m_lsbStereo: " << m_config.m_lsbStereo
<< " m_showPilot: " << m_config.m_showPilot
<< " m_rdsActive: " << m_config.m_rdsActive
<< " m_copyAudioToUDP: " << m_config.m_copyAudioToUDP
<< " m_udpAddress: " << m_config.m_udpAddress
<< " m_udpPort: " << m_config.m_udpPort;
return true; qDebug() << "BFMDemod::handleMessage: MsgConfigureBFMDemod:"
} << " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_volume: " << settings.m_volume
<< " m_squelch: " << settings.m_squelch
<< " m_audioStereo: " << settings.m_audioStereo
<< " m_lsbStereo: " << settings.m_lsbStereo
<< " m_showPilot: " << settings.m_showPilot
<< " m_rdsActive: " << settings.m_rdsActive
<< " m_copyAudioToUDP: " << settings.m_copyAudioToUDP
<< " m_udpAddress: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " force: " << cfg.getForce();
return true;
}
else else
{ {
qDebug() << "BFMDemod::handleMessage: none"; qDebug() << "BFMDemod::handleMessage: none";
@ -376,87 +366,87 @@ bool BFMDemod::handleMessage(const Message& cmd)
} }
} }
void BFMDemod::apply(bool force) void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
{ {
if ((m_config.m_inputSampleRate != m_running.m_inputSampleRate) if ((settings.m_inputSampleRate != m_settings.m_inputSampleRate)
|| (m_config.m_audioStereo && (m_config.m_audioStereo != m_running.m_audioStereo)) || force) || (settings.m_audioStereo && (settings.m_audioStereo != m_settings.m_audioStereo)) || force)
{
m_pilotPLL.configure(19000.0/m_config.m_inputSampleRate, 50.0/m_config.m_inputSampleRate, 0.01);
}
if((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) ||
(m_config.m_inputSampleRate != m_running.m_inputSampleRate) || force)
{
qDebug() << "BFMDemod::handleMessage: m_nco.setFreq";
m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate);
}
if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
(m_config.m_afBandwidth != m_running.m_afBandwidth) || force)
{
m_settingsMutex.lock();
qDebug() << "BFMDemod::handleMessage: m_interpolator.create";
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_afBandwidth);
m_interpolatorDistanceRemain = (Real) m_config.m_inputSampleRate / m_config.m_audioSampleRate;
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate;
m_interpolatorStereo.create(16, m_config.m_inputSampleRate, m_config.m_afBandwidth);
m_interpolatorStereoDistanceRemain = (Real) m_config.m_inputSampleRate / m_config.m_audioSampleRate;
m_interpolatorStereoDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate;
m_interpolatorRDS.create(4, m_config.m_inputSampleRate, 600.0);
m_interpolatorRDSDistanceRemain = (Real) m_config.m_inputSampleRate / 250000.0;
m_interpolatorRDSDistance = (Real) m_config.m_inputSampleRate / 250000.0;
m_settingsMutex.unlock();
}
if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth) ||
(m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || force)
{
m_settingsMutex.lock();
Real lowCut = -(m_config.m_rfBandwidth / 2.0) / m_config.m_inputSampleRate;
Real hiCut = (m_config.m_rfBandwidth / 2.0) / m_config.m_inputSampleRate;
m_rfFilter->create_filter(lowCut, hiCut);
m_phaseDiscri.setFMScaling(m_config.m_inputSampleRate / m_fmExcursion);
m_settingsMutex.unlock();
qDebug() << "BFMDemod::handleMessage: m_rfFilter->create_filter: sampleRate: "
<< m_config.m_inputSampleRate
<< " lowCut: " << lowCut * m_config.m_inputSampleRate
<< " hiCut: " << hiCut * m_config.m_inputSampleRate;
}
if ((m_config.m_afBandwidth != m_running.m_afBandwidth) ||
(m_config.m_audioSampleRate != m_running.m_audioSampleRate) || force)
{
m_settingsMutex.lock();
qDebug() << "BFMDemod::handleMessage: m_lowpass.create";
m_lowpass.create(21, m_config.m_audioSampleRate, m_config.m_afBandwidth);
m_settingsMutex.unlock();
}
if ((m_config.m_squelch != m_running.m_squelch) || force)
{
qDebug() << "BFMDemod::handleMessage: set m_squelchLevel";
m_squelchLevel = std::pow(10.0, m_config.m_squelch / 20.0);
m_squelchLevel *= m_squelchLevel;
}
if ((m_config.m_audioSampleRate != m_running.m_audioSampleRate) || force)
{
m_deemphasisFilterX.configure(default_deemphasis * m_config.m_audioSampleRate * 1.0e-6);
m_deemphasisFilterY.configure(default_deemphasis * m_config.m_audioSampleRate * 1.0e-6);
}
if ((m_config.m_udpAddress != m_running.m_udpAddress)
|| (m_config.m_udpPort != m_running.m_udpPort) || force)
{ {
m_udpBufferAudio->setAddress(m_config.m_udpAddress); m_pilotPLL.configure(19000.0/settings.m_inputSampleRate, 50.0/settings.m_inputSampleRate, 0.01);
m_udpBufferAudio->setPort(m_config.m_udpPort);
} }
m_running = m_config; if((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) ||
(settings.m_inputSampleRate != m_settings.m_inputSampleRate) || force)
{
qDebug() << "BFMDemod::handleMessage: m_nco.setFreq";
m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate);
}
if((settings.m_inputSampleRate != m_settings.m_inputSampleRate) ||
(settings.m_afBandwidth != m_settings.m_afBandwidth) || force)
{
m_settingsMutex.lock();
qDebug() << "BFMDemod::handleMessage: m_interpolator.create";
m_interpolator.create(16, settings.m_inputSampleRate, settings.m_afBandwidth);
m_interpolatorDistanceRemain = (Real) settings.m_inputSampleRate / settings.m_audioSampleRate;
m_interpolatorDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate;
m_interpolatorStereo.create(16, settings.m_inputSampleRate, settings.m_afBandwidth);
m_interpolatorStereoDistanceRemain = (Real) settings.m_inputSampleRate / settings.m_audioSampleRate;
m_interpolatorStereoDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate;
m_interpolatorRDS.create(4, settings.m_inputSampleRate, 600.0);
m_interpolatorRDSDistanceRemain = (Real) settings.m_inputSampleRate / 250000.0;
m_interpolatorRDSDistance = (Real) settings.m_inputSampleRate / 250000.0;
m_settingsMutex.unlock();
}
if((settings.m_inputSampleRate != m_settings.m_inputSampleRate) ||
(settings.m_rfBandwidth != m_settings.m_rfBandwidth) ||
(settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force)
{
m_settingsMutex.lock();
Real lowCut = -(settings.m_rfBandwidth / 2.0) / settings.m_inputSampleRate;
Real hiCut = (settings.m_rfBandwidth / 2.0) / settings.m_inputSampleRate;
m_rfFilter->create_filter(lowCut, hiCut);
m_phaseDiscri.setFMScaling(settings.m_inputSampleRate / m_fmExcursion);
m_settingsMutex.unlock();
qDebug() << "BFMDemod::handleMessage: m_rfFilter->create_filter: sampleRate: "
<< settings.m_inputSampleRate
<< " lowCut: " << lowCut * settings.m_inputSampleRate
<< " hiCut: " << hiCut * settings.m_inputSampleRate;
}
if ((settings.m_afBandwidth != m_settings.m_afBandwidth) ||
(settings.m_audioSampleRate != m_settings.m_audioSampleRate) || force)
{
m_settingsMutex.lock();
qDebug() << "BFMDemod::handleMessage: m_lowpass.create";
m_lowpass.create(21, settings.m_audioSampleRate, settings.m_afBandwidth);
m_settingsMutex.unlock();
}
if ((settings.m_squelch != m_settings.m_squelch) || force)
{
qDebug() << "BFMDemod::handleMessage: set m_squelchLevel";
m_squelchLevel = std::pow(10.0, settings.m_squelch / 20.0);
m_squelchLevel *= m_squelchLevel;
}
if ((settings.m_audioSampleRate != m_settings.m_audioSampleRate) || force)
{
m_deemphasisFilterX.configure(default_deemphasis * settings.m_audioSampleRate * 1.0e-6);
m_deemphasisFilterY.configure(default_deemphasis * settings.m_audioSampleRate * 1.0e-6);
}
if ((settings.m_udpAddress != m_settings.m_udpAddress)
|| (settings.m_udpPort != m_settings.m_udpPort) || force)
{
m_udpBufferAudio->setAddress(const_cast<QString&>(settings.m_udpAddress));
m_udpBufferAudio->setPort(settings.m_udpPort);
}
m_settings = settings;
} }

View File

@ -33,31 +33,88 @@
#include "util/message.h" #include "util/message.h"
#include "util/udpsink.h" #include "util/udpsink.h"
#include "rdsparser.h"
#include "rdsdecoder.h" #include "rdsdecoder.h"
#include "rdsdemod.h" #include "rdsdemod.h"
#include "bfmdemodsettings.h"
class RDSParser; class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class BFMDemod : public BasebandSampleSink { class BFMDemod : public BasebandSampleSink {
public: public:
BFMDemod(BasebandSampleSink* sampleSink, RDSParser* rdsParser); class MsgConfigureBFMDemod : public Message {
MESSAGE_CLASS_DECLARATION
public:
const BFMDemodSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureBFMDemod* create(const BFMDemodSettings& settings, bool force)
{
return new MsgConfigureBFMDemod(settings, force);
}
private:
BFMDemodSettings m_settings;
bool m_force;
MsgConfigureBFMDemod(const BFMDemodSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
class MsgConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
{
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
}
private:
int m_sampleRate;
int m_centerFrequency;
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
Message(),
m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency)
{ }
};
class MsgReportChannelSampleRateChanged : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getSampleRate() const { return m_sampleRate; }
static MsgReportChannelSampleRateChanged* create(int sampleRate)
{
return new MsgReportChannelSampleRateChanged(sampleRate);
}
private:
int m_sampleRate;
MsgReportChannelSampleRateChanged(int sampleRate) :
Message(),
m_sampleRate(sampleRate)
{ }
};
BFMDemod(DeviceSourceAPI *deviceAPI);
virtual ~BFMDemod(); virtual ~BFMDemod();
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
void configure(MessageQueue* messageQueue, int getSampleRate() const { return m_settings.m_inputSampleRate; }
Real rfBandwidth,
Real afBandwidth,
Real volume,
Real squelch,
bool audioStereo,
bool lsbStereo,
bool showPilot,
bool rdsActive,
bool copyAudioUDP,
const QString& m_udpAddress,
quint16 udpPort,
bool force = false);
int getSampleRate() const { return m_config.m_inputSampleRate; }
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
virtual void start(); virtual void start();
virtual void stop(); virtual void stop();
@ -85,134 +142,22 @@ public:
m_magsqCount = 0; m_magsqCount = 0;
} }
RDSParser& getRDSParser() { return m_rdsParser; }
private slots:
void channelSampleRateChanged();
private: private:
class MsgConfigureBFMDemod : public Message {
MESSAGE_CLASS_DECLARATION
public:
Real getRFBandwidth() const { return m_rfBandwidth; }
Real getAFBandwidth() const { return m_afBandwidth; }
Real getVolume() const { return m_volume; }
Real getSquelch() const { return m_squelch; }
bool getAudioStereo() const { return m_audioStereo; }
bool getLsbStereo() const { return m_lsbStereo; }
bool getShowPilot() const { return m_showPilot; }
bool getRDSActive() const { return m_rdsActive; }
bool getCopyAudioToUDP() const { return m_copyAudioToUDP; }
const QString& getUDPAddress() const { return m_udpAddress; }
quint16 getUDPPort() const { return m_udpPort; }
bool getForce() const { return m_force; }
static MsgConfigureBFMDemod* create(Real rfBandwidth,
Real afBandwidth,
Real volume,
Real squelch,
bool audioStereo,
bool lsbStereo,
bool showPilot,
bool rdsActive,
bool copyAudioToUDP,
const QString& udpAddress,
quint16 udpPort,
bool force)
{
return new MsgConfigureBFMDemod(rfBandwidth,
afBandwidth,
volume,
squelch,
audioStereo,
lsbStereo,
showPilot,
rdsActive,
copyAudioToUDP,
udpAddress,
udpPort,
force);
}
private:
Real m_rfBandwidth;
Real m_afBandwidth;
Real m_volume;
Real m_squelch;
bool m_audioStereo;
bool m_lsbStereo;
bool m_showPilot;
bool m_rdsActive;
bool m_copyAudioToUDP;
QString m_udpAddress;
quint16 m_udpPort;
bool m_force;
MsgConfigureBFMDemod(Real rfBandwidth,
Real afBandwidth,
Real volume,
Real squelch,
bool audioStereo,
bool lsbStereo,
bool showPilot,
bool rdsActive,
bool copyAudioToUDP,
const QString& udpAddress,
quint16 udpPort,
bool force) :
Message(),
m_rfBandwidth(rfBandwidth),
m_afBandwidth(afBandwidth),
m_volume(volume),
m_squelch(squelch),
m_audioStereo(audioStereo),
m_lsbStereo(lsbStereo),
m_showPilot(showPilot),
m_rdsActive(rdsActive),
m_copyAudioToUDP(copyAudioToUDP),
m_udpAddress(udpAddress),
m_udpPort(udpPort),
m_force(force)
{ }
};
enum RateState { enum RateState {
RSInitialFill, RSInitialFill,
RSRunning RSRunning
}; };
struct Config { DeviceSourceAPI *m_deviceAPI;
int m_inputSampleRate; ThreadedBasebandSampleSink* m_threadedChannelizer;
qint64 m_inputFrequencyOffset; DownChannelizer* m_channelizer;
Real m_rfBandwidth;
Real m_afBandwidth;
Real m_squelch;
Real m_volume;
quint32 m_audioSampleRate;
bool m_audioStereo;
bool m_lsbStereo;
bool m_showPilot;
bool m_rdsActive;
bool m_copyAudioToUDP;
QString m_udpAddress;
quint16 m_udpPort;
Config() : BFMDemodSettings m_settings;
m_inputSampleRate(-1),
m_inputFrequencyOffset(0),
m_rfBandwidth(-1),
m_afBandwidth(-1),
m_squelch(0),
m_volume(0),
m_audioSampleRate(0),
m_audioStereo(false),
m_lsbStereo(false),
m_showPilot(false),
m_rdsActive(false),
m_copyAudioToUDP(false),
m_udpAddress("127.0.0.1"),
m_udpPort(9999)
{ }
};
Config m_config;
Config m_running;
NCO m_nco; NCO m_nco;
Interpolator m_interpolator; //!< Interpolator between fixed demod bandwidth and audio bandwidth (rational) Interpolator m_interpolator; //!< Interpolator between fixed demod bandwidth and audio bandwidth (rational)
@ -254,7 +199,7 @@ private:
RDSDemod m_rdsDemod; RDSDemod m_rdsDemod;
RDSDecoder m_rdsDecoder; RDSDecoder m_rdsDecoder;
RDSParser *m_rdsParser; RDSParser m_rdsParser;
LowPassFilterRC m_deemphasisFilterX; LowPassFilterRC m_deemphasisFilterX;
LowPassFilterRC m_deemphasisFilterY; LowPassFilterRC m_deemphasisFilterY;
@ -268,7 +213,7 @@ private:
static const int m_udpBlockSize; static const int m_udpBlockSize;
void apply(bool force = false); void applySettings(const BFMDemodSettings& settings, bool force = false);
}; };
#endif // INCLUDE_BFMDEMOD_H #endif // INCLUDE_BFMDEMOD_H

View File

@ -37,26 +37,13 @@
#include "gui/basicchannelsettingsdialog.h" #include "gui/basicchannelsettingsdialog.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "bfmdemodsettings.h"
#include "bfmdemod.h" #include "bfmdemod.h"
#include "rdstmc.h" #include "rdstmc.h"
#include "ui_bfmdemodgui.h" #include "ui_bfmdemodgui.h"
const QString BFMDemodGUI::m_channelID = "sdrangel.channel.bfm"; const QString BFMDemodGUI::m_channelID = "sdrangel.channel.bfm";
const int BFMDemodGUI::m_rfBW[] = {
80000, 100000, 120000, 140000, 160000, 180000, 200000, 220000, 250000
};
//int requiredBW(int rfBW)
//{
// if (rfBW <= 48000)
// return 48000;
// else if (rfBW < 100000)
// return 96000;
// else
// return 384000;
//}
BFMDemodGUI* BFMDemodGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI) BFMDemodGUI* BFMDemodGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI)
{ {
BFMDemodGUI* gui = new BFMDemodGUI(pluginAPI, deviceAPI); BFMDemodGUI* gui = new BFMDemodGUI(pluginAPI, deviceAPI);
@ -91,119 +78,65 @@ void BFMDemodGUI::setCenterFrequency(qint64 centerFrequency)
void BFMDemodGUI::resetToDefaults() void BFMDemodGUI::resetToDefaults()
{ {
blockApplySettings(true); m_settings.resetToDefaults();
displaySettings();
ui->rfBW->setValue(4); blockApplySettings(true);
ui->afBW->setValue(3);
ui->volume->setValue(20);
ui->squelch->setValue(-40);
ui->deltaFrequency->setValue(0);
ui->copyAudioToUDP->setChecked(false);
m_channelMarker.setTitle("Broadcast FM Demod");
m_channelMarker.setColor(QColor(80, 120, 228));
m_channelMarker.setBandwidth(12500);
m_channelMarker.setCenterFrequency(0);
m_channelMarker.setUDPAddress("127.0.0.1");
m_channelMarker.setUDPSendPort(9999);
setTitleColor(m_channelMarker.getColor());
ui->g00AltFrequenciesBox->setEnabled(false); ui->g00AltFrequenciesBox->setEnabled(false);
ui->g14MappedFrequencies->setEnabled(false); ui->g14MappedFrequencies->setEnabled(false);
ui->g14AltFrequencies->setEnabled(false); ui->g14AltFrequencies->setEnabled(false);
blockApplySettings(false); blockApplySettings(false);
applySettings(); applySettings();
} }
QByteArray BFMDemodGUI::serialize() const QByteArray BFMDemodGUI::serialize() const
{ {
SimpleSerializer s(1); return m_settings.serialize();
s.writeS32(1, m_channelMarker.getCenterFrequency());
s.writeS32(2, ui->rfBW->value());
s.writeS32(3, ui->afBW->value());
s.writeS32(4, ui->volume->value());
s.writeS32(5, ui->squelch->value());
s.writeU32(7, m_channelMarker.getColor().rgb());
s.writeBlob(8, ui->spectrumGUI->serialize());
s.writeBool(9, ui->audioStereo->isChecked());
s.writeBool(10, ui->lsbStereo->isChecked());
s.writeBlob(11, m_channelMarker.serialize());
return s.final();
} }
bool BFMDemodGUI::deserialize(const QByteArray& data) bool BFMDemodGUI::deserialize(const QByteArray& data)
{ {
SimpleDeserializer d(data); if(m_settings.deserialize(data)) {
updateChannelMarker();
if (!d.isValid()) displaySettings();
{ applySettings(true);
resetToDefaults(); return true;
return false; } else {
} resetToDefaults();
return false;
if (d.getVersion() == 1) }
{
QByteArray bytetmp;
qint32 tmp;
quint32 u32tmp;
bool booltmp;
QString strtmp;
blockApplySettings(true);
m_channelMarker.blockSignals(true);
d.readBlob(11, &bytetmp);
m_channelMarker.deserialize(bytetmp);
d.readS32(1, &tmp, 0);
m_channelMarker.setCenterFrequency(tmp);
d.readS32(2, &tmp, 4);
ui->rfBW->setValue(tmp);
ui->rfBWText->setText(QString("%1 kHz").arg(m_rfBW[tmp] / 1000.0));
m_channelMarker.setBandwidth(m_rfBW[tmp]);
d.readS32(3, &tmp, 3);
ui->afBW->setValue(tmp);
d.readS32(4, &tmp, 20);
ui->volume->setValue(tmp);
d.readS32(5, &tmp, -40);
ui->squelch->setValue(tmp);
if(d.readU32(7, &u32tmp))
{
m_channelMarker.setColor(u32tmp);
}
d.readBlob(8, &bytetmp);
ui->spectrumGUI->deserialize(bytetmp);
d.readBool(9, &booltmp, false);
ui->audioStereo->setChecked(booltmp);
d.readBool(10, &booltmp, false);
ui->lsbStereo->setChecked(booltmp);
this->setWindowTitle(m_channelMarker.getTitle());
displayUDPAddress();
blockApplySettings(false);
m_channelMarker.blockSignals(false);
applySettings(true);
return true;
}
else
{
resetToDefaults();
return false;
}
} }
bool BFMDemodGUI::handleMessage(const Message& message __attribute__((unused))) bool BFMDemodGUI::handleMessage(const Message& message)
{ {
return false; if (BFMDemod::MsgReportChannelSampleRateChanged::match(message))
{
BFMDemod::MsgReportChannelSampleRateChanged& report = (BFMDemod::MsgReportChannelSampleRateChanged&) message;
m_rate = report.getSampleRate();
ui->glSpectrum->setCenterFrequency(m_rate / 4);
ui->glSpectrum->setSampleRate(m_rate / 2);
return true;
}
else
{
return false;
}
}
void BFMDemodGUI::handleInputMessages()
{
Message* message;
while ((message = getInputMessageQueue()->pop()) != 0)
{
qDebug("BFMDemodGUI::handleInputMessages: message: %s", message->getIdentifier());
if (handleMessage(*message))
{
delete message;
}
}
} }
void BFMDemodGUI::channelMarkerChanged() void BFMDemodGUI::channelMarkerChanged()
@ -216,30 +149,36 @@ void BFMDemodGUI::channelMarkerChanged()
void BFMDemodGUI::on_deltaFrequency_changed(qint64 value) void BFMDemodGUI::on_deltaFrequency_changed(qint64 value)
{ {
m_channelMarker.setCenterFrequency(value); m_channelMarker.setCenterFrequency(value);
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
applySettings();
} }
void BFMDemodGUI::on_rfBW_valueChanged(int value) void BFMDemodGUI::on_rfBW_valueChanged(int value)
{ {
ui->rfBWText->setText(QString("%1 kHz").arg(m_rfBW[value] / 1000.0)); ui->rfBWText->setText(QString("%1 kHz").arg(BFMDemodSettings::getRFBW(value) / 1000.0));
m_channelMarker.setBandwidth(m_rfBW[value]); m_channelMarker.setBandwidth(BFMDemodSettings::getRFBW(value));
m_settings.m_rfBandwidth = BFMDemodSettings::getRFBW(value);
applySettings(); applySettings();
} }
void BFMDemodGUI::on_afBW_valueChanged(int value) void BFMDemodGUI::on_afBW_valueChanged(int value)
{ {
ui->afBWText->setText(QString("%1 kHz").arg(value)); ui->afBWText->setText(QString("%1 kHz").arg(value));
m_settings.m_afBandwidth = value * 1000.0;
applySettings(); applySettings();
} }
void BFMDemodGUI::on_volume_valueChanged(int value) void BFMDemodGUI::on_volume_valueChanged(int value)
{ {
ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
m_settings.m_volume = value / 10.0;
applySettings(); applySettings();
} }
void BFMDemodGUI::on_squelch_valueChanged(int value) void BFMDemodGUI::on_squelch_valueChanged(int value)
{ {
ui->squelchText->setText(QString("%1 dB").arg(value)); ui->squelchText->setText(QString("%1 dB").arg(value));
m_settings.m_squelch = value;
applySettings(); applySettings();
} }
@ -250,26 +189,31 @@ void BFMDemodGUI::on_audioStereo_toggled(bool stereo)
ui->audioStereo->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); ui->audioStereo->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
} }
m_settings.m_audioStereo = stereo;
applySettings(); applySettings();
} }
void BFMDemodGUI::on_lsbStereo_toggled(bool lsb __attribute__((unused))) void BFMDemodGUI::on_lsbStereo_toggled(bool lsb)
{ {
m_settings.m_lsbStereo = lsb;
applySettings(); applySettings();
} }
void BFMDemodGUI::on_copyAudioToUDP_toggled(bool copy __attribute__((unused))) void BFMDemodGUI::on_copyAudioToUDP_toggled(bool copy)
{ {
m_settings.m_copyAudioToUDP = copy;
applySettings(); applySettings();
} }
void BFMDemodGUI::on_showPilot_clicked() void BFMDemodGUI::on_showPilot_clicked()
{ {
m_settings.m_showPilot = ui->showPilot->isChecked();
applySettings(); applySettings();
} }
void BFMDemodGUI::on_rds_clicked() void BFMDemodGUI::on_rds_clicked()
{ {
m_settings.m_rdsActive = ui->rds->isChecked();
applySettings(); applySettings();
} }
@ -277,7 +221,7 @@ void BFMDemodGUI::on_clearData_clicked(bool checked __attribute__((unused)))
{ {
if (ui->rds->isChecked()) if (ui->rds->isChecked())
{ {
m_rdsParser.clearAllFields(); m_bfmDemod->getRDSParser().clearAllFields();
ui->g14ProgServiceNames->clear(); ui->g14ProgServiceNames->clear();
ui->g14MappedFrequencies->clear(); ui->g14MappedFrequencies->clear();
@ -298,9 +242,9 @@ void BFMDemodGUI::on_g14ProgServiceNames_currentIndexChanged(int _index)
if (index < m_g14ComboIndex.size()) if (index < m_g14ComboIndex.size())
{ {
unsigned int piKey = m_g14ComboIndex[index]; unsigned int piKey = m_g14ComboIndex[index];
RDSParser::freqs_map_t::const_iterator mIt = m_rdsParser.m_g14_mapped_freqs.find(piKey); RDSParser::freqs_map_t::const_iterator mIt = m_bfmDemod->getRDSParser().m_g14_mapped_freqs.find(piKey);
if (mIt != m_rdsParser.m_g14_mapped_freqs.end()) if (mIt != m_bfmDemod->getRDSParser().m_g14_mapped_freqs.end())
{ {
ui->g14MappedFrequencies->clear(); ui->g14MappedFrequencies->clear();
RDSParser::freqs_set_t::iterator sIt = (mIt->second).begin(); RDSParser::freqs_set_t::iterator sIt = (mIt->second).begin();
@ -316,9 +260,9 @@ void BFMDemodGUI::on_g14ProgServiceNames_currentIndexChanged(int _index)
ui->g14MappedFrequencies->setEnabled(ui->g14MappedFrequencies->count() > 0); ui->g14MappedFrequencies->setEnabled(ui->g14MappedFrequencies->count() > 0);
} }
mIt = m_rdsParser.m_g14_alt_freqs.find(piKey); mIt = m_bfmDemod->getRDSParser().m_g14_alt_freqs.find(piKey);
if (mIt != m_rdsParser.m_g14_alt_freqs.end()) if (mIt != m_bfmDemod->getRDSParser().m_g14_alt_freqs.end())
{ {
ui->g14AltFrequencies->clear(); ui->g14AltFrequencies->clear();
RDSParser::freqs_set_t::iterator sIt = (mIt->second).begin(); RDSParser::freqs_set_t::iterator sIt = (mIt->second).begin();
@ -354,7 +298,6 @@ void BFMDemodGUI::on_g14AltFrequencies_activated(int index __attribute__((unused
changeFrequency(f); changeFrequency(f);
} }
void BFMDemodGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused))) void BFMDemodGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused)))
{ {
} }
@ -385,13 +328,12 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
setAttribute(Qt::WA_DeleteOnClose, true); setAttribute(Qt::WA_DeleteOnClose, true);
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
m_spectrumVis = new SpectrumVis(ui->glSpectrum); m_spectrumVis = new SpectrumVis(ui->glSpectrum);
m_bfmDemod = new BFMDemod(m_spectrumVis, &m_rdsParser); m_bfmDemod = new BFMDemod(m_deviceAPI);
m_channelizer = new DownChannelizer(m_bfmDemod); m_bfmDemod->setMessageQueueToGUI(getInputMessageQueue());
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); m_bfmDemod->setSampleSink(m_spectrumVis);
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged()));
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
ui->glSpectrum->setCenterFrequency(m_rate / 4); ui->glSpectrum->setCenterFrequency(m_rate / 4);
ui->glSpectrum->setSampleRate(m_rate / 2); ui->glSpectrum->setSampleRate(m_rate / 2);
@ -401,16 +343,18 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
m_spectrumVis->configure(m_spectrumVis->getInputMessageQueue(), 64, 10, FFTWindow::BlackmanHarris); m_spectrumVis->configure(m_spectrumVis->getInputMessageQueue(), 64, 10, FFTWindow::BlackmanHarris);
connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
//m_channelMarker = new ChannelMarker(this);
m_channelMarker.setTitle("Broadcast FM Demod"); m_channelMarker.setTitle("Broadcast FM Demod");
m_channelMarker.setColor(QColor(80, 120, 228));
m_channelMarker.setBandwidth(12500); m_channelMarker.setBandwidth(12500);
m_channelMarker.setCenterFrequency(0); m_channelMarker.setCenterFrequency(0);
m_channelMarker.setUDPAddress("127.0.0.1"); m_channelMarker.setUDPAddress("127.0.0.1");
m_channelMarker.setUDPSendPort(9999); m_channelMarker.setUDPSendPort(9999);
m_channelMarker.setVisible(true); m_channelMarker.setVisible(true);
m_channelMarker.setColor(m_settings.m_rgbColor);
setTitleColor(m_channelMarker.getColor()); setTitleColor(m_channelMarker.getColor());
m_settings.setChannelMarker(&m_channelMarker);
m_settings.setSpectrumGUI(ui->spectrumGUI);
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
m_deviceAPI->registerChannelInstance(m_channelID, this); m_deviceAPI->registerChannelInstance(m_channelID, this);
@ -425,6 +369,7 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
rdsUpdateFixedFields(); rdsUpdateFixedFields();
rdsUpdate(true); rdsUpdate(true);
displaySettings();
displayUDPAddress(); displayUDPAddress();
applySettings(true); applySettings(true);
} }
@ -432,11 +377,7 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
BFMDemodGUI::~BFMDemodGUI() BFMDemodGUI::~BFMDemodGUI()
{ {
m_deviceAPI->removeChannelInstance(this); m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
delete m_bfmDemod; delete m_bfmDemod;
//delete m_channelMarker;
delete ui; delete ui;
} }
@ -445,6 +386,13 @@ void BFMDemodGUI::displayUDPAddress()
ui->copyAudioToUDP->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort())); ui->copyAudioToUDP->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort()));
} }
void BFMDemodGUI::updateChannelMarker()
{
m_channelMarker.blockSignals(true);
this->setWindowTitle(m_channelMarker.getTitle());
m_channelMarker.blockSignals(false);
}
void BFMDemodGUI::blockApplySettings(bool block) void BFMDemodGUI::blockApplySettings(bool block)
{ {
m_doApplySettings = !block; m_doApplySettings = !block;
@ -456,28 +404,54 @@ void BFMDemodGUI::applySettings(bool force)
{ {
setTitleColor(m_channelMarker.getColor()); setTitleColor(m_channelMarker.getColor());
m_channelizer->configure(m_channelizer->getInputMessageQueue(), BFMDemod::MsgConfigureChannelizer *msgChan = BFMDemod::MsgConfigureChannelizer::create(
requiredBW(m_rfBW[ui->rfBW->value()]), // TODO: this is where requested sample rate is specified requiredBW(BFMDemodSettings::getRFBW(ui->rfBW->value())),
m_channelMarker.getCenterFrequency()); m_channelMarker.getCenterFrequency());
m_bfmDemod->getInputMessageQueue()->push(msgChan);
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_bfmDemod->configure(m_bfmDemod->getInputMessageQueue(), BFMDemod::MsgConfigureBFMDemod* msgConfig = BFMDemod::MsgConfigureBFMDemod::create( m_settings, force);
m_rfBW[ui->rfBW->value()], m_bfmDemod->getInputMessageQueue()->push(msgConfig);
ui->afBW->value() * 1000.0,
ui->volume->value() / 10.0,
ui->squelch->value(),
ui->audioStereo->isChecked(),
ui->lsbStereo->isChecked(),
ui->showPilot->isChecked(),
ui->rds->isChecked(),
ui->copyAudioToUDP->isChecked(),
m_channelMarker.getUDPAddress(),
m_channelMarker.getUDPSendPort(),
force);
} }
} }
void BFMDemodGUI::displaySettings()
{
blockApplySettings(true);
ui->deltaFrequency->setValue(m_settings.m_inputFrequencyOffset);
ui->rfBW->setValue(BFMDemodSettings::getRFBWIndex(m_settings.m_rfBandwidth));
ui->rfBWText->setText(QString("%1 kHz").arg(m_settings.m_rfBandwidth / 1000.0));
m_channelMarker.setBandwidth(m_settings.m_rfBandwidth);
ui->afBW->setValue(m_settings.m_afBandwidth/1000.0);
ui->afBWText->setText(QString("%1 kHz").arg(m_settings.m_afBandwidth/1000.0));
ui->volume->setValue(m_settings.m_volume * 10.0);
ui->volumeText->setText(QString("%1").arg(m_settings.m_volume, 0, 'f', 1));
ui->squelch->setValue(m_settings.m_squelch);
ui->squelchText->setText(QString("%1 dB").arg(m_settings.m_squelch));
ui->audioStereo->setChecked(m_settings.m_audioStereo);
ui->lsbStereo->setChecked(m_settings.m_lsbStereo);
ui->showPilot->setChecked(m_settings.m_showPilot);
ui->rds->setChecked(m_settings.m_rdsActive);
ui->copyAudioToUDP->setChecked(m_settings.m_copyAudioToUDP);
m_channelMarker.blockSignals(true);
m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
m_channelMarker.setUDPAddress(m_settings.m_udpAddress);
m_channelMarker.setUDPSendPort(m_settings.m_udpPort);
m_channelMarker.setColor(m_settings.m_rgbColor);
setTitleColor(m_settings.m_rgbColor);
m_channelMarker.blockSignals(false);
blockApplySettings(false);
}
void BFMDemodGUI::leaveEvent(QEvent*) void BFMDemodGUI::leaveEvent(QEvent*)
{ {
blockApplySettings(true); blockApplySettings(true);
@ -541,38 +515,31 @@ void BFMDemodGUI::tick()
//qDebug() << "Pilot lock: " << m_bfmDemod->getPilotLock() << ":" << m_bfmDemod->getPilotLevel(); TODO: update a GUI item with status //qDebug() << "Pilot lock: " << m_bfmDemod->getPilotLock() << ":" << m_bfmDemod->getPilotLevel(); TODO: update a GUI item with status
} }
void BFMDemodGUI::channelSampleRateChanged()
{
m_rate = m_bfmDemod->getSampleRate();
ui->glSpectrum->setCenterFrequency(m_rate / 4);
ui->glSpectrum->setSampleRate(m_rate / 2);
}
void BFMDemodGUI::rdsUpdateFixedFields() void BFMDemodGUI::rdsUpdateFixedFields()
{ {
ui->g00Label->setText(m_rdsParser.rds_group_acronym_tags[0].c_str()); ui->g00Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[0].c_str());
ui->g01Label->setText(m_rdsParser.rds_group_acronym_tags[1].c_str()); ui->g01Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[1].c_str());
ui->g02Label->setText(m_rdsParser.rds_group_acronym_tags[2].c_str()); ui->g02Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[2].c_str());
ui->g03Label->setText(m_rdsParser.rds_group_acronym_tags[3].c_str()); ui->g03Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[3].c_str());
ui->g04Label->setText(m_rdsParser.rds_group_acronym_tags[4].c_str()); ui->g04Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[4].c_str());
//ui->g05Label->setText(m_rdsParser.rds_group_acronym_tags[5].c_str()); //ui->g05Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[5].c_str());
//ui->g06Label->setText(m_rdsParser.rds_group_acronym_tags[6].c_str()); //ui->g06Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[6].c_str());
//ui->g07Label->setText(m_rdsParser.rds_group_acronym_tags[7].c_str()); //ui->g07Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[7].c_str());
ui->g08Label->setText(m_rdsParser.rds_group_acronym_tags[8].c_str()); ui->g08Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[8].c_str());
ui->g09Label->setText(m_rdsParser.rds_group_acronym_tags[9].c_str()); ui->g09Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[9].c_str());
ui->g14Label->setText(m_rdsParser.rds_group_acronym_tags[14].c_str()); ui->g14Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[14].c_str());
ui->g00CountLabel->setText(m_rdsParser.rds_group_acronym_tags[0].c_str()); ui->g00CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[0].c_str());
ui->g01CountLabel->setText(m_rdsParser.rds_group_acronym_tags[1].c_str()); ui->g01CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[1].c_str());
ui->g02CountLabel->setText(m_rdsParser.rds_group_acronym_tags[2].c_str()); ui->g02CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[2].c_str());
ui->g03CountLabel->setText(m_rdsParser.rds_group_acronym_tags[3].c_str()); ui->g03CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[3].c_str());
ui->g04CountLabel->setText(m_rdsParser.rds_group_acronym_tags[4].c_str()); ui->g04CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[4].c_str());
ui->g05CountLabel->setText(m_rdsParser.rds_group_acronym_tags[5].c_str()); ui->g05CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[5].c_str());
ui->g06CountLabel->setText(m_rdsParser.rds_group_acronym_tags[6].c_str()); ui->g06CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[6].c_str());
ui->g07CountLabel->setText(m_rdsParser.rds_group_acronym_tags[7].c_str()); ui->g07CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[7].c_str());
ui->g08CountLabel->setText(m_rdsParser.rds_group_acronym_tags[8].c_str()); ui->g08CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[8].c_str());
ui->g09CountLabel->setText(m_rdsParser.rds_group_acronym_tags[9].c_str()); ui->g09CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[9].c_str());
ui->g14CountLabel->setText(m_rdsParser.rds_group_acronym_tags[14].c_str()); ui->g14CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[14].c_str());
} }
void BFMDemodGUI::rdsUpdate(bool force) void BFMDemodGUI::rdsUpdate(bool force)
@ -591,21 +558,21 @@ void BFMDemodGUI::rdsUpdate(bool force)
} }
// PI group // PI group
if (m_rdsParser.m_pi_updated || force) if (m_bfmDemod->getRDSParser().m_pi_updated || force)
{ {
ui->piLabel->setStyleSheet("QLabel { background-color : green; }"); ui->piLabel->setStyleSheet("QLabel { background-color : green; }");
ui->piCountText->setNum((int) m_rdsParser.m_pi_count); ui->piCountText->setNum((int) m_bfmDemod->getRDSParser().m_pi_count);
QString pistring(str(boost::format("%04X") % m_rdsParser.m_pi_program_identification).c_str()); QString pistring(str(boost::format("%04X") % m_bfmDemod->getRDSParser().m_pi_program_identification).c_str());
ui->piText->setText(pistring); ui->piText->setText(pistring);
if (m_rdsParser.m_pi_traffic_program) { if (m_bfmDemod->getRDSParser().m_pi_traffic_program) {
ui->piTPIndicator->setStyleSheet("QLabel { background-color : green; }"); ui->piTPIndicator->setStyleSheet("QLabel { background-color : green; }");
} else { } else {
ui->piTPIndicator->setStyleSheet("QLabel { background:rgb(79,79,79); }"); ui->piTPIndicator->setStyleSheet("QLabel { background:rgb(79,79,79); }");
} }
ui->piType->setText(QString(m_rdsParser.pty_table[m_rdsParser.m_pi_program_type].c_str())); ui->piType->setText(QString(m_bfmDemod->getRDSParser().pty_table[m_bfmDemod->getRDSParser().m_pi_program_type].c_str()));
ui->piCoverage->setText(QString(m_rdsParser.coverage_area_codes[m_rdsParser.m_pi_area_coverage_index].c_str())); ui->piCoverage->setText(QString(m_bfmDemod->getRDSParser().coverage_area_codes[m_bfmDemod->getRDSParser().m_pi_area_coverage_index].c_str()));
} }
else else
{ {
@ -613,29 +580,29 @@ void BFMDemodGUI::rdsUpdate(bool force)
} }
// G0 group // G0 group
if (m_rdsParser.m_g0_updated || force) if (m_bfmDemod->getRDSParser().m_g0_updated || force)
{ {
ui->g00Label->setStyleSheet("QLabel { background-color : green; }"); ui->g00Label->setStyleSheet("QLabel { background-color : green; }");
ui->g00CountText->setNum((int) m_rdsParser.m_g0_count); ui->g00CountText->setNum((int) m_bfmDemod->getRDSParser().m_g0_count);
if (m_rdsParser.m_g0_psn_bitmap == 0b1111) { if (m_bfmDemod->getRDSParser().m_g0_psn_bitmap == 0b1111) {
ui->g00ProgServiceName->setText(QString(m_rdsParser.m_g0_program_service_name)); ui->g00ProgServiceName->setText(QString(m_bfmDemod->getRDSParser().m_g0_program_service_name));
} }
if (m_rdsParser.m_g0_traffic_announcement) { if (m_bfmDemod->getRDSParser().m_g0_traffic_announcement) {
ui->g00TrafficAnnouncement->setStyleSheet("QLabel { background-color : green; }"); ui->g00TrafficAnnouncement->setStyleSheet("QLabel { background-color : green; }");
} else { } else {
ui->g00TrafficAnnouncement->setStyleSheet("QLabel { background:rgb(79,79,79); }"); ui->g00TrafficAnnouncement->setStyleSheet("QLabel { background:rgb(79,79,79); }");
} }
ui->g00MusicSpeech->setText(QString((m_rdsParser.m_g0_music_speech ? "Music" : "Speech"))); ui->g00MusicSpeech->setText(QString((m_bfmDemod->getRDSParser().m_g0_music_speech ? "Music" : "Speech")));
ui->g00MonoStereo->setText(QString((m_rdsParser.m_g0_mono_stereo ? "Mono" : "Stereo"))); ui->g00MonoStereo->setText(QString((m_bfmDemod->getRDSParser().m_g0_mono_stereo ? "Mono" : "Stereo")));
if (m_rdsParser.m_g0_af_updated) if (m_bfmDemod->getRDSParser().m_g0_af_updated)
{ {
ui->g00AltFrequenciesBox->clear(); ui->g00AltFrequenciesBox->clear();
for (std::set<double>::iterator it = m_rdsParser.m_g0_alt_freq.begin(); it != m_rdsParser.m_g0_alt_freq.end(); ++it) for (std::set<double>::iterator it = m_bfmDemod->getRDSParser().m_g0_alt_freq.begin(); it != m_bfmDemod->getRDSParser().m_g0_alt_freq.end(); ++it)
{ {
if (*it > 76.0) if (*it > 76.0)
{ {
@ -654,20 +621,20 @@ void BFMDemodGUI::rdsUpdate(bool force)
} }
// G1 group // G1 group
if (m_rdsParser.m_g1_updated || force) if (m_bfmDemod->getRDSParser().m_g1_updated || force)
{ {
ui->g01Label->setStyleSheet("QLabel { background-color : green; }"); ui->g01Label->setStyleSheet("QLabel { background-color : green; }");
ui->g01CountText->setNum((int) m_rdsParser.m_g1_count); ui->g01CountText->setNum((int) m_bfmDemod->getRDSParser().m_g1_count);
if ((m_rdsParser.m_g1_country_page_index >= 0) && (m_rdsParser.m_g1_country_index >= 0)) { if ((m_bfmDemod->getRDSParser().m_g1_country_page_index >= 0) && (m_bfmDemod->getRDSParser().m_g1_country_index >= 0)) {
ui->g01CountryCode->setText(QString((m_rdsParser.pi_country_codes[m_rdsParser.m_g1_country_page_index][m_rdsParser.m_g1_country_index]).c_str())); ui->g01CountryCode->setText(QString((m_bfmDemod->getRDSParser().pi_country_codes[m_bfmDemod->getRDSParser().m_g1_country_page_index][m_bfmDemod->getRDSParser().m_g1_country_index]).c_str()));
} }
if (m_rdsParser.m_g1_language_index >= 0) { if (m_bfmDemod->getRDSParser().m_g1_language_index >= 0) {
ui->g01Language->setText(QString(m_rdsParser.language_codes[m_rdsParser.m_g1_language_index].c_str())); ui->g01Language->setText(QString(m_bfmDemod->getRDSParser().language_codes[m_bfmDemod->getRDSParser().m_g1_language_index].c_str()));
} }
ui->g01DHM->setText(QString(str(boost::format("%id:%i:%i") % m_rdsParser.m_g1_pin_day % m_rdsParser.m_g1_pin_hour % m_rdsParser.m_g1_pin_minute).c_str())); ui->g01DHM->setText(QString(str(boost::format("%id:%i:%i") % m_bfmDemod->getRDSParser().m_g1_pin_day % m_bfmDemod->getRDSParser().m_g1_pin_hour % m_bfmDemod->getRDSParser().m_g1_pin_minute).c_str()));
} }
else else
{ {
@ -675,11 +642,11 @@ void BFMDemodGUI::rdsUpdate(bool force)
} }
// G2 group // G2 group
if (m_rdsParser.m_g2_updated || force) if (m_bfmDemod->getRDSParser().m_g2_updated || force)
{ {
ui->g02Label->setStyleSheet("QLabel { background-color : green; }"); ui->g02Label->setStyleSheet("QLabel { background-color : green; }");
ui->g02CountText->setNum((int) m_rdsParser.m_g2_count); ui->g02CountText->setNum((int) m_bfmDemod->getRDSParser().m_g2_count);
ui->go2Text->setText(QString(m_rdsParser.m_g2_radiotext)); ui->go2Text->setText(QString(m_bfmDemod->getRDSParser().m_g2_radiotext));
} }
else else
{ {
@ -687,11 +654,11 @@ void BFMDemodGUI::rdsUpdate(bool force)
} }
// G3 group // G3 group
if (m_rdsParser.m_g3_updated || force) if (m_bfmDemod->getRDSParser().m_g3_updated || force)
{ {
ui->g03Label->setStyleSheet("QLabel { background-color : green; }"); ui->g03Label->setStyleSheet("QLabel { background-color : green; }");
ui->g03CountText->setNum((int) m_rdsParser.m_g3_count); ui->g03CountText->setNum((int) m_bfmDemod->getRDSParser().m_g3_count);
std::string g3str = str(boost::format("%02X%c %04X %04X") % m_rdsParser.m_g3_appGroup % (m_rdsParser.m_g3_groupB ? 'B' : 'A') % m_rdsParser.m_g3_message % m_rdsParser.m_g3_aid); std::string g3str = str(boost::format("%02X%c %04X %04X") % m_bfmDemod->getRDSParser().m_g3_appGroup % (m_bfmDemod->getRDSParser().m_g3_groupB ? 'B' : 'A') % m_bfmDemod->getRDSParser().m_g3_message % m_bfmDemod->getRDSParser().m_g3_aid);
ui->g03Data->setText(QString(g3str.c_str())); ui->g03Data->setText(QString(g3str.c_str()));
} }
else else
@ -700,12 +667,12 @@ void BFMDemodGUI::rdsUpdate(bool force)
} }
// G4 group // G4 group
if (m_rdsParser.m_g4_updated || force) if (m_bfmDemod->getRDSParser().m_g4_updated || force)
{ {
ui->g04Label->setStyleSheet("QLabel { background-color : green; }"); ui->g04Label->setStyleSheet("QLabel { background-color : green; }");
ui->g04CountText->setNum((int) m_rdsParser.m_g4_count); ui->g04CountText->setNum((int) m_bfmDemod->getRDSParser().m_g4_count);
std::string time = str(boost::format("%02i.%02i.%4i, %02i:%02i (%+.1fh)")\ std::string time = str(boost::format("%02i.%02i.%4i, %02i:%02i (%+.1fh)")\
% m_rdsParser.m_g4_day % m_rdsParser.m_g4_month % (1900 + m_rdsParser.m_g4_year) % m_rdsParser.m_g4_hours % m_rdsParser.m_g4_minutes % m_rdsParser.m_g4_local_time_offset); % m_bfmDemod->getRDSParser().m_g4_day % m_bfmDemod->getRDSParser().m_g4_month % (1900 + m_bfmDemod->getRDSParser().m_g4_year) % m_bfmDemod->getRDSParser().m_g4_hours % m_bfmDemod->getRDSParser().m_g4_minutes % m_bfmDemod->getRDSParser().m_g4_local_time_offset);
ui->g04Time->setText(QString(time.c_str())); ui->g04Time->setText(QString(time.c_str()));
} }
else else
@ -714,42 +681,42 @@ void BFMDemodGUI::rdsUpdate(bool force)
} }
// G5 group // G5 group
if (m_rdsParser.m_g5_updated || force) if (m_bfmDemod->getRDSParser().m_g5_updated || force)
{ {
ui->g05CountText->setNum((int) m_rdsParser.m_g5_count); ui->g05CountText->setNum((int) m_bfmDemod->getRDSParser().m_g5_count);
} }
// G6 group // G6 group
if (m_rdsParser.m_g6_updated || force) if (m_bfmDemod->getRDSParser().m_g6_updated || force)
{ {
ui->g06CountText->setNum((int) m_rdsParser.m_g6_count); ui->g06CountText->setNum((int) m_bfmDemod->getRDSParser().m_g6_count);
} }
// G7 group // G7 group
if (m_rdsParser.m_g7_updated || force) if (m_bfmDemod->getRDSParser().m_g7_updated || force)
{ {
ui->g07CountText->setNum((int) m_rdsParser.m_g7_count); ui->g07CountText->setNum((int) m_bfmDemod->getRDSParser().m_g7_count);
} }
// G8 group // G8 group
if (m_rdsParser.m_g8_updated || force) if (m_bfmDemod->getRDSParser().m_g8_updated || force)
{ {
ui->g08Label->setStyleSheet("QLabel { background-color : green; }"); ui->g08Label->setStyleSheet("QLabel { background-color : green; }");
ui->g08CountText->setNum((int) m_rdsParser.m_g8_count); ui->g08CountText->setNum((int) m_bfmDemod->getRDSParser().m_g8_count);
std::ostringstream os; std::ostringstream os;
os << (m_rdsParser.m_g8_sign ? "-" : "+") << m_rdsParser.m_g8_extent + 1; os << (m_bfmDemod->getRDSParser().m_g8_sign ? "-" : "+") << m_bfmDemod->getRDSParser().m_g8_extent + 1;
ui->g08Extent->setText(QString(os.str().c_str())); ui->g08Extent->setText(QString(os.str().c_str()));
int event_line = RDSTMC::get_tmc_event_code_index(m_rdsParser.m_g8_event, 1); int event_line = RDSTMC::get_tmc_event_code_index(m_bfmDemod->getRDSParser().m_g8_event, 1);
ui->g08TMCEvent->setText(QString(RDSTMC::get_tmc_events(event_line, 1).c_str())); ui->g08TMCEvent->setText(QString(RDSTMC::get_tmc_events(event_line, 1).c_str()));
QString pistring(str(boost::format("%04X") % m_rdsParser.m_g8_location).c_str()); QString pistring(str(boost::format("%04X") % m_bfmDemod->getRDSParser().m_g8_location).c_str());
ui->g08Location->setText(pistring); ui->g08Location->setText(pistring);
if (m_rdsParser.m_g8_label_index >= 0) { if (m_bfmDemod->getRDSParser().m_g8_label_index >= 0) {
ui->g08Description->setText(QString(m_rdsParser.label_descriptions[m_rdsParser.m_g8_label_index].c_str())); ui->g08Description->setText(QString(m_bfmDemod->getRDSParser().label_descriptions[m_bfmDemod->getRDSParser().m_g8_label_index].c_str()));
} }
ui->g08Content->setNum(m_rdsParser.m_g8_content); ui->g08Content->setNum(m_bfmDemod->getRDSParser().m_g8_content);
} }
else else
{ {
@ -757,11 +724,11 @@ void BFMDemodGUI::rdsUpdate(bool force)
} }
// G9 group // G9 group
if (m_rdsParser.m_g9_updated || force) if (m_bfmDemod->getRDSParser().m_g9_updated || force)
{ {
ui->g09Label->setStyleSheet("QLabel { background-color : green; }"); ui->g09Label->setStyleSheet("QLabel { background-color : green; }");
ui->g09CountText->setNum((int) m_rdsParser.m_g9_count); ui->g09CountText->setNum((int) m_bfmDemod->getRDSParser().m_g9_count);
std::string g9str = str(boost::format("%02X %04X %04X %02X %04X") % m_rdsParser.m_g9_varA % m_rdsParser.m_g9_cA % m_rdsParser.m_g9_dA % m_rdsParser.m_g9_varB % m_rdsParser.m_g9_dB); std::string g9str = str(boost::format("%02X %04X %04X %02X %04X") % m_bfmDemod->getRDSParser().m_g9_varA % m_bfmDemod->getRDSParser().m_g9_cA % m_bfmDemod->getRDSParser().m_g9_dA % m_bfmDemod->getRDSParser().m_g9_varB % m_bfmDemod->getRDSParser().m_g9_dB);
ui->g09Data->setText(QString(g9str.c_str())); ui->g09Data->setText(QString(g9str.c_str()));
} }
else else
@ -770,18 +737,18 @@ void BFMDemodGUI::rdsUpdate(bool force)
} }
// G14 group // G14 group
if (m_rdsParser.m_g14_updated || force) if (m_bfmDemod->getRDSParser().m_g14_updated || force)
{ {
ui->g14CountText->setNum((int) m_rdsParser.m_g14_count); ui->g14CountText->setNum((int) m_bfmDemod->getRDSParser().m_g14_count);
if (m_rdsParser.m_g14_data_available) if (m_bfmDemod->getRDSParser().m_g14_data_available)
{ {
ui->g14Label->setStyleSheet("QLabel { background-color : green; }"); ui->g14Label->setStyleSheet("QLabel { background-color : green; }");
m_g14ComboIndex.clear(); m_g14ComboIndex.clear();
ui->g14ProgServiceNames->clear(); ui->g14ProgServiceNames->clear();
RDSParser::psns_map_t::iterator it = m_rdsParser.m_g14_program_service_names.begin(); RDSParser::psns_map_t::iterator it = m_bfmDemod->getRDSParser().m_g14_program_service_names.begin();
const RDSParser::psns_map_t::iterator itEnd = m_rdsParser.m_g14_program_service_names.end(); const RDSParser::psns_map_t::iterator itEnd = m_bfmDemod->getRDSParser().m_g14_program_service_names.end();
int i = 0; int i = 0;
for (; it != itEnd; ++it, i++) for (; it != itEnd; ++it, i++)
@ -797,12 +764,11 @@ void BFMDemodGUI::rdsUpdate(bool force)
} }
} }
m_rdsParser.clearUpdateFlags(); m_bfmDemod->getRDSParser().clearUpdateFlags();
} }
void BFMDemodGUI::changeFrequency(qint64 f) void BFMDemodGUI::changeFrequency(qint64 f)
{ {
qint64 df = m_channelMarker.getCenterFrequency(); qint64 df = m_channelMarker.getCenterFrequency();
qDebug() << "BFMDemodGUI::changeFrequency: " << f - df; qDebug() << "BFMDemodGUI::changeFrequency: " << f - df;
// TODO: in the future it should be able to set the center frequency of the sample source this channel plugin is linked to
} }

View File

@ -18,16 +18,16 @@
#ifndef INCLUDE_BFMDEMODGUI_H #ifndef INCLUDE_BFMDEMODGUI_H
#define INCLUDE_BFMDEMODGUI_H #define INCLUDE_BFMDEMODGUI_H
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
#include "bfmdemodsettings.h"
#include "rdsparser.h"
class PluginAPI; class PluginAPI;
class DeviceSourceAPI; class DeviceSourceAPI;
class RDSParser;
class ThreadedBasebandSampleSink; class ThreadedBasebandSampleSink;
class DownChannelizer; class DownChannelizer;
@ -38,7 +38,7 @@ namespace Ui {
class BFMDemodGUI; class BFMDemodGUI;
} }
class BFMDemodGUI : public RollupWidget, public PluginInstanceUI { class BFMDemodGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:
@ -60,7 +60,6 @@ public:
private slots: private slots:
void channelMarkerChanged(); void channelMarkerChanged();
void channelSampleRateChanged();
void on_deltaFrequency_changed(qint64 value); void on_deltaFrequency_changed(qint64 value);
void on_rfBW_valueChanged(int value); void on_rfBW_valueChanged(int value);
void on_afBW_valueChanged(int value); void on_afBW_valueChanged(int value);
@ -78,6 +77,7 @@ private slots:
void on_g14AltFrequencies_activated(int index); void on_g14AltFrequencies_activated(int index);
void onWidgetRolled(QWidget* widget, bool rollDown); void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p); void onMenuDialogCalled(const QPoint& p);
void handleInputMessages();
void tick(); void tick();
private: private:
@ -85,13 +85,11 @@ private:
PluginAPI* m_pluginAPI; PluginAPI* m_pluginAPI;
DeviceSourceAPI* m_deviceAPI; DeviceSourceAPI* m_deviceAPI;
ChannelMarker m_channelMarker; ChannelMarker m_channelMarker;
BFMDemodSettings m_settings;
bool m_doApplySettings; bool m_doApplySettings;
int m_rdsTimerCount; int m_rdsTimerCount;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
SpectrumVis* m_spectrumVis; SpectrumVis* m_spectrumVis;
RDSParser m_rdsParser;
BFMDemod* m_bfmDemod; BFMDemod* m_bfmDemod;
MovingAverage<double> m_channelPowerDbAvg; MovingAverage<double> m_channelPowerDbAvg;
@ -99,14 +97,14 @@ private:
std::vector<unsigned int> m_g14ComboIndex; std::vector<unsigned int> m_g14ComboIndex;
MessageQueue m_inputMessageQueue; MessageQueue m_inputMessageQueue;
static const int m_rfBW[];
explicit BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent = NULL); explicit BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent = NULL);
virtual ~BFMDemodGUI(); virtual ~BFMDemodGUI();
void blockApplySettings(bool block); void blockApplySettings(bool block);
void applySettings(bool force = false); void applySettings(bool force = false);
void displaySettings();
void displayUDPAddress(); void displayUDPAddress();
void updateChannelMarker();
void rdsUpdate(bool force); void rdsUpdate(bool force);
void rdsUpdateFixedFields(); void rdsUpdateFixedFields();

View File

@ -0,0 +1,154 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QColor>
#include "dsp/dspengine.h"
#include "util/simpleserializer.h"
#include "settings/serializable.h"
#include "bfmdemodsettings.h"
const int BFMDemodSettings::m_nbRFBW = 9;
const int BFMDemodSettings::m_rfBW[] = {
80000, 100000, 120000, 140000, 160000, 180000, 200000, 220000, 250000
};
BFMDemodSettings::BFMDemodSettings() :
m_channelMarker(0),
m_spectrumGUI(0)
{
resetToDefaults();
}
void BFMDemodSettings::resetToDefaults()
{
m_inputSampleRate = 384000;
m_inputFrequencyOffset = 0;
m_rfBandwidth = getRFBW(5);
m_afBandwidth = 15000;
m_volume = 2.0;
m_squelch = -60.0;
m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
m_audioStereo = false;
m_lsbStereo = false;
m_showPilot = false;
m_rdsActive = false;
m_copyAudioToUDP = false;
m_udpAddress = "127.0.0.1";
m_udpPort = 9999;
m_rgbColor = QColor(80, 120, 228).rgb();
}
QByteArray BFMDemodSettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_inputFrequencyOffset);
s.writeS32(2, getRFBWIndex(m_rfBandwidth));
s.writeS32(3, m_afBandwidth/1000.0);
s.writeS32(4, m_volume*10.0);
s.writeS32(5, m_squelch);
s.writeU32(7, m_rgbColor);
if (m_spectrumGUI) {
s.writeBlob(8, m_spectrumGUI->serialize());
}
s.writeBool(9, m_audioStereo);
s.writeBool(10, m_lsbStereo);
if (m_channelMarker) {
s.writeBlob(11, m_channelMarker->serialize());
}
return s.final();
}
bool BFMDemodSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1)
{
QByteArray bytetmp;
qint32 tmp;
QString strtmp;
d.readS32(1, &tmp, 0);
m_inputFrequencyOffset = tmp;
d.readS32(2, &tmp, 4);
m_rfBandwidth = getRFBW(tmp);
d.readS32(3, &tmp, 3);
m_afBandwidth = tmp * 1000.0;
d.readS32(4, &tmp, 20);
m_volume = tmp * 0.1;
d.readS32(5, &tmp, -60);
m_squelch = tmp;
d.readU32(7, &m_rgbColor);
d.readBlob(8, &bytetmp);
if (m_spectrumGUI) {
m_spectrumGUI->deserialize(bytetmp);
}
d.readBool(9, &m_audioStereo, false);
d.readBool(10, &m_lsbStereo, false);
d.readBlob(11, &bytetmp);
if (m_channelMarker) {
m_channelMarker->deserialize(bytetmp);
}
return true;
}
else
{
resetToDefaults();
return false;
}
}
int BFMDemodSettings::getRFBW(int index)
{
if (index < 0) {
return m_rfBW[0];
} else if (index < m_nbRFBW) {
return m_rfBW[index];
} else {
return m_rfBW[m_nbRFBW-1];
}
}
int BFMDemodSettings::getRFBWIndex(int rfbw)
{
for (int i = 0; i < m_nbRFBW; i++)
{
if (rfbw <= m_rfBW[i])
{
return i;
}
}
return m_nbRFBW-1;
}

View File

@ -0,0 +1,58 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_CHANNELRX_DEMODBFM_BFMDEMODSETTINGS_H_
#define PLUGINS_CHANNELRX_DEMODBFM_BFMDEMODSETTINGS_H_
class Serializable;
struct BFMDemodSettings
{
int m_inputSampleRate;
qint64 m_inputFrequencyOffset;
Real m_rfBandwidth;
Real m_afBandwidth;
Real m_volume;
Real m_squelch;
quint32 m_audioSampleRate;
bool m_audioStereo;
bool m_lsbStereo;
bool m_showPilot;
bool m_rdsActive;
bool m_copyAudioToUDP;
QString m_udpAddress;
quint16 m_udpPort;
quint32 m_rgbColor;
Serializable *m_channelMarker;
Serializable *m_spectrumGUI;
static const int m_nbRFBW;
static const int m_rfBW[];
BFMDemodSettings();
void resetToDefaults();
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
void setSpectrumGUI(Serializable *spectrumGUI) { m_spectrumGUI = spectrumGUI; }
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
static int getRFBW(int index);
static int getRFBWIndex(int rfbw);
};
#endif /* PLUGINS_CHANNELRX_DEMODBFM_BFMDEMODSETTINGS_H_ */

View File

@ -24,7 +24,7 @@
const PluginDescriptor BFMPlugin::m_pluginDescriptor = { const PluginDescriptor BFMPlugin::m_pluginDescriptor = {
QString("Broadcast FM Demodulator"), QString("Broadcast FM Demodulator"),
QString("3.6.1"), QString("3.7.3"),
QString("(c) Edouard Griffiths, F4EXB"), QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"), QString("https://github.com/f4exb/sdrangel"),
true, true,
@ -50,7 +50,7 @@ void BFMPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerRxChannel(BFMDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(BFMDemodGUI::m_channelID, this);
} }
PluginInstanceUI* BFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) PluginInstanceGUI* BFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{ {
if(channelName == BFMDemodGUI::m_channelID) if(channelName == BFMDemodGUI::m_channelID)
{ {

View File

@ -34,7 +34,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -30,6 +30,7 @@ CONFIG(Debug):build_subdir = debug
SOURCES += bfmdemod.cpp\ SOURCES += bfmdemod.cpp\
bfmdemodgui.cpp\ bfmdemodgui.cpp\
bfmdemodsettings.cpp\
bfmplugin.cpp\ bfmplugin.cpp\
rdsdemod.cpp\ rdsdemod.cpp\
rdsdecoder.cpp\ rdsdecoder.cpp\
@ -38,6 +39,7 @@ SOURCES += bfmdemod.cpp\
HEADERS += bfmdemod.h\ HEADERS += bfmdemod.h\
bfmdemodgui.h\ bfmdemodgui.h\
bfmdemodsettings.h\
bfmplugin.h\ bfmplugin.h\
rdsdemod.h\ rdsdemod.h\
rdsdecoder.h\ rdsdecoder.h\

View File

@ -22,6 +22,10 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#undef M_PI
#define M_PI 3.14159265358979323846
#undef M_PI_2
#define M_PI_2 1.57079632679489661923
const Real RDSDemod::m_pllBeta = 50; const Real RDSDemod::m_pllBeta = 50;
const Real RDSDemod::m_fsc = 1187.5; const Real RDSDemod::m_fsc = 1187.5;
@ -77,7 +81,7 @@ bool RDSDemod::process(Real demod, bool& bit)
m_parms.clock_offset = 0; m_parms.clock_offset = 0;
}*/ }*/
m_parms.subcarr_phi += (2 * M_PI * m_fsc) / (Real) m_srate; m_parms.subcarr_phi += (2 * M_PI * m_fsc) / (Real) m_srate;
m_parms.clock_phi = m_parms.subcarr_phi + m_parms.clock_offset; m_parms.clock_phi = m_parms.subcarr_phi + m_parms.clock_offset;
// Clock phase recovery // Clock phase recovery

View File

@ -4,6 +4,8 @@ set(dsddemod_SOURCES
dsddemod.cpp dsddemod.cpp
dsddemodgui.cpp dsddemodgui.cpp
dsddemodplugin.cpp dsddemodplugin.cpp
dsddemodbaudrates.cpp
dsddemodsettings.cpp
dsddecoder.cpp dsddecoder.cpp
) )
@ -11,6 +13,8 @@ set(dsddemod_HEADERS
dsddemod.h dsddemod.h
dsddemodgui.h dsddemodgui.h
dsddemodplugin.h dsddemodplugin.h
dsddemodbaudrates.h
dsddemodsettings.h
dsddecoder.h dsddecoder.h
) )

View File

@ -40,12 +40,16 @@ CONFIG(Debug):build_subdir = debug
SOURCES = dsddecoder.cpp\ SOURCES = dsddecoder.cpp\
dsddemod.cpp\ dsddemod.cpp\
dsddemodgui.cpp\ dsddemodgui.cpp\
dsddemodplugin.cpp dsddemodplugin.cpp\
dsddemodbaudrates.cpp\
dsddemodsettings.cpp
HEADERS = dsddecoder.h\ HEADERS = dsddecoder.h\
dsddemod.h\ dsddemod.h\
dsddemodgui.h\ dsddemodgui.h\
dsddemodplugin.h dsddemodplugin.h\
dsddemodbaudrates.h\
dsddemodsettings.h
FORMS = dsddemodgui.ui FORMS = dsddemodgui.ui

View File

@ -15,51 +15,48 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#include "../../channelrx/demoddsd/dsddemod.h"
#include <QTime> #include <QTime>
#include <QDebug> #include <QDebug>
#include <stdio.h> #include <stdio.h>
#include <complex.h> #include <complex.h>
#include <dsp/downchannelizer.h> #include <dsp/downchannelizer.h>
#include "audio/audiooutput.h" #include "audio/audiooutput.h"
#include "dsp/pidcontroller.h" #include "dsp/pidcontroller.h"
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "dsddemodgui.h" #include "dsp/threadedbasebandsamplesink.h"
#include <dsp/downchannelizer.h>
#include <device/devicesourceapi.h>
#include "dsddemod.h"
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemod, Message) MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemod, Message)
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureMyPosition, Message) MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureMyPosition, Message)
const int DSDDemod::m_udpBlockSize = 512; const int DSDDemod::m_udpBlockSize = 512;
DSDDemod::DSDDemod(BasebandSampleSink* sampleSink) : DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) :
m_sampleCount(0), m_deviceAPI(deviceAPI),
m_squelchCount(0), m_interpolatorDistance(0.0f),
m_squelchOpen(false), m_interpolatorDistanceRemain(0.0f),
m_sampleCount(0),
m_squelchCount(0),
m_squelchGate(0),
m_squelchLevel(1e-4),
m_squelchOpen(false),
m_movingAverage(40, 0), m_movingAverage(40, 0),
m_fmExcursion(24), m_fmExcursion(24),
m_audioFifo1(48000), m_audioFifo1(48000),
m_audioFifo2(48000), m_audioFifo2(48000),
m_scope(sampleSink), m_scope(0),
m_scopeEnabled(true), m_scopeEnabled(true),
m_dsdDecoder(), m_dsdDecoder(),
m_settingsMutex(QMutex::Recursive) m_settingsMutex(QMutex::Recursive)
{ {
setObjectName("DSDDemod"); setObjectName("DSDDemod");
m_config.m_inputSampleRate = 96000;
m_config.m_inputFrequencyOffset = 0;
m_config.m_rfBandwidth = 100;
m_config.m_demodGain = 100;
m_config.m_fmDeviation = 100;
m_config.m_squelchGate = 5; // 10s of ms at 48000 Hz sample rate. Corresponds to 2400 for AGC attack
m_config.m_squelch = -30.0;
m_config.m_volume = 1.0;
m_config.m_baudRate = 4800;
m_config.m_audioMute = false;
m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
m_config.m_enableCosineFiltering = false;
m_audioBuffer.resize(1<<14); m_audioBuffer.resize(1<<14);
m_audioBufferFill = 0; m_audioBufferFill = 0;
@ -75,11 +72,15 @@ DSDDemod::DSDDemod(BasebandSampleSink* sampleSink) :
DSPEngine::instance()->addAudioSink(&m_audioFifo1); DSPEngine::instance()->addAudioSink(&m_audioFifo1);
DSPEngine::instance()->addAudioSink(&m_audioFifo2); DSPEngine::instance()->addAudioSink(&m_audioFifo2);
m_udpBufferAudio = new UDPSink<AudioSample>(this, m_udpBlockSize, m_config.m_udpPort); m_udpBufferAudio = new UDPSink<AudioSample>(this, m_udpBlockSize, m_settings.m_udpPort);
m_audioFifo1.setUDPSink(m_udpBufferAudio); m_audioFifo1.setUDPSink(m_udpBufferAudio);
m_audioFifo2.setUDPSink(m_udpBufferAudio); m_audioFifo2.setUDPSink(m_udpBufferAudio);
apply(true); m_channelizer = new DownChannelizer(this);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
applySettings(m_settings, true);
} }
DSDDemod::~DSDDemod() DSDDemod::~DSDDemod()
@ -88,47 +89,10 @@ DSDDemod::~DSDDemod()
DSPEngine::instance()->removeAudioSink(&m_audioFifo1); DSPEngine::instance()->removeAudioSink(&m_audioFifo1);
DSPEngine::instance()->removeAudioSink(&m_audioFifo2); DSPEngine::instance()->removeAudioSink(&m_audioFifo2);
delete m_udpBufferAudio; delete m_udpBufferAudio;
}
void DSDDemod::configure(MessageQueue* messageQueue, m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
int rfBandwidth, delete m_threadedChannelizer;
int demodGain, delete m_channelizer;
int fmDeviation,
int volume,
int baudRate,
int squelchGate,
Real squelch,
bool audioMute,
bool enableCosineFiltering,
bool syncOrConstellation,
bool slot1On,
bool slot2On,
bool tdmaStereo,
bool pllLock,
bool udpCopyAudio,
const QString& udpAddress,
quint16 udpPort,
bool force)
{
Message* cmd = MsgConfigureDSDDemod::create(rfBandwidth,
demodGain,
fmDeviation,
volume,
baudRate,
squelchGate,
squelch,
audioMute,
enableCosineFiltering,
syncOrConstellation,
slot1On,
slot2On,
tdmaStereo,
pllLock,
udpCopyAudio,
udpAddress,
udpPort,
force);
messageQueue->push(cmd);
} }
void DSDDemod::configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude) void DSDDemod::configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude)
@ -168,7 +132,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
m_magsqCount++; m_magsqCount++;
Real demod = 32768.0f * m_phaseDiscri.phaseDiscriminator(ci) * ((float) m_running.m_demodGain / 100.0f); Real demod = 32768.0f * m_phaseDiscri.phaseDiscriminator(ci) * m_settings.m_demodGain;
m_sampleCount++; m_sampleCount++;
// AF processing // AF processing
@ -205,7 +169,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
m_dsdDecoder.pushSample(sample); m_dsdDecoder.pushSample(sample);
if (m_running.m_enableCosineFiltering) { // show actual input to FSK demod if (m_settings.m_enableCosineFiltering) { // show actual input to FSK demod
sample = m_dsdDecoder.getFilteredSample(); sample = m_dsdDecoder.getFilteredSample();
} }
@ -223,7 +187,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
delayedSample = m_sampleBuffer[m_sampleBufferIndex - samplesPerSymbol]; delayedSample = m_sampleBuffer[m_sampleBufferIndex - samplesPerSymbol];
} }
if (m_running.m_syncOrConstellation) if (m_settings.m_syncOrConstellation)
{ {
Sample s(sample, m_dsdDecoder.getSymbolSyncSample()); Sample s(sample, m_dsdDecoder.getSymbolSyncSample());
m_scopeSampleBuffer.push_back(s); m_scopeSampleBuffer.push_back(s);
@ -236,30 +200,30 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
if (DSPEngine::instance()->hasDVSerialSupport()) if (DSPEngine::instance()->hasDVSerialSupport())
{ {
if ((m_running.m_slot1On) && m_dsdDecoder.mbeDVReady1()) if ((m_settings.m_slot1On) && m_dsdDecoder.mbeDVReady1())
{ {
if (!m_running.m_audioMute) if (!m_settings.m_audioMute)
{ {
DSPEngine::instance()->pushMbeFrame( DSPEngine::instance()->pushMbeFrame(
m_dsdDecoder.getMbeDVFrame1(), m_dsdDecoder.getMbeDVFrame1(),
m_dsdDecoder.getMbeRateIndex(), m_dsdDecoder.getMbeRateIndex(),
m_running.m_volume, m_settings.m_volume,
m_running.m_tdmaStereo ? 1 : 3, // left or both channels m_settings.m_tdmaStereo ? 1 : 3, // left or both channels
&m_audioFifo1); &m_audioFifo1);
} }
m_dsdDecoder.resetMbeDV1(); m_dsdDecoder.resetMbeDV1();
} }
if ((m_running.m_slot2On) && m_dsdDecoder.mbeDVReady2()) if ((m_settings.m_slot2On) && m_dsdDecoder.mbeDVReady2())
{ {
if (!m_running.m_audioMute) if (!m_settings.m_audioMute)
{ {
DSPEngine::instance()->pushMbeFrame( DSPEngine::instance()->pushMbeFrame(
m_dsdDecoder.getMbeDVFrame2(), m_dsdDecoder.getMbeDVFrame2(),
m_dsdDecoder.getMbeRateIndex(), m_dsdDecoder.getMbeRateIndex(),
m_running.m_volume, m_settings.m_volume,
m_running.m_tdmaStereo ? 2 : 3, // right or both channels m_settings.m_tdmaStereo ? 2 : 3, // right or both channels
&m_audioFifo2); &m_audioFifo2);
} }
@ -269,9 +233,9 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
// if (DSPEngine::instance()->hasDVSerialSupport() && m_dsdDecoder.mbeDVReady1()) // if (DSPEngine::instance()->hasDVSerialSupport() && m_dsdDecoder.mbeDVReady1())
// { // {
// if (!m_running.m_audioMute) // if (!m_settings.m_audioMute)
// { // {
// DSPEngine::instance()->pushMbeFrame(m_dsdDecoder.getMbeDVFrame1(), m_dsdDecoder.getMbeRateIndex(), m_running.m_volume, &m_audioFifo1); // DSPEngine::instance()->pushMbeFrame(m_dsdDecoder.getMbeDVFrame1(), m_dsdDecoder.getMbeRateIndex(), m_settings.m_volume, &m_audioFifo1);
// } // }
// //
// m_dsdDecoder.resetMbeDV1(); // m_dsdDecoder.resetMbeDV1();
@ -283,14 +247,14 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
if (!DSPEngine::instance()->hasDVSerialSupport()) if (!DSPEngine::instance()->hasDVSerialSupport())
{ {
if (m_running.m_slot1On) if (m_settings.m_slot1On)
{ {
int nbAudioSamples; int nbAudioSamples;
short *dsdAudio = m_dsdDecoder.getAudio1(nbAudioSamples); short *dsdAudio = m_dsdDecoder.getAudio1(nbAudioSamples);
if (nbAudioSamples > 0) if (nbAudioSamples > 0)
{ {
if (!m_running.m_audioMute) { if (!m_settings.m_audioMute) {
m_audioFifo1.write((const quint8*) dsdAudio, nbAudioSamples, 10); m_audioFifo1.write((const quint8*) dsdAudio, nbAudioSamples, 10);
} }
@ -298,14 +262,14 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
} }
} }
if (m_running.m_slot2On) if (m_settings.m_slot2On)
{ {
int nbAudioSamples; int nbAudioSamples;
short *dsdAudio = m_dsdDecoder.getAudio2(nbAudioSamples); short *dsdAudio = m_dsdDecoder.getAudio2(nbAudioSamples);
if (nbAudioSamples > 0) if (nbAudioSamples > 0)
{ {
if (!m_running.m_audioMute) { if (!m_settings.m_audioMute) {
m_audioFifo2.write((const quint8*) dsdAudio, nbAudioSamples, 10); m_audioFifo2.write((const quint8*) dsdAudio, nbAudioSamples, 10);
} }
@ -318,7 +282,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
// //
// if (nbAudioSamples > 0) // if (nbAudioSamples > 0)
// { // {
// if (!m_running.m_audioMute) { // if (!m_settings.m_audioMute) {
// uint res = m_audioFifo1.write((const quint8*) dsdAudio, nbAudioSamples, 10); // uint res = m_audioFifo1.write((const quint8*) dsdAudio, nbAudioSamples, 10);
// } // }
// //
@ -354,60 +318,60 @@ bool DSDDemod::handleMessage(const Message& cmd)
{ {
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
m_config.m_inputSampleRate = notif.getSampleRate(); DSDDemodSettings settings = m_settings;
m_config.m_inputFrequencyOffset = notif.getFrequencyOffset(); settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
apply(); applySettings(settings);
qDebug() << "DSDDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << m_config.m_inputSampleRate qDebug() << "DSDDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset; << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset;
return true; return true;
} }
else if (MsgConfigureDSDDemod::match(cmd)) else if (MsgConfigureChannelizer::match(cmd))
{ {
MsgConfigureDSDDemod& cfg = (MsgConfigureDSDDemod&) cmd; MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
m_config.m_rfBandwidth = cfg.getRFBandwidth(); m_channelizer->configure(m_channelizer->getInputMessageQueue(),
m_config.m_demodGain = cfg.getDemodGain(); cfg.getSampleRate(),
m_config.m_fmDeviation = cfg.getFMDeviation(); cfg.getCenterFrequency());
m_config.m_volume = cfg.getVolume();
m_config.m_baudRate = cfg.getBaudRate();
m_config.m_squelchGate = cfg.getSquelchGate();
m_config.m_squelch = cfg.getSquelch();
m_config.m_audioMute = cfg.getAudioMute();
m_config.m_enableCosineFiltering = cfg.getEnableCosineFiltering();
m_config.m_syncOrConstellation = cfg.getSyncOrConstellation();
m_config.m_slot1On = cfg.getSlot1On();
m_config.m_slot2On = cfg.getSlot2On();
m_config.m_tdmaStereo = cfg.getTDMAStereo();
m_config.m_pllLock = cfg.getPLLLock();
m_config.m_udpCopyAudio = cfg.getUDPCopyAudio();
m_config.m_udpAddress = cfg.getUDPAddress();
m_config.m_udpPort = cfg.getUDPPort();
apply(); return true;
}
else if (MsgConfigureDSDDemod::match(cmd))
{
MsgConfigureDSDDemod& cfg = (MsgConfigureDSDDemod&) cmd;
qDebug() << "DSDDemod::handleMessage: MsgConfigureDSDDemod: m_rfBandwidth: " << m_config.m_rfBandwidth * 100 DSDDemodSettings settings = cfg.getSettings();
<< " m_demodGain: " << m_config.m_demodGain / 100.0
<< " m_fmDeviation: " << m_config.m_fmDeviation * 100
<< " m_volume: " << m_config.m_volume / 10.0
<< " m_baudRate: " << m_config.m_baudRate
<< " m_squelchGate" << m_config.m_squelchGate
<< " m_squelch: " << m_config.m_squelch
<< " m_audioMute: " << m_config.m_audioMute
<< " m_enableCosineFiltering: " << m_config.m_enableCosineFiltering
<< " m_syncOrConstellation: " << m_config.m_syncOrConstellation
<< " m_slot1On: " << m_config.m_slot1On
<< " m_slot2On: " << m_config.m_slot2On
<< " m_tdmaStereo: " << m_config.m_tdmaStereo
<< " m_pllLock: " << m_config.m_pllLock
<< " m_udpCopyAudio: " << m_config.m_udpCopyAudio
<< " m_udpAddress: " << m_config.m_udpAddress
<< " m_udpPort: " << m_config.m_udpPort;
return true; // These settings are set with DownChannelizer::MsgChannelizerNotification
} settings.m_inputSampleRate = m_settings.m_inputSampleRate;
settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset;
applySettings(settings, cfg.getForce());
qDebug() << "DSDDemod::handleMessage: MsgConfigureDSDDemod: m_rfBandwidth: " << m_settings.m_rfBandwidth
<< " m_fmDeviation: " << m_settings.m_fmDeviation
<< " m_demodGain: " << m_settings.m_demodGain
<< " m_volume: " << m_settings.m_volume
<< " m_baudRate: " << m_settings.m_baudRate
<< " m_squelchGate" << m_settings.m_squelchGate
<< " m_squelch: " << m_settings.m_squelch
<< " m_audioMute: " << m_settings.m_audioMute
<< " m_enableCosineFiltering: " << m_settings.m_enableCosineFiltering
<< " m_syncOrConstellation: " << m_settings.m_syncOrConstellation
<< " m_slot1On: " << m_settings.m_slot1On
<< " m_slot2On: " << m_settings.m_slot2On
<< " m_tdmaStereo: " << m_settings.m_tdmaStereo
<< " m_pllLock: " << m_settings.m_pllLock
<< " m_udpCopyAudio: " << m_settings.m_udpCopyAudio
<< " m_udpAddress: " << m_settings.m_udpAddress
<< " m_udpPort: " << m_settings.m_udpPort
<< " force: " << cfg.getForce();
return true;
}
else if (MsgConfigureMyPosition::match(cmd)) else if (MsgConfigureMyPosition::match(cmd))
{ {
MsgConfigureMyPosition& cfg = (MsgConfigureMyPosition&) cmd; MsgConfigureMyPosition& cfg = (MsgConfigureMyPosition&) cmd;
@ -420,82 +384,81 @@ bool DSDDemod::handleMessage(const Message& cmd)
} }
} }
void DSDDemod::apply(bool force) void DSDDemod::applySettings(DSDDemodSettings& settings, bool force)
{ {
if ((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) ||
(m_config.m_inputSampleRate != m_running.m_inputSampleRate) || force) (settings.m_inputSampleRate != m_settings.m_inputSampleRate) || force)
{
m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate);
}
if ((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth) || force)
{
m_settingsMutex.lock();
m_interpolator.create(16, m_config.m_inputSampleRate, (m_config.m_rfBandwidth * 100) / 2.2);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate;
m_phaseDiscri.setFMScaling((float) m_config.m_rfBandwidth / (float) m_config.m_fmDeviation);
m_settingsMutex.unlock();
}
if ((m_config.m_fmDeviation != m_running.m_fmDeviation) || force)
{
m_phaseDiscri.setFMScaling((float) m_config.m_rfBandwidth / (float) m_config.m_fmDeviation);
}
if ((m_config.m_squelchGate != m_running.m_squelchGate) || force)
{
m_squelchGate = 480 * m_config.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate
m_squelchCount = 0; // reset squelch open counter
}
if ((m_config.m_squelch != m_running.m_squelch) || force)
{
// input is a value in tenths of dB
m_squelchLevel = std::pow(10.0, m_config.m_squelch / 100.0);
//m_squelchLevel *= m_squelchLevel;
}
if ((m_config.m_volume != m_running.m_volume) || force)
{ {
m_dsdDecoder.setAudioGain(m_config.m_volume / 10.0f); m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate);
} }
if ((m_config.m_baudRate != m_running.m_baudRate) || force) if ((settings.m_inputSampleRate != m_settings.m_inputSampleRate) ||
(settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
{ {
m_dsdDecoder.setBaudRate(m_config.m_baudRate); m_settingsMutex.lock();
m_interpolator.create(16, settings.m_inputSampleRate, (settings.m_rfBandwidth) / 2.2);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate;
m_phaseDiscri.setFMScaling((float) settings.m_rfBandwidth / (float) settings.m_fmDeviation);
m_settingsMutex.unlock();
} }
if ((m_config.m_enableCosineFiltering != m_running.m_enableCosineFiltering) || force) if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force)
{ {
m_dsdDecoder.enableCosineFiltering(m_config.m_enableCosineFiltering); m_phaseDiscri.setFMScaling((float) settings.m_rfBandwidth / (float) settings.m_fmDeviation);
} }
if ((m_config.m_tdmaStereo != m_running.m_tdmaStereo) || force) if ((settings.m_squelchGate != m_settings.m_squelchGate) || force)
{ {
m_dsdDecoder.setTDMAStereo(m_config.m_tdmaStereo); m_squelchGate = 480 * settings.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate
m_squelchCount = 0; // reset squelch open counter
} }
if ((m_config.m_pllLock != m_running.m_pllLock) || force) if ((settings.m_squelch != m_settings.m_squelch) || force)
{ {
m_dsdDecoder.setSymbolPLLLock(m_config.m_pllLock); // input is a value in dB
m_squelchLevel = std::pow(10.0, settings.m_squelch / 10.0);
} }
if ((m_config.m_udpAddress != m_running.m_udpAddress) if ((settings.m_volume != m_settings.m_volume) || force)
|| (m_config.m_udpPort != m_running.m_udpPort) || force)
{ {
m_udpBufferAudio->setAddress(m_config.m_udpAddress); m_dsdDecoder.setAudioGain(settings.m_volume);
m_udpBufferAudio->setPort(m_config.m_udpPort);
} }
if ((m_config.m_udpCopyAudio != m_running.m_udpCopyAudio) if ((settings.m_baudRate != m_settings.m_baudRate) || force)
|| (m_config.m_slot1On != m_running.m_slot1On)
|| (m_config.m_slot2On != m_running.m_slot2On) || force)
{ {
m_audioFifo1.setCopyToUDP(m_config.m_slot1On && m_config.m_udpCopyAudio); m_dsdDecoder.setBaudRate(settings.m_baudRate);
m_audioFifo2.setCopyToUDP(m_config.m_slot2On && !m_config.m_slot1On && m_config.m_udpCopyAudio);
} }
m_running = m_config; if ((settings.m_enableCosineFiltering != m_settings.m_enableCosineFiltering) || force)
{
m_dsdDecoder.enableCosineFiltering(settings.m_enableCosineFiltering);
}
if ((settings.m_tdmaStereo != m_settings.m_tdmaStereo) || force)
{
m_dsdDecoder.setTDMAStereo(settings.m_tdmaStereo);
}
if ((settings.m_pllLock != m_settings.m_pllLock) || force)
{
m_dsdDecoder.setSymbolPLLLock(settings.m_pllLock);
}
if ((settings.m_udpAddress != m_settings.m_udpAddress)
|| (settings.m_udpPort != m_settings.m_udpPort) || force)
{
m_udpBufferAudio->setAddress(settings.m_udpAddress);
m_udpBufferAudio->setPort(settings.m_udpPort);
}
if ((settings.m_udpCopyAudio != m_settings.m_udpCopyAudio)
|| (settings.m_slot1On != m_settings.m_slot1On)
|| (settings.m_slot2On != m_settings.m_slot2On) || force)
{
m_audioFifo1.setCopyToUDP(settings.m_slot1On && settings.m_udpCopyAudio);
m_audioFifo2.setCopyToUDP(settings.m_slot2On && !settings.m_slot1On && settings.m_udpCopyAudio);
}
m_settings = settings;
} }

View File

@ -33,34 +33,64 @@
#include "util/message.h" #include "util/message.h"
#include "util/udpsink.h" #include "util/udpsink.h"
#include "dsddemodsettings.h"
#include "dsddecoder.h" #include "dsddecoder.h"
class DSDDemodGUI; class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class DSDDemod : public BasebandSampleSink { class DSDDemod : public BasebandSampleSink {
public: public:
DSDDemod(BasebandSampleSink* sampleSink); class MsgConfigureDSDDemod : public Message {
~DSDDemod(); MESSAGE_CLASS_DECLARATION
void configure(MessageQueue* messageQueue, public:
int rfBandwidth, const DSDDemodSettings& getSettings() const { return m_settings; }
int demodGain, bool getForce() const { return m_force; }
int volume,
int baudRate, static MsgConfigureDSDDemod* create(const DSDDemodSettings& settings, bool force)
int fmDeviation, {
int squelchGate, return new MsgConfigureDSDDemod(settings, force);
Real squelch, }
bool audioMute,
bool enableCosineFiltering, private:
bool syncOrConstellation, DSDDemodSettings m_settings;
bool slot1On, bool m_force;
bool slot2On,
bool tdmaStereo, MsgConfigureDSDDemod(const DSDDemodSettings& settings, bool force) :
bool pllLock, Message(),
bool udpCopyAudio, m_settings(settings),
const QString& udpAddress, m_force(force)
quint16 udpPort, { }
bool force); };
class MsgConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
{
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
}
private:
int m_sampleRate;
int m_centerFrequency;
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
Message(),
m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency)
{ }
};
DSDDemod(DeviceSourceAPI *deviceAPI);
~DSDDemod();
void setScopeSink(BasebandSampleSink* sampleSink) { m_scope = sampleSink; }
void configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude); void configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude);
@ -69,10 +99,6 @@ public:
virtual void stop(); virtual void stop();
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
void registerGUI(DSDDemodGUI *dsdDemodGUI) {
m_dsdDemodGUI = dsdDemodGUI;
}
double getMagSq() { return m_magsq; } double getMagSq() { return m_magsq; }
bool getSquelchOpen() const { return m_squelchOpen; } bool getSquelchOpen() const { return m_squelchOpen; }
@ -113,180 +139,16 @@ private:
{} {}
}; };
class MsgConfigureDSDDemod : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getRFBandwidth() const { return m_rfBandwidth; }
int getDemodGain() const { return m_demodGain; }
int getFMDeviation() const { return m_fmDeviation; }
int getVolume() const { return m_volume; }
int getBaudRate() const { return m_baudRate; }
int getSquelchGate() const { return m_squelchGate; }
Real getSquelch() const { return m_squelch; }
bool getAudioMute() const { return m_audioMute; }
bool getEnableCosineFiltering() const { return m_enableCosineFiltering; }
bool getSyncOrConstellation() const { return m_syncOrConstellation; }
bool getSlot1On() const { return m_slot1On; }
bool getSlot2On() const { return m_slot2On; }
bool getTDMAStereo() const { return m_tdmaStereo; }
bool getPLLLock() const { return m_pllLock; }
bool getUDPCopyAudio() const { return m_udpCopyAudio; }
const QString& getUDPAddress() const { return m_udpAddress; }
quint16 getUDPPort() const { return m_udpPort; }
static MsgConfigureDSDDemod* create(int rfBandwidth,
int demodGain,
int fmDeviation,
int volume,
int baudRate,
int squelchGate,
Real squelch,
bool audioMute,
bool enableCosineFiltering,
bool syncOrConstellation,
bool slot1On,
bool slot2On,
bool tdmaStereo,
bool pllLock,
bool udpCopyAudio,
const QString& udpAddress,
quint16 udpPort,
bool force)
{
return new MsgConfigureDSDDemod(rfBandwidth,
demodGain,
fmDeviation,
volume,
baudRate,
squelchGate,
squelch,
audioMute,
enableCosineFiltering,
syncOrConstellation,
slot1On,
slot2On,
tdmaStereo,
pllLock,
udpCopyAudio,
udpAddress,
udpPort,
force);
}
private:
Real m_rfBandwidth;
Real m_demodGain;
int m_fmDeviation;
int m_volume;
int m_baudRate;
int m_squelchGate;
Real m_squelch;
bool m_audioMute;
bool m_enableCosineFiltering;
bool m_syncOrConstellation;
bool m_slot1On;
bool m_slot2On;
bool m_tdmaStereo;
bool m_pllLock;
bool m_udpCopyAudio;
QString m_udpAddress;
quint16 m_udpPort;
bool m_force;
MsgConfigureDSDDemod(int rfBandwidth,
int demodGain,
int fmDeviation,
int volume,
int baudRate,
int squelchGate,
Real squelch,
bool audioMute,
bool enableCosineFiltering,
bool syncOrConstellation,
bool slot1On,
bool slot2On,
bool tdmaStereo,
bool pllLock,
bool udpCopyAudio,
const QString& udpAddress,
quint16 udpPort,
bool force) :
Message(),
m_rfBandwidth(rfBandwidth),
m_demodGain(demodGain),
m_fmDeviation(fmDeviation),
m_volume(volume),
m_baudRate(baudRate),
m_squelchGate(squelchGate),
m_squelch(squelch),
m_audioMute(audioMute),
m_enableCosineFiltering(enableCosineFiltering),
m_syncOrConstellation(syncOrConstellation),
m_slot1On(slot1On),
m_slot2On(slot2On),
m_tdmaStereo(tdmaStereo),
m_pllLock(pllLock),
m_udpCopyAudio(udpCopyAudio),
m_udpAddress(udpAddress),
m_udpPort(udpPort),
m_force(force)
{ }
};
enum RateState { enum RateState {
RSInitialFill, RSInitialFill,
RSRunning RSRunning
}; };
struct Config { DSDDemodSettings m_settings;
int m_inputSampleRate;
qint64 m_inputFrequencyOffset;
int m_rfBandwidth;
int m_demodGain;
int m_volume;
int m_baudRate;
int m_fmDeviation;
int m_squelchGate;
Real m_squelch;
bool m_audioMute;
quint32 m_audioSampleRate;
bool m_enableCosineFiltering;
bool m_syncOrConstellation;
bool m_slot1On;
bool m_slot2On;
bool m_tdmaStereo;
bool m_pllLock;
bool m_udpCopyAudio;
QString m_udpAddress;
quint16 m_udpPort;
Config() : DeviceSourceAPI *m_deviceAPI;
m_inputSampleRate(-1), ThreadedBasebandSampleSink* m_threadedChannelizer;
m_inputFrequencyOffset(0), DownChannelizer* m_channelizer;
m_rfBandwidth(-1),
m_demodGain(-1),
m_volume(-1),
m_baudRate(4800),
m_fmDeviation(1),
m_squelchGate(1),
m_squelch(0),
m_audioMute(false),
m_audioSampleRate(0),
m_enableCosineFiltering(false),
m_syncOrConstellation(false),
m_slot1On(false),
m_slot2On(false),
m_tdmaStereo(false),
m_pllLock(true),
m_udpCopyAudio(false),
m_udpAddress("127.0.0.1"),
m_udpPort(9999)
{ }
};
Config m_config;
Config m_running;
NCO m_nco; NCO m_nco;
Interpolator m_interpolator; Interpolator m_interpolator;
@ -299,7 +161,6 @@ private:
double m_squelchLevel; double m_squelchLevel;
bool m_squelchOpen; bool m_squelchOpen;
Real m_lastArgument;
MovingAverage<double> m_movingAverage; MovingAverage<double> m_movingAverage;
double m_magsq; double m_magsq;
double m_magsqSum; double m_magsqSum;
@ -320,7 +181,6 @@ private:
bool m_scopeEnabled; bool m_scopeEnabled;
DSDDecoder m_dsdDecoder; DSDDecoder m_dsdDecoder;
DSDDemodGUI *m_dsdDemodGUI;
QMutex m_settingsMutex; QMutex m_settingsMutex;
PhaseDiscriminators m_phaseDiscri; PhaseDiscriminators m_phaseDiscri;
@ -328,7 +188,7 @@ private:
static const int m_udpBlockSize; static const int m_udpBlockSize;
void apply(bool force = false); void applySettings(DSDDemodSettings& settings, bool force = false);
}; };
#endif // INCLUDE_DSDDEMOD_H #endif // INCLUDE_DSDDEMOD_H

View File

@ -0,0 +1,50 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 F4EXB //
// written by Edouard Griffiths //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "dsddemodbaudrates.h"
unsigned int DSDDemodBaudRates::m_rates[] = {2400, 4800};
unsigned int DSDDemodBaudRates::m_nb_rates = 2;
unsigned int DSDDemodBaudRates::m_defaultRateIndex = 1; // 4800 bauds
unsigned int DSDDemodBaudRates::getRate(unsigned int rate_index)
{
if (rate_index < m_nb_rates)
{
return m_rates[rate_index];
}
else
{
return m_rates[m_defaultRateIndex];
}
}
unsigned int DSDDemodBaudRates::getRateIndex(unsigned int rate)
{
for (unsigned int i=0; i < m_nb_rates; i++)
{
if (rate == m_rates[i])
{
return i;
}
}
return m_defaultRateIndex;
}

View File

@ -0,0 +1,35 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 F4EXB //
// written by Edouard Griffiths //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_CHANNELRX_DEMODDSD_DSDDEMODBAUDRATES_H_
#define PLUGINS_CHANNELRX_DEMODDSD_DSDDEMODBAUDRATES_H_
class DSDDemodBaudRates
{
public:
static unsigned int getRate(unsigned int rate_index);
static unsigned int getRateIndex(unsigned int rate);
static unsigned int getDefaultRate() { return m_rates[m_defaultRateIndex]; }
static unsigned int getDefaultRateIndex() { return m_defaultRateIndex; }
static unsigned int getNbRates() { return m_nb_rates; }
private:
static unsigned int m_nb_rates;
static unsigned int m_rates[2];
static unsigned int m_defaultRateIndex;
};
#endif /* PLUGINS_CHANNELRX_DEMODDSD_DSDDEMODBAUDRATES_H_ */

View File

@ -34,14 +34,11 @@
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "dsddemodbaudrates.h"
#include "dsddemod.h" #include "dsddemod.h"
const QString DSDDemodGUI::m_channelID = "sdrangel.channel.dsddemod"; const QString DSDDemodGUI::m_channelID = "sdrangel.channel.dsddemod";
unsigned int DSDDemodBaudRates::m_rates[] = {2400, 4800};
unsigned int DSDDemodBaudRates::m_nb_rates = 2;
unsigned int DSDDemodBaudRates::m_defaultRateIndex = 1; // 4800 bauds
DSDDemodGUI* DSDDemodGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI) DSDDemodGUI* DSDDemodGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI)
{ {
DSDDemodGUI* gui = new DSDDemodGUI(pluginAPI, deviceAPI); DSDDemodGUI* gui = new DSDDemodGUI(pluginAPI, deviceAPI);
@ -76,112 +73,31 @@ void DSDDemodGUI::setCenterFrequency(qint64 centerFrequency)
void DSDDemodGUI::resetToDefaults() void DSDDemodGUI::resetToDefaults()
{ {
m_settings.resetToDefaults();
blockApplySettings(true); blockApplySettings(true);
displaySettings();
ui->rfBW->setValue(100); // x100 Hz
ui->demodGain->setValue(100); // 100ths
ui->fmDeviation->setValue(50); // x100 Hz
ui->volume->setValue(20); // /10.0
ui->baudRate->setCurrentIndex(DSDDemodBaudRates::getDefaultRateIndex());
ui->squelchGate->setValue(5);
ui->squelch->setValue(-40);
ui->deltaFrequency->setValue(0);
ui->symbolPLLLock->setChecked(true);
blockApplySettings(false); blockApplySettings(false);
applySettings(); applySettings();
} }
QByteArray DSDDemodGUI::serialize() const QByteArray DSDDemodGUI::serialize() const
{ {
SimpleSerializer s(1); return m_settings.serialize();
s.writeS32(1, m_channelMarker.getCenterFrequency());
s.writeS32(2, ui->rfBW->value());
s.writeS32(3, ui->demodGain->value());
s.writeS32(4, ui->fmDeviation->value());
s.writeS32(5, ui->squelch->value());
s.writeU32(7, m_channelMarker.getColor().rgb());
s.writeS32(8, ui->squelchGate->value());
s.writeS32(9, ui->volume->value());
s.writeBlob(10, ui->scopeGUI->serialize());
s.writeS32(11, ui->baudRate->currentIndex());
s.writeBool(12, m_enableCosineFiltering);
s.writeBool(13, m_syncOrConstellation);
s.writeBool(14, m_slot1On);
s.writeBool(15, m_slot2On);
s.writeBool(16, m_tdmaStereo);
s.writeBlob(17, m_channelMarker.serialize());
return s.final();
} }
bool DSDDemodGUI::deserialize(const QByteArray& data) bool DSDDemodGUI::deserialize(const QByteArray& data)
{ {
SimpleDeserializer d(data); if (m_settings.deserialize(data))
{
if (!d.isValid()) displaySettings();
{ applySettings(true);
resetToDefaults(); return true;
return false; }
} else
{
if (d.getVersion() == 1) resetToDefaults();
{ return false;
QByteArray bytetmp; }
QString strtmp;
quint32 u32tmp;
qint32 tmp;
blockApplySettings(true);
m_channelMarker.blockSignals(true);
d.readBlob(17, &bytetmp);
m_channelMarker.deserialize(bytetmp);
d.readS32(1, &tmp, 0);
m_channelMarker.setCenterFrequency(tmp);
d.readS32(2, &tmp, 4);
ui->rfBW->setValue(tmp);
d.readS32(3, &tmp, 3);
ui->demodGain->setValue(tmp);
d.readS32(4, &tmp, 20);
ui->fmDeviation->setValue(tmp);
d.readS32(5, &tmp, -40);
ui->squelch->setValue(tmp);
if(d.readU32(7, &u32tmp))
{
m_channelMarker.setColor(u32tmp);
}
d.readS32(8, &tmp, 5);
ui->squelchGate->setValue(tmp);
d.readS32(9, &tmp, 20);
ui->volume->setValue(tmp);
d.readBlob(10, &bytetmp);
ui->scopeGUI->deserialize(bytetmp);
d.readS32(11, &tmp, 20);
ui->baudRate->setCurrentIndex(tmp);
d.readBool(12, &m_enableCosineFiltering, false);
d.readBool(13, &m_syncOrConstellation, false);
d.readBool(14, &m_slot1On, false);
d.readBool(15, &m_slot2On, false);
d.readBool(16, &m_tdmaStereo, false);
this->setWindowTitle(m_channelMarker.getTitle());
displayUDPAddress();
blockApplySettings(false);
m_channelMarker.blockSignals(false);
updateMyPosition(); // we do it also here to be able to refresh with latest settings
applySettings(true);
return true;
}
else
{
resetToDefaults();
return false;
}
} }
bool DSDDemodGUI::handleMessage(const Message& message __attribute__((unused))) bool DSDDemodGUI::handleMessage(const Message& message __attribute__((unused)))
@ -192,79 +108,92 @@ bool DSDDemodGUI::handleMessage(const Message& message __attribute__((unused)))
void DSDDemodGUI::on_deltaFrequency_changed(qint64 value) void DSDDemodGUI::on_deltaFrequency_changed(qint64 value)
{ {
m_channelMarker.setCenterFrequency(value); m_channelMarker.setCenterFrequency(value);
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
applySettings();
} }
void DSDDemodGUI::on_rfBW_valueChanged(int value) void DSDDemodGUI::on_rfBW_valueChanged(int value)
{ {
qDebug() << "DSDDemodGUI::on_rfBW_valueChanged" << value * 100;
m_channelMarker.setBandwidth(value * 100); m_channelMarker.setBandwidth(value * 100);
m_settings.m_rfBandwidth = value * 100.0;
ui->rfBWText->setText(QString("%1k").arg(value / 10.0, 0, 'f', 1));
applySettings(); applySettings();
} }
void DSDDemodGUI::on_demodGain_valueChanged(int value __attribute__((unused))) void DSDDemodGUI::on_demodGain_valueChanged(int value)
{ {
m_settings.m_demodGain = value / 100.0;
ui->demodGainText->setText(QString("%1").arg(value / 100.0, 0, 'f', 2));
applySettings(); applySettings();
} }
void DSDDemodGUI::on_fmDeviation_valueChanged(int value __attribute__((unused))) void DSDDemodGUI::on_fmDeviation_valueChanged(int value)
{ {
m_settings.m_fmDeviation = value * 100.0;
ui->fmDeviationText->setText(QString("%1k").arg(value / 10.0, 0, 'f', 1));
applySettings(); applySettings();
} }
void DSDDemodGUI::on_volume_valueChanged(int value __attribute__((unused))) void DSDDemodGUI::on_volume_valueChanged(int value)
{ {
m_settings.m_volume= value / 10.0;
ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
applySettings(); applySettings();
} }
void DSDDemodGUI::on_baudRate_currentIndexChanged(int index __attribute__((unused))) void DSDDemodGUI::on_baudRate_currentIndexChanged(int index)
{ {
m_settings.m_baudRate = DSDDemodBaudRates::getRate(index);
applySettings(); applySettings();
} }
void DSDDemodGUI::on_enableCosineFiltering_toggled(bool enable) void DSDDemodGUI::on_enableCosineFiltering_toggled(bool enable)
{ {
m_enableCosineFiltering = enable; m_settings.m_enableCosineFiltering = enable;
applySettings(); applySettings();
} }
void DSDDemodGUI::on_syncOrConstellation_toggled(bool checked) void DSDDemodGUI::on_syncOrConstellation_toggled(bool checked)
{ {
m_syncOrConstellation = checked; m_settings.m_syncOrConstellation = checked;
applySettings(); applySettings();
} }
void DSDDemodGUI::on_slot1On_toggled(bool checked) void DSDDemodGUI::on_slot1On_toggled(bool checked)
{ {
m_slot1On = checked; m_settings.m_slot1On = checked;
applySettings(); applySettings();
} }
void DSDDemodGUI::on_slot2On_toggled(bool checked) void DSDDemodGUI::on_slot2On_toggled(bool checked)
{ {
m_slot2On = checked; m_settings.m_slot2On = checked;
applySettings(); applySettings();
} }
void DSDDemodGUI::on_tdmaStereoSplit_toggled(bool checked) void DSDDemodGUI::on_tdmaStereoSplit_toggled(bool checked)
{ {
m_tdmaStereo = checked; m_settings.m_tdmaStereo = checked;
applySettings(); applySettings();
} }
void DSDDemodGUI::on_squelchGate_valueChanged(int value __attribute__((unused))) void DSDDemodGUI::on_squelchGate_valueChanged(int value)
{ {
m_settings.m_squelchGate = value;
ui->squelchGateText->setText(QString("%1").arg(value * 10.0, 0, 'f', 0));
applySettings(); applySettings();
} }
void DSDDemodGUI::on_squelch_valueChanged(int value) void DSDDemodGUI::on_squelch_valueChanged(int value)
{ {
ui->squelchText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); ui->squelchText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
m_settings.m_squelch = value / 10.0;
applySettings(); applySettings();
} }
void DSDDemodGUI::on_audioMute_toggled(bool checked) void DSDDemodGUI::on_audioMute_toggled(bool checked)
{ {
m_audioMute = checked; m_settings.m_audioMute = checked;
applySettings(); applySettings();
} }
@ -275,11 +204,13 @@ void DSDDemodGUI::on_symbolPLLLock_toggled(bool checked)
} else { } else {
ui->symbolPLLLock->setStyleSheet("QToolButton { background:rgb(53,53,53); }"); ui->symbolPLLLock->setStyleSheet("QToolButton { background:rgb(53,53,53); }");
} }
m_settings.m_pllLock = checked;
applySettings(); applySettings();
} }
void DSDDemodGUI::on_udpOutput_toggled(bool checked __attribute__((unused))) void DSDDemodGUI::on_udpOutput_toggled(bool checked)
{ {
m_settings.m_udpCopyAudio = checked;
applySettings(); applySettings();
} }
@ -322,8 +253,9 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
m_scopeVis = new ScopeVis(ui->glScope); m_scopeVis = new ScopeVis(ui->glScope);
m_dsdDemod = new DSDDemod(m_scopeVis); m_dsdDemod = new DSDDemod(m_deviceAPI);
m_dsdDemod->registerGUI(this); m_dsdDemod->setScopeSink(m_scopeVis);
m_dsdDemod->setMessageQueueToGUI(getInputMessageQueue());
ui->glScope->setSampleRate(48000); ui->glScope->setSampleRate(48000);
m_scopeVis->setSampleRate(48000); m_scopeVis->setSampleRate(48000);
@ -339,11 +271,7 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999);
ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue); ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue);
m_channelizer = new DownChannelizer(m_dsdDemod);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
//m_channelMarker = new ChannelMarker(this);
m_channelMarker.setTitle(windowTitle()); m_channelMarker.setTitle(windowTitle());
m_channelMarker.setColor(Qt::cyan); m_channelMarker.setColor(Qt::cyan);
m_channelMarker.setBandwidth(10000); m_channelMarker.setBandwidth(10000);
@ -358,7 +286,11 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
m_settings.setChannelMarker(&m_channelMarker);
m_settings.setScopeGUI(ui->scopeGUI);
updateMyPosition(); updateMyPosition();
displaySettings();
displayUDPAddress(); displayUDPAddress();
applySettings(true); applySettings(true);
} }
@ -366,11 +298,7 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
DSDDemodGUI::~DSDDemodGUI() DSDDemodGUI::~DSDDemodGUI()
{ {
m_deviceAPI->removeChannelInstance(this); m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
delete m_dsdDemod; delete m_dsdDemod;
//delete m_channelMarker;
delete ui; delete ui;
} }
@ -392,49 +320,65 @@ void DSDDemodGUI::displayUDPAddress()
ui->udpOutput->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort())); ui->udpOutput->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort()));
} }
void DSDDemodGUI::displaySettings()
{
blockApplySettings(true);
m_channelMarker.blockSignals(true);
m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
m_channelMarker.setUDPAddress(m_settings.m_udpAddress);
m_channelMarker.setUDPSendPort(m_settings.m_udpPort);
m_channelMarker.setColor(m_settings.m_rgbColor);
this->setWindowTitle(m_channelMarker.getTitle());
setTitleColor(m_settings.m_rgbColor);
m_channelMarker.blockSignals(false);
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
ui->rfBW->setValue(m_settings.m_rfBandwidth / 100.0);
ui->rfBWText->setText(QString("%1k").arg(ui->rfBW->value() / 10.0, 0, 'f', 1));
ui->fmDeviation->setValue(m_settings.m_fmDeviation / 100.0);
ui->fmDeviationText->setText(QString("%1k").arg(ui->fmDeviation->value() / 10.0, 0, 'f', 1));
ui->squelch->setValue(m_settings.m_squelch * 10.0);
ui->squelchText->setText(QString("%1").arg(ui->squelch->value() / 10.0, 0, 'f', 1));
ui->squelchGate->setValue(m_settings.m_squelchGate);
ui->squelchGateText->setText(QString("%1").arg(ui->squelchGate->value() * 10.0, 0, 'f', 0));
ui->demodGain->setValue(m_settings.m_demodGain * 100.0);
ui->demodGainText->setText(QString("%1").arg(ui->demodGain->value() / 100.0, 0, 'f', 2));
ui->volume->setValue(m_settings.m_volume * 10.0);
ui->volumeText->setText(QString("%1").arg(ui->volume->value() / 10.0, 0, 'f', 1));
ui->enableCosineFiltering->setChecked(m_settings.m_enableCosineFiltering);
ui->syncOrConstellation->setChecked(m_settings.m_syncOrConstellation);
ui->slot1On->setChecked(m_settings.m_slot1On);
ui->slot2On->setChecked(m_settings.m_slot2On);
ui->tdmaStereoSplit->setChecked(m_settings.m_tdmaStereo);
ui->audioMute->setChecked(m_settings.m_audioMute);
ui->udpOutput->setChecked(m_settings.m_udpCopyAudio);
ui->symbolPLLLock->setChecked(m_settings.m_pllLock);
ui->baudRate->setCurrentIndex(DSDDemodBaudRates::getRateIndex(m_settings.m_baudRate));
blockApplySettings(false);
}
void DSDDemodGUI::applySettings(bool force) void DSDDemodGUI::applySettings(bool force)
{ {
if (m_doApplySettings) if (m_doApplySettings)
{ {
qDebug() << "DSDDemodGUI::applySettings"; qDebug() << "DSDDemodGUI::applySettings";
setTitleColor(m_channelMarker.getColor()); DSDDemod::MsgConfigureChannelizer* channelConfigMsg = DSDDemod::MsgConfigureChannelizer::create(
48000, m_channelMarker.getCenterFrequency());
m_dsdDemod->getInputMessageQueue()->push(channelConfigMsg);
m_channelizer->configure(m_channelizer->getInputMessageQueue(), DSDDemod::MsgConfigureDSDDemod* message = DSDDemod::MsgConfigureDSDDemod::create( m_settings, force);
48000, m_dsdDemod->getInputMessageQueue()->push(message);
m_channelMarker.getCenterFrequency());
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
ui->rfBWText->setText(QString("%1k").arg(ui->rfBW->value() / 10.0, 0, 'f', 1));
ui->demodGainText->setText(QString("%1").arg(ui->demodGain->value() / 100.0, 0, 'f', 2));
ui->fmDeviationText->setText(QString("%1k").arg(ui->fmDeviation->value() / 10.0, 0, 'f', 1));
ui->squelchGateText->setText(QString("%1").arg(ui->squelchGate->value() * 10.0, 0, 'f', 0));
ui->volumeText->setText(QString("%1").arg(ui->volume->value() / 10.0, 0, 'f', 1));
ui->enableCosineFiltering->setChecked(m_enableCosineFiltering);
ui->syncOrConstellation->setChecked(m_syncOrConstellation);
ui->slot1On->setChecked(m_slot1On);
ui->slot2On->setChecked(m_slot2On);
ui->tdmaStereoSplit->setChecked(m_tdmaStereo);
m_dsdDemod->configure(m_dsdDemod->getInputMessageQueue(),
ui->rfBW->value(),
ui->demodGain->value(),
ui->fmDeviation->value(),
ui->volume->value(),
DSDDemodBaudRates::getRate(ui->baudRate->currentIndex()),
ui->squelchGate->value(), // in 10ths of ms
ui->squelch->value(),
ui->audioMute->isChecked(),
m_enableCosineFiltering,
m_syncOrConstellation,
m_slot1On,
m_slot2On,
m_tdmaStereo,
ui->symbolPLLLock->isChecked(),
ui->udpOutput->isChecked(),
m_channelMarker.getUDPAddress(),
m_channelMarker.getUDPSendPort(),
force);
} }
} }
@ -683,28 +627,3 @@ void DSDDemodGUI::tick()
m_tickCount++; m_tickCount++;
} }
unsigned int DSDDemodBaudRates::getRate(unsigned int rate_index)
{
if (rate_index < m_nb_rates)
{
return m_rates[rate_index];
}
else
{
return m_rates[m_defaultRateIndex];
}
}
unsigned int DSDDemodBaudRates::getRateIndex(unsigned int rate)
{
for (unsigned int i=0; i < m_nb_rates; i++)
{
if (rate == m_rates[i])
{
return i;
}
}
return m_defaultRateIndex;
}

View File

@ -18,20 +18,20 @@
#ifndef INCLUDE_DSDDEMODGUI_H #ifndef INCLUDE_DSDDEMODGUI_H
#define INCLUDE_DSDDEMODGUI_H #define INCLUDE_DSDDEMODGUI_H
#include <plugin/plugininstancegui.h>
#include <QMenu> #include <QMenu>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/dsptypes.h" #include "dsp/dsptypes.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
#include "dsddemodsettings.h"
class PluginAPI; class PluginAPI;
class DeviceSourceAPI; class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class ScopeVis; class ScopeVis;
class DSDDemod; class DSDDemod;
@ -39,7 +39,7 @@ namespace Ui {
class DSDDemodGUI; class DSDDemodGUI;
} }
class DSDDemodGUI : public RollupWidget, public PluginInstanceUI { class DSDDemodGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:
@ -96,12 +96,11 @@ private:
PluginAPI* m_pluginAPI; PluginAPI* m_pluginAPI;
DeviceSourceAPI* m_deviceAPI; DeviceSourceAPI* m_deviceAPI;
ChannelMarker m_channelMarker; ChannelMarker m_channelMarker;
DSDDemodSettings m_settings;
bool m_doApplySettings; bool m_doApplySettings;
char m_formatStatusText[82+1]; //!< Fixed signal format dependent status text char m_formatStatusText[82+1]; //!< Fixed signal format dependent status text
SignalFormat m_signalFormat; SignalFormat m_signalFormat;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
ScopeVis* m_scopeVis; ScopeVis* m_scopeVis;
DSDDemod* m_dsdDemod; DSDDemod* m_dsdDemod;
@ -124,6 +123,7 @@ private:
void blockApplySettings(bool block); void blockApplySettings(bool block);
void applySettings(bool force = false); void applySettings(bool force = false);
void displaySettings();
void updateMyPosition(); void updateMyPosition();
void displayUDPAddress(); void displayUDPAddress();
@ -131,18 +131,4 @@ private:
void enterEvent(QEvent*); void enterEvent(QEvent*);
}; };
class DSDDemodBaudRates
{
public:
static unsigned int getRate(unsigned int rate_index);
static unsigned int getRateIndex(unsigned int rate);
static unsigned int getDefaultRate() { return m_rates[m_defaultRateIndex]; }
static unsigned int getDefaultRateIndex() { return m_defaultRateIndex; }
static unsigned int getNbRates();
private:
static unsigned int m_nb_rates;
static unsigned int m_rates[2];
static unsigned int m_defaultRateIndex;
};
#endif // INCLUDE_DSDDEMODGUI_H #endif // INCLUDE_DSDDEMODGUI_H

View File

@ -24,7 +24,7 @@
const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = { const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = {
QString("DSD Demodulator"), QString("DSD Demodulator"),
QString("3.6.1"), QString("3.7.3"),
QString("(c) Edouard Griffiths, F4EXB"), QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"), QString("https://github.com/f4exb/sdrangel"),
true, true,
@ -50,7 +50,7 @@ void DSDDemodPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerRxChannel(DSDDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(DSDDemodGUI::m_channelID, this);
} }
PluginInstanceUI* DSDDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) PluginInstanceGUI* DSDDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{ {
if(channelName == DSDDemodGUI::m_channelID) if(channelName == DSDDemodGUI::m_channelID)
{ {

View File

@ -34,7 +34,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -0,0 +1,144 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB. //
// //
// This program is free som_udpCopyAudioftware; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QColor>
#include "dsp/dspengine.h"
#include "util/simpleserializer.h"
#include "settings/serializable.h"
#include "dsddemodsettings.h"
DSDDemodSettings::DSDDemodSettings() :
m_channelMarker(0),
m_scopeGUI(0)
{
resetToDefaults();
}
void DSDDemodSettings::resetToDefaults()
{
m_inputSampleRate = 96000;
m_inputFrequencyOffset = 0;
m_rfBandwidth = 12500.0;
m_fmDeviation = 5000.0;
m_demodGain = 1.25;
m_volume = 2.0;
m_baudRate = 4800;
m_squelchGate = 5; // 10s of ms at 48000 Hz sample rate. Corresponds to 2400 for AGC attack
m_squelch = -40.0;
m_audioMute = false;
m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
m_enableCosineFiltering = false;
m_syncOrConstellation = false;
m_slot1On = true;
m_slot2On = false;
m_tdmaStereo = false;
m_pllLock = true;
m_udpCopyAudio = false;
m_udpAddress = "127.0.0.1";
m_udpPort = 9999;
m_rgbColor = QColor(0, 255, 255).rgb();
}
QByteArray DSDDemodSettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_inputFrequencyOffset);
s.writeS32(2, m_rfBandwidth/100.0);
s.writeS32(3, m_demodGain*100.0);
s.writeS32(4, m_fmDeviation/100.0);
s.writeS32(5, m_squelch*10.0);
s.writeS32(6, m_inputSampleRate);
s.writeU32(7, m_rgbColor);
s.writeS32(8, m_squelchGate);
s.writeS32(9, m_volume*10.0);
if (m_scopeGUI) {
s.writeBlob(10, m_scopeGUI->serialize());
}
s.writeS32(11, m_baudRate);
s.writeBool(12, m_enableCosineFiltering);
s.writeBool(13, m_syncOrConstellation);
s.writeBool(14, m_slot1On);
s.writeBool(15, m_slot2On);
s.writeBool(16, m_tdmaStereo);
if (m_channelMarker) {
s.writeBlob(17, m_channelMarker->serialize());
}
return s.final();
}
bool DSDDemodSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
resetToDefaults();
return false;
}
if (d.getVersion() == 1)
{
QByteArray bytetmp;
QString strtmp;
qint32 tmp;
if (m_channelMarker) {
d.readBlob(17, &bytetmp);
m_channelMarker->deserialize(bytetmp);
}
d.readS32(1, &tmp, 0);
m_inputFrequencyOffset = tmp;
d.readS32(2, &tmp, 125);
m_rfBandwidth = tmp * 100.0;
d.readS32(3, &tmp, 125);
m_demodGain = tmp / 100.0;
d.readS32(4, &tmp, 50);
m_fmDeviation = tmp * 100.0;
d.readS32(5, &tmp, -400);
m_squelch = tmp / 10.0;
d.readS32(6, &m_inputSampleRate, 96000);
d.readU32(7, &m_rgbColor);
d.readS32(8, &m_squelchGate, 5);
d.readS32(9, &tmp, 20);
m_volume = tmp / 10.0;
if (m_scopeGUI) {
d.readBlob(10, &bytetmp);
m_scopeGUI->deserialize(bytetmp);
}
d.readS32(11, &m_baudRate, 4800);
d.readBool(12, &m_enableCosineFiltering, false);
d.readBool(13, &m_syncOrConstellation, false);
d.readBool(14, &m_slot1On, false);
d.readBool(15, &m_slot2On, false);
d.readBool(16, &m_tdmaStereo, false);
return true;
}
else
{
resetToDefaults();
return false;
}
}

View File

@ -0,0 +1,60 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_CHANNELRX_DEMODDSD_DSDDEMODSETTINGS_H_
#define PLUGINS_CHANNELRX_DEMODDSD_DSDDEMODSETTINGS_H_
#include <QByteArray>
class Serializable;
struct DSDDemodSettings
{
int m_inputSampleRate;
qint64 m_inputFrequencyOffset;
Real m_rfBandwidth;
Real m_fmDeviation;
Real m_demodGain;
Real m_volume;
int m_baudRate;
int m_squelchGate;
Real m_squelch;
bool m_audioMute;
quint32 m_audioSampleRate;
bool m_enableCosineFiltering;
bool m_syncOrConstellation;
bool m_slot1On;
bool m_slot2On;
bool m_tdmaStereo;
bool m_pllLock;
bool m_udpCopyAudio;
QString m_udpAddress;
quint16 m_udpPort;
quint32 m_rgbColor;
Serializable *m_channelMarker;
Serializable *m_scopeGUI;
DSDDemodSettings();
void resetToDefaults();
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
void setScopeGUI(Serializable *scopeGUI) { m_scopeGUI = scopeGUI; }
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif /* PLUGINS_CHANNELRX_DEMODDSD_DSDDEMODSETTINGS_H_ */

View File

@ -1,9 +1,9 @@
#ifndef INCLUDE_LoRaDEMODGUI_H #ifndef INCLUDE_LoRaDEMODGUI_H
#define INCLUDE_LoRaDEMODGUI_H #define INCLUDE_LoRaDEMODGUI_H
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
#define BANDWIDTHSTRING {7813,15625,20833,31250,62500} #define BANDWIDTHSTRING {7813,15625,20833,31250,62500}
@ -19,7 +19,7 @@ namespace Ui {
class LoRaDemodGUI; class LoRaDemodGUI;
} }
class LoRaDemodGUI : public RollupWidget, public PluginInstanceUI { class LoRaDemodGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:

View File

@ -33,7 +33,7 @@ void LoRaPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerRxChannel(LoRaDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(LoRaDemodGUI::m_channelID, this);
} }
PluginInstanceUI* LoRaPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) PluginInstanceGUI* LoRaPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{ {
if(channelName == LoRaDemodGUI::m_channelID) if(channelName == LoRaDemodGUI::m_channelID)
{ {

View File

@ -17,7 +17,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -1,11 +1,11 @@
#ifndef INCLUDE_NFMDEMODGUI_H #ifndef INCLUDE_NFMDEMODGUI_H
#define INCLUDE_NFMDEMODGUI_H #define INCLUDE_NFMDEMODGUI_H
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/dsptypes.h" #include "dsp/dsptypes.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
class PluginAPI; class PluginAPI;
@ -19,7 +19,7 @@ namespace Ui {
class NFMDemodGUI; class NFMDemodGUI;
} }
class NFMDemodGUI : public RollupWidget, public PluginInstanceUI { class NFMDemodGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:

View File

@ -33,7 +33,7 @@ void NFMPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerRxChannel(NFMDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(NFMDemodGUI::m_channelID, this);
} }
PluginInstanceUI* NFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) PluginInstanceGUI* NFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{ {
if(channelName == NFMDemodGUI::m_channelID) { if(channelName == NFMDemodGUI::m_channelID) {
NFMDemodGUI* gui = NFMDemodGUI::create(m_pluginAPI, deviceAPI); NFMDemodGUI* gui = NFMDemodGUI::create(m_pluginAPI, deviceAPI);

View File

@ -17,7 +17,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -3,12 +3,14 @@ project(ssb)
set(ssb_SOURCES set(ssb_SOURCES
ssbdemod.cpp ssbdemod.cpp
ssbdemodgui.cpp ssbdemodgui.cpp
ssbdemodsettings.cpp
ssbplugin.cpp ssbplugin.cpp
) )
set(ssb_HEADERS set(ssb_HEADERS
ssbdemod.h ssbdemod.h
ssbdemodgui.h ssbdemodgui.h
ssbdemodsettings.h
ssbplugin.h ssbplugin.h
) )

View File

@ -25,10 +25,12 @@ CONFIG(Debug):build_subdir = debug
SOURCES += ssbdemod.cpp\ SOURCES += ssbdemod.cpp\
ssbdemodgui.cpp\ ssbdemodgui.cpp\
ssbdemodsettings.cpp\
ssbplugin.cpp ssbplugin.cpp
HEADERS += ssbdemod.h\ HEADERS += ssbdemod.h\
ssbdemodgui.h\ ssbdemodgui.h\
ssbdemodsettings.h\
ssbplugin.h ssbplugin.h
FORMS += ssbdemodgui.ui FORMS += ssbdemodgui.ui

View File

@ -16,19 +16,26 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#include "ssbdemod.h"
#include <dsp/downchannelizer.h>
#include <QTime> #include <QTime>
#include <QDebug> #include <QDebug>
#include <stdio.h> #include <stdio.h>
#include "audio/audiooutput.h" #include "audio/audiooutput.h"
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include <dsp/downchannelizer.h>
#include "dsp/threadedbasebandsamplesink.h"
#include "device/devicesourceapi.h"
#include "util/db.h" #include "util/db.h"
MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemod, Message) #include "ssbdemod.h"
SSBDemod::SSBDemod(BasebandSampleSink* sampleSink) : MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemod, Message)
MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemodPrivate, Message)
MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureChannelizer, Message)
SSBDemod::SSBDemod(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_audioBinaual(false), m_audioBinaual(false),
m_audioFlipChannels(false), m_audioFlipChannels(false),
m_dsb(false), m_dsb(false),
@ -40,7 +47,7 @@ SSBDemod::SSBDemod(BasebandSampleSink* sampleSink) :
m_agcPowerThreshold(1e-2), m_agcPowerThreshold(1e-2),
m_agcThresholdGate(0), m_agcThresholdGate(0),
m_audioActive(false), m_audioActive(false),
m_sampleSink(sampleSink), m_sampleSink(0),
m_audioFifo(24000), m_audioFifo(24000),
m_settingsMutex(QMutex::Recursive) m_settingsMutex(QMutex::Recursive)
{ {
@ -75,7 +82,13 @@ SSBDemod::SSBDemod(BasebandSampleSink* sampleSink) :
SSBFilter = new fftfilt(m_LowCutoff / m_audioSampleRate, m_Bandwidth / m_audioSampleRate, ssbFftLen); SSBFilter = new fftfilt(m_LowCutoff / m_audioSampleRate, m_Bandwidth / m_audioSampleRate, ssbFftLen);
DSBFilter = new fftfilt((2.0f * m_Bandwidth) / m_audioSampleRate, 2 * ssbFftLen); DSBFilter = new fftfilt((2.0f * m_Bandwidth) / m_audioSampleRate, 2 * ssbFftLen);
m_channelizer = new DownChannelizer(this);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
DSPEngine::instance()->addAudioSink(&m_audioFifo); DSPEngine::instance()->addAudioSink(&m_audioFifo);
applySettings(m_settings, true);
} }
SSBDemod::~SSBDemod() SSBDemod::~SSBDemod()
@ -84,6 +97,10 @@ SSBDemod::~SSBDemod()
if (DSBFilter) delete DSBFilter; if (DSBFilter) delete DSBFilter;
DSPEngine::instance()->removeAudioSink(&m_audioFifo); DSPEngine::instance()->removeAudioSink(&m_audioFifo);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
} }
void SSBDemod::configure(MessageQueue* messageQueue, void SSBDemod::configure(MessageQueue* messageQueue,
@ -101,7 +118,7 @@ void SSBDemod::configure(MessageQueue* messageQueue,
int agcPowerThreshold, int agcPowerThreshold,
int agcThresholdGate) int agcThresholdGate)
{ {
Message* cmd = MsgConfigureSSBDemod::create( Message* cmd = MsgConfigureSSBDemodPrivate::create(
Bandwidth, Bandwidth,
LowCutoff, LowCutoff,
volume, volume,
@ -262,10 +279,6 @@ void SSBDemod::stop()
bool SSBDemod::handleMessage(const Message& cmd) bool SSBDemod::handleMessage(const Message& cmd)
{ {
float band, lowCutoff;
qDebug() << "SSBDemod::handleMessage";
if (DownChannelizer::MsgChannelizerNotification::match(cmd)) if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{ {
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
@ -284,94 +297,48 @@ bool SSBDemod::handleMessage(const Message& cmd)
return true; return true;
} }
else if (MsgConfigureSSBDemod::match(cmd)) else if (MsgConfigureChannelizer::match(cmd))
{ {
MsgConfigureSSBDemod& cfg = (MsgConfigureSSBDemod&) cmd; MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
m_settingsMutex.lock(); m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(),
cfg.getCenterFrequency());
band = cfg.getBandwidth(); qDebug() << "SSBDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << cfg.getSampleRate()
lowCutoff = cfg.getLoCutoff(); << " centerFrequency: " << cfg.getCenterFrequency();
if (band < 0) { return true;
band = -band; }
lowCutoff = -lowCutoff; else if (MsgConfigureSSBDemod::match(cmd))
m_usb = false; {
} else MsgConfigureSSBDemod& cfg = (MsgConfigureSSBDemod&) cmd;
m_usb = true;
if (band < 100.0f) SSBDemodSettings settings = cfg.getSettings();
{
band = 100.0f;
lowCutoff = 0;
}
m_Bandwidth = band;
m_LowCutoff = lowCutoff;
m_interpolator.create(16, m_sampleRate, band * 2.0f); // These settings are set with DownChannelizer::MsgChannelizerNotification
SSBFilter->create_filter(m_LowCutoff / (float) m_audioSampleRate, m_Bandwidth / (float) m_audioSampleRate); settings.m_inputSampleRate = m_settings.m_inputSampleRate;
DSBFilter->create_dsb_filter((2.0f * m_Bandwidth) / (float) m_audioSampleRate); settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset;
m_volume = cfg.getVolume(); applySettings(settings, cfg.getForce());
//m_volume *= 2.0; // for 327.68
m_volume /= 4.0; // for 3276.8
m_spanLog2 = cfg.getSpanLog2(); qDebug() << "SSBDemod::handleMessage: MsgConfigureSSBDemod:"
m_audioBinaual = cfg.getAudioBinaural(); << " m_rfBandwidth: " << settings.m_rfBandwidth
m_audioFlipChannels = cfg.getAudioFlipChannels(); << " m_lowCutoff: " << settings.m_lowCutoff
m_dsb = cfg.getDSB(); << " m_volume: " << settings.m_volume
m_audioMute = cfg.getAudioMute(); << " m_spanLog2: " << settings.m_spanLog2
m_agcActive = cfg.getAGC(); << " m_audioBinaual: " << settings.m_audioBinaural
<< " m_audioFlipChannels: " << settings.m_audioFlipChannels
<< " m_dsb: " << settings.m_dsb
<< " m_audioMute: " << settings.m_audioMute
<< " m_agcActive: " << settings.m_agc
<< " m_agcClamping: " << settings.m_agcClamping
<< " m_agcTimeLog2: " << settings.m_agcTimeLog2
<< " agcPowerThreshold: " << settings.m_agcPowerThreshold
<< " agcThresholdGate: " << settings.m_agcThresholdGate;
int agcNbSamples = 48 * (1<<cfg.getAGCTimeLog2()); return true;
m_agc.setThresholdEnable(cfg.getAGCPowerThershold() != -99); }
double agcPowerThreshold = CalcDb::powerFromdB(cfg.getAGCPowerThershold()) * (1<<30);
int agcThresholdGate = 48 * cfg.getAGCThersholdGate(); // ms
bool agcClamping = cfg.getAGCClamping();
if (m_agcNbSamples != agcNbSamples)
{
m_agc.resize(agcNbSamples, agcTarget);
m_agc.setStepDownDelay(agcNbSamples);
m_agcNbSamples = agcNbSamples;
}
if (m_agcPowerThreshold != agcPowerThreshold)
{
m_agc.setThreshold(agcPowerThreshold);
m_agcPowerThreshold = agcPowerThreshold;
}
if (m_agcThresholdGate != agcThresholdGate)
{
m_agc.setGate(agcThresholdGate);
m_agcThresholdGate = agcThresholdGate;
}
if (m_agcClamping != agcClamping)
{
m_agc.setClamping(agcClamping);
m_agcClamping = agcClamping;
}
m_settingsMutex.unlock();
qDebug() << "SBDemod::handleMessage: MsgConfigureSSBDemod: m_Bandwidth: " << m_Bandwidth
<< " m_LowCutoff: " << m_LowCutoff
<< " m_volume: " << m_volume
<< " m_spanLog2: " << m_spanLog2
<< " m_audioBinaual: " << m_audioBinaual
<< " m_audioFlipChannels: " << m_audioFlipChannels
<< " m_dsb: " << m_dsb
<< " m_audioMute: " << m_audioMute
<< " m_agcActive: " << m_agcActive
<< " m_agcClamping: " << m_agcClamping
<< " agcNbSamples: " << agcNbSamples
<< " agcPowerThreshold: " << agcPowerThreshold
<< " agcThresholdGate: " << agcThresholdGate;
return true;
}
else else
{ {
if(m_sampleSink != 0) if(m_sampleSink != 0)
@ -384,3 +351,116 @@ bool SSBDemod::handleMessage(const Message& cmd)
} }
} }
} }
void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
{
if ((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) ||
(m_settings.m_inputSampleRate != settings.m_inputSampleRate) || force)
{
m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate);
}
if((m_settings.m_inputSampleRate != settings.m_inputSampleRate) ||
(m_settings.m_rfBandwidth != settings.m_rfBandwidth) ||
(m_settings.m_lowCutoff != settings.m_lowCutoff) ||
(m_settings.m_audioSampleRate != settings.m_audioSampleRate) || force)
{
float band, lowCutoff;
band = settings.m_rfBandwidth;
lowCutoff = settings.m_lowCutoff;
m_audioSampleRate = settings.m_audioSampleRate;
if (band < 0) {
band = -band;
lowCutoff = -lowCutoff;
m_usb = false;
} else
m_usb = true;
if (band < 100.0f)
{
band = 100.0f;
lowCutoff = 0;
}
m_Bandwidth = band;
m_LowCutoff = lowCutoff;
m_settingsMutex.lock();
m_interpolator.create(16, m_sampleRate, band * 2.0f);
SSBFilter->create_filter(m_LowCutoff / (float) m_audioSampleRate, m_Bandwidth / (float) m_audioSampleRate);
DSBFilter->create_dsb_filter((2.0f * m_Bandwidth) / (float) m_audioSampleRate);
m_settingsMutex.unlock();
}
if ((m_settings.m_volume != settings.m_volume) || force)
{
m_volume = settings.m_volume;
m_volume /= 4.0; // for 3276.8
}
if ((m_settings.m_agcTimeLog2 != settings.m_agcTimeLog2) ||
(m_settings.m_agcPowerThreshold != settings.m_agcPowerThreshold) ||
(m_settings.m_agcThresholdGate != settings.m_agcThresholdGate) ||
(m_settings.m_agcClamping != settings.m_agcClamping) || force)
{
int agcNbSamples = 48 * (1<<settings.m_agcTimeLog2);
m_agc.setThresholdEnable(settings.m_agcPowerThreshold != -99);
double agcPowerThreshold = CalcDb::powerFromdB(settings.m_agcPowerThreshold) * (1<<30);
int agcThresholdGate = 48 * settings.m_agcThresholdGate; // ms
bool agcClamping = settings.m_agcClamping;
if (m_agcNbSamples != agcNbSamples)
{
m_settingsMutex.lock();
m_agc.resize(agcNbSamples, agcTarget);
m_agc.setStepDownDelay(agcNbSamples);
m_agcNbSamples = agcNbSamples;
m_settingsMutex.unlock();
}
if (m_agcPowerThreshold != agcPowerThreshold)
{
m_agc.setThreshold(agcPowerThreshold);
m_agcPowerThreshold = agcPowerThreshold;
}
if (m_agcThresholdGate != agcThresholdGate)
{
m_agc.setGate(agcThresholdGate);
m_agcThresholdGate = agcThresholdGate;
}
if (m_agcClamping != agcClamping)
{
m_agc.setClamping(agcClamping);
m_agcClamping = agcClamping;
}
qDebug() << "SBDemod::applySettings: AGC:"
<< " agcNbSamples: " << agcNbSamples
<< " agcPowerThreshold: " << agcPowerThreshold
<< " agcThresholdGate: " << agcThresholdGate
<< " agcClamping: " << agcClamping;
}
// TODO:
// if ((m_settings.m_udpAddress != settings.m_udpAddress)
// || (m_settings.m_udpPort != settings.m_udpPort) || force)
// {
// m_udpBufferAudio->setAddress(const_cast<QString&>(settings.m_udpAddress));
// m_udpBufferAudio->setPort(settings.m_udpPort);
// }
m_spanLog2 = settings.m_spanLog2;
m_audioBinaual = settings.m_audioBinaural;
m_audioFlipChannels = settings.m_audioFlipChannels;
m_dsb = settings.m_dsb;
m_audioMute = settings.m_audioMute;
m_agcActive = settings.m_agc;
m_settings = settings;
}

View File

@ -18,9 +18,10 @@
#ifndef INCLUDE_SSBDEMOD_H #ifndef INCLUDE_SSBDEMOD_H
#define INCLUDE_SSBDEMOD_H #define INCLUDE_SSBDEMOD_H
#include <dsp/basebandsamplesink.h>
#include <QMutex> #include <QMutex>
#include <vector> #include <vector>
#include <dsp/basebandsamplesink.h>
#include "dsp/ncof.h" #include "dsp/ncof.h"
#include "dsp/interpolator.h" #include "dsp/interpolator.h"
#include "dsp/fftfilt.h" #include "dsp/fftfilt.h"
@ -28,13 +29,66 @@
#include "audio/audiofifo.h" #include "audio/audiofifo.h"
#include "util/message.h" #include "util/message.h"
#include "ssbdemodsettings.h"
#define ssbFftLen 1024 #define ssbFftLen 1024
#define agcTarget 3276.8 // -10 dB amplitude => -20 dB power: center of normal signal #define agcTarget 3276.8 // -10 dB amplitude => -20 dB power: center of normal signal
class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class SSBDemod : public BasebandSampleSink { class SSBDemod : public BasebandSampleSink {
public: public:
SSBDemod(BasebandSampleSink* sampleSink); class MsgConfigureSSBDemod : public Message {
MESSAGE_CLASS_DECLARATION
public:
const SSBDemodSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureSSBDemod* create(const SSBDemodSettings& settings, bool force)
{
return new MsgConfigureSSBDemod(settings, force);
}
private:
SSBDemodSettings m_settings;
bool m_force;
MsgConfigureSSBDemod(const SSBDemodSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
class MsgConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
{
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
}
private:
int m_sampleRate;
int m_centerFrequency;
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
Message(),
m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency)
{ }
};
SSBDemod(DeviceSourceAPI *deviceAPI);
virtual ~SSBDemod(); virtual ~SSBDemod();
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
void configure(MessageQueue* messageQueue, void configure(MessageQueue* messageQueue,
Real Bandwidth, Real Bandwidth,
@ -71,7 +125,7 @@ public:
} }
private: private:
class MsgConfigureSSBDemod : public Message { class MsgConfigureSSBDemodPrivate : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
@ -89,7 +143,7 @@ private:
int getAGCPowerThershold() const { return m_agcPowerThreshold; } int getAGCPowerThershold() const { return m_agcPowerThreshold; }
int getAGCThersholdGate() const { return m_agcThresholdGate; } int getAGCThersholdGate() const { return m_agcThresholdGate; }
static MsgConfigureSSBDemod* create(Real Bandwidth, static MsgConfigureSSBDemodPrivate* create(Real Bandwidth,
Real LowCutoff, Real LowCutoff,
Real volume, Real volume,
int spanLog2, int spanLog2,
@ -103,7 +157,7 @@ private:
int agcPowerThreshold, int agcPowerThreshold,
int agcThresholdGate) int agcThresholdGate)
{ {
return new MsgConfigureSSBDemod( return new MsgConfigureSSBDemodPrivate(
Bandwidth, Bandwidth,
LowCutoff, LowCutoff,
volume, volume,
@ -134,7 +188,7 @@ private:
int m_agcPowerThreshold; int m_agcPowerThreshold;
int m_agcThresholdGate; int m_agcThresholdGate;
MsgConfigureSSBDemod(Real Bandwidth, MsgConfigureSSBDemodPrivate(Real Bandwidth,
Real LowCutoff, Real LowCutoff,
Real volume, Real volume,
int spanLog2, int spanLog2,
@ -164,6 +218,11 @@ private:
{ } { }
}; };
DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
SSBDemodSettings m_settings;
Real m_Bandwidth; Real m_Bandwidth;
Real m_LowCutoff; Real m_LowCutoff;
Real m_volume; Real m_volume;
@ -204,6 +263,8 @@ private:
quint32 m_audioSampleRate; quint32 m_audioSampleRate;
QMutex m_settingsMutex; QMutex m_settingsMutex;
void applySettings(const SSBDemodSettings& settings, bool force = false);
}; };
#endif // INCLUDE_SSBDEMOD_H #endif // INCLUDE_SSBDEMOD_H

View File

@ -2,12 +2,9 @@
#include "ssbdemodgui.h" #include "ssbdemodgui.h"
#include <device/devicesourceapi.h> #include <device/devicesourceapi.h>
#include <dsp/downchannelizer.h>
#include <QDockWidget> #include <QDockWidget>
#include <QMainWindow> #include <QMainWindow>
#include "dsp/threadedbasebandsamplesink.h"
#include "ui_ssbdemodgui.h"
#include "ui_ssbdemodgui.h" #include "ui_ssbdemodgui.h"
#include "dsp/spectrumvis.h" #include "dsp/spectrumvis.h"
#include "gui/glspectrum.h" #include "gui/glspectrum.h"
@ -50,113 +47,36 @@ qint64 SSBDemodGUI::getCenterFrequency() const
void SSBDemodGUI::setCenterFrequency(qint64 centerFrequency) void SSBDemodGUI::setCenterFrequency(qint64 centerFrequency)
{ {
m_channelMarker.setCenterFrequency(centerFrequency); m_channelMarker.setCenterFrequency(centerFrequency);
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
applySettings(); applySettings();
} }
void SSBDemodGUI::resetToDefaults() void SSBDemodGUI::resetToDefaults()
{ {
blockApplySettings(true); m_settings.resetToDefaults();
ui->BW->setValue(30);
ui->volume->setValue(30);
ui->deltaFrequency->setValue(0);
ui->spanLog2->setValue(3);
ui->agc->setChecked(false);
ui->agcTimeLog2->setValue(7);
ui->agcPowerThreshold->setValue(-40);
ui->agcThresholdGate->setValue(4);
blockApplySettings(false);
} }
QByteArray SSBDemodGUI::serialize() const QByteArray SSBDemodGUI::serialize() const
{ {
SimpleSerializer s(1); return m_settings.serialize();
s.writeS32(1, m_channelMarker.getCenterFrequency());
s.writeS32(2, ui->BW->value());
s.writeS32(3, ui->volume->value());
s.writeBlob(4, ui->spectrumGUI->serialize());
s.writeU32(5, m_channelMarker.getColor().rgb());
s.writeS32(6, ui->lowCut->value());
s.writeS32(7, ui->spanLog2->value());
s.writeBool(8, m_audioBinaural);
s.writeBool(9, m_audioFlipChannels);
s.writeBool(10, m_dsb);
s.writeBool(11, ui->agc->isChecked());
s.writeS32(12, ui->agcTimeLog2->value());
s.writeS32(13, ui->agcPowerThreshold->value());
s.writeS32(14, ui->agcThresholdGate->value());
s.writeBool(15, ui->agcClamping->isChecked());
return s.final();
} }
bool SSBDemodGUI::deserialize(const QByteArray& data) bool SSBDemodGUI::deserialize(const QByteArray& data)
{ {
SimpleDeserializer d(data); if(m_settings.deserialize(data))
{
if (!d.isValid()) updateChannelMarker();
{
resetToDefaults();
applySettings();
return false;
}
if (d.getVersion() == 1)
{
QByteArray bytetmp;
quint32 u32tmp;
qint32 tmp;
bool booltmp;
blockApplySettings(true);
m_channelMarker.blockSignals(true);
d.readS32(1, &tmp, 0);
m_channelMarker.setCenterFrequency(tmp);
d.readS32(2, &tmp, 30);
ui->BW->setValue(tmp);
d.readS32(3, &tmp, 30);
ui->volume->setValue(tmp);
d.readBlob(4, &bytetmp);
ui->spectrumGUI->deserialize(bytetmp);
if(d.readU32(5, &u32tmp))
m_channelMarker.setColor(u32tmp);
d.readS32(6, &tmp, 3);
ui->lowCut->setValue(tmp);
d.readS32(7, &tmp, 20);
ui->spanLog2->setValue(tmp);
setNewRate(tmp);
d.readBool(8, &m_audioBinaural);
ui->audioBinaural->setChecked(m_audioBinaural);
d.readBool(9, &m_audioFlipChannels);
ui->audioFlipChannels->setChecked(m_audioFlipChannels);
d.readBool(10, &m_dsb);
ui->dsb->setChecked(m_dsb);
d.readBool(11, &booltmp, false);
ui->agc->setChecked(booltmp);
d.readS32(12, &tmp, 7);
ui->agcTimeLog2->setValue(tmp);
d.readS32(13, &tmp, -40);
ui->agcPowerThreshold->setValue(tmp);
d.readS32(14, &tmp, 4);
ui->agcThresholdGate->setValue(tmp);
d.readBool(15, &booltmp, false);
ui->agcClamping->setChecked(booltmp);
displaySettings(); displaySettings();
applySettings(true); // will have true
blockApplySettings(false); return true;
m_channelMarker.blockSignals(false); }
else
applySettings(); {
return true; m_settings.resetToDefaults();
} displaySettings();
else applySettings(true); // will have true
{ return false;
resetToDefaults(); }
applySettings();
return false;
}
} }
bool SSBDemodGUI::handleMessage(const Message& message __attribute__((unused))) bool SSBDemodGUI::handleMessage(const Message& message __attribute__((unused)))
@ -172,18 +92,21 @@ void SSBDemodGUI::viewChanged()
void SSBDemodGUI::on_audioBinaural_toggled(bool binaural) void SSBDemodGUI::on_audioBinaural_toggled(bool binaural)
{ {
m_audioBinaural = binaural; m_audioBinaural = binaural;
m_settings.m_audioBinaural = binaural;
applySettings(); applySettings();
} }
void SSBDemodGUI::on_audioFlipChannels_toggled(bool flip) void SSBDemodGUI::on_audioFlipChannels_toggled(bool flip)
{ {
m_audioFlipChannels = flip; m_audioFlipChannels = flip;
m_settings.m_audioFlipChannels = flip;
applySettings(); applySettings();
} }
void SSBDemodGUI::on_dsb_toggled(bool dsb) void SSBDemodGUI::on_dsb_toggled(bool dsb)
{ {
m_dsb = dsb; m_dsb = dsb;
m_settings.m_dsb = dsb;
if (m_dsb) if (m_dsb)
{ {
@ -220,6 +143,8 @@ void SSBDemodGUI::on_dsb_toggled(bool dsb)
void SSBDemodGUI::on_deltaFrequency_changed(qint64 value) void SSBDemodGUI::on_deltaFrequency_changed(qint64 value)
{ {
m_channelMarker.setCenterFrequency(value); m_channelMarker.setCenterFrequency(value);
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
applySettings();
} }
void SSBDemodGUI::on_BW_valueChanged(int value) void SSBDemodGUI::on_BW_valueChanged(int value)
@ -236,6 +161,7 @@ void SSBDemodGUI::on_BW_valueChanged(int value)
ui->BWText->setText(tr("%1k").arg(s)); ui->BWText->setText(tr("%1k").arg(s));
} }
m_settings.m_rfBandwidth = value * 100;
on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100);
setNewRate(m_spanLog2); setNewRate(m_spanLog2);
} }
@ -279,22 +205,26 @@ void SSBDemodGUI::on_lowCut_valueChanged(int value)
QString s = QString::number(lowCutoff/1000.0, 'f', 1); QString s = QString::number(lowCutoff/1000.0, 'f', 1);
ui->lowCutText->setText(tr("%1k").arg(s)); ui->lowCutText->setText(tr("%1k").arg(s));
ui->lowCut->setValue(lowCutoff/100); ui->lowCut->setValue(lowCutoff/100);
m_settings.m_lowCutoff = lowCutoff;
applySettings(); applySettings();
} }
void SSBDemodGUI::on_volume_valueChanged(int value) void SSBDemodGUI::on_volume_valueChanged(int value)
{ {
ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
m_settings.m_volume = value / 10.0;
applySettings(); applySettings();
} }
void SSBDemodGUI::on_agc_toggled(bool checked __attribute((__unused__))) void SSBDemodGUI::on_agc_toggled(bool checked)
{ {
m_settings.m_agc = checked;
applySettings(); applySettings();
} }
void SSBDemodGUI::on_agcClamping_toggled(bool checked __attribute((__unused__))) void SSBDemodGUI::on_agcClamping_toggled(bool checked)
{ {
m_settings.m_agcClamping = checked;
applySettings(); applySettings();
} }
@ -302,12 +232,14 @@ void SSBDemodGUI::on_agcTimeLog2_valueChanged(int value)
{ {
QString s = QString::number((1<<value), 'f', 0); QString s = QString::number((1<<value), 'f', 0);
ui->agcTimeText->setText(s); ui->agcTimeText->setText(s);
m_settings.m_agcTimeLog2 = value;
applySettings(); applySettings();
} }
void SSBDemodGUI::on_agcPowerThreshold_valueChanged(int value) void SSBDemodGUI::on_agcPowerThreshold_valueChanged(int value)
{ {
displayAGCPowerThreshold(value); displayAGCPowerThreshold(value);
m_settings.m_agcPowerThreshold = value;
applySettings(); applySettings();
} }
@ -315,12 +247,14 @@ void SSBDemodGUI::on_agcThresholdGate_valueChanged(int value)
{ {
QString s = QString::number(value, 'f', 0); QString s = QString::number(value, 'f', 0);
ui->agcThresholdGateText->setText(s); ui->agcThresholdGateText->setText(s);
m_settings.m_agcThresholdGate = value;
applySettings(); applySettings();
} }
void SSBDemodGUI::on_audioMute_toggled(bool checked) void SSBDemodGUI::on_audioMute_toggled(bool checked)
{ {
m_audioMute = checked; m_audioMute = checked;
m_settings.m_audioMute = checked;
applySettings(); applySettings();
} }
@ -328,6 +262,7 @@ void SSBDemodGUI::on_spanLog2_valueChanged(int value)
{ {
if (setNewRate(value)) if (setNewRate(value))
{ {
m_settings.m_spanLog2 = value;
applySettings(); applySettings();
} }
@ -373,10 +308,9 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked()));
m_spectrumVis = new SpectrumVis(ui->glSpectrum); m_spectrumVis = new SpectrumVis(ui->glSpectrum);
m_ssbDemod = new SSBDemod(m_spectrumVis); m_ssbDemod = new SSBDemod(m_deviceAPI);
m_channelizer = new DownChannelizer(m_ssbDemod); m_ssbDemod->setMessageQueueToGUI(getInputMessageQueue());
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); m_ssbDemod->setSampleSink(m_spectrumVis);
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
@ -389,13 +323,11 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
//m_channelMarker = new ChannelMarker(this);
m_channelMarker.setColor(Qt::green);
m_channelMarker.setBandwidth(m_rate);
m_channelMarker.setSidebands(ChannelMarker::usb);
m_channelMarker.setCenterFrequency(0);
m_channelMarker.setVisible(true); m_channelMarker.setVisible(true);
m_settings.setChannelMarker(&m_channelMarker);
m_settings.setSpectrumGUI(ui->spectrumGUI);
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
m_deviceAPI->registerChannelInstance(m_channelID, this); m_deviceAPI->registerChannelInstance(m_channelID, this);
@ -404,21 +336,16 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
resetToDefaults();
displaySettings(); displaySettings();
applySettings(); applySettings(true);
setNewRate(m_spanLog2); setNewRate(m_spanLog2);
} }
SSBDemodGUI::~SSBDemodGUI() SSBDemodGUI::~SSBDemodGUI()
{ {
m_deviceAPI->removeChannelInstance(this); m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
delete m_ssbDemod; delete m_ssbDemod;
delete m_spectrumVis; delete m_spectrumVis;
//delete m_channelMarker;
delete ui; delete ui;
} }
@ -454,7 +381,6 @@ bool SSBDemodGUI::setNewRate(int spanLog2)
m_channelMarker.setLowCutoff(m_rate); m_channelMarker.setLowCutoff(m_rate);
} }
QString s = QString::number(m_rate/1000.0, 'f', 1); QString s = QString::number(m_rate/1000.0, 'f', 1);
if (m_dsb) if (m_dsb)
@ -504,41 +430,101 @@ void SSBDemodGUI::blockApplySettings(bool block)
m_doApplySettings = !block; m_doApplySettings = !block;
} }
void SSBDemodGUI::applySettings() void SSBDemodGUI::applySettings(bool force)
{ {
if (m_doApplySettings) if (m_doApplySettings)
{ {
setTitleColor(m_channelMarker.getColor()); setTitleColor(m_channelMarker.getColor());
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_channelizer->configure(m_channelizer->getInputMessageQueue(), SSBDemod::MsgConfigureChannelizer* channelConfigMsg = SSBDemod::MsgConfigureChannelizer::create(
48000, 48000, m_channelMarker.getCenterFrequency());
m_channelMarker.getCenterFrequency()); m_ssbDemod->getInputMessageQueue()->push(channelConfigMsg);
m_ssbDemod->configure(m_ssbDemod->getInputMessageQueue(), SSBDemod::MsgConfigureSSBDemod* message = SSBDemod::MsgConfigureSSBDemod::create( m_settings, force);
ui->BW->value() * 100.0, m_ssbDemod->getInputMessageQueue()->push(message);
ui->lowCut->value() * 100.0,
ui->volume->value() / 10.0,
m_spanLog2,
m_audioBinaural,
m_audioFlipChannels,
m_dsb,
ui->audioMute->isChecked(),
ui->agc->isChecked(),
ui->agcClamping->isChecked(),
ui->agcTimeLog2->value(),
ui->agcPowerThreshold->value(),
ui->agcThresholdGate->value());
} }
} }
void SSBDemodGUI::displaySettings() void SSBDemodGUI::displaySettings()
{ {
QString s = QString::number((1<<ui->agcTimeLog2->value()), 'f', 0); m_channelMarker.blockSignals(true);
m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset);
m_channelMarker.setBandwidth(m_settings.m_rfBandwidth * 2);
m_channelMarker.setLowCutoff(m_settings.m_lowCutoff);
m_channelMarker.setUDPAddress(m_settings.m_udpAddress);
m_channelMarker.setUDPSendPort(m_settings.m_udpPort);
m_channelMarker.setColor(m_settings.m_rgbColor);
setTitleColor(m_settings.m_rgbColor);
if (m_settings.m_dsb) {
m_channelMarker.setSidebands(ChannelMarker::dsb);
} else {
if (m_settings.m_rfBandwidth < 0) {
m_channelMarker.setSidebands(ChannelMarker::lsb);
} else {
m_channelMarker.setSidebands(ChannelMarker::usb);
}
}
m_channelMarker.blockSignals(false);
blockApplySettings(true);
ui->agc->setChecked(m_settings.m_agc);
ui->agcClamping->setChecked(m_settings.m_agcClamping);
ui->audioBinaural->setChecked(m_settings.m_audioBinaural);
ui->audioFlipChannels->setChecked(m_settings.m_audioFlipChannels);
ui->audioMute->setChecked(m_settings.m_audioMute);
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
ui->dsb->setChecked(m_settings.m_dsb);
ui->spanLog2->setValue(m_settings.m_spanLog2);
ui->BW->setValue(m_settings.m_rfBandwidth / 100.0);
QString s = QString::number(m_settings.m_rfBandwidth/1000.0, 'f', 1);
if (m_settings.m_dsb)
{
ui->BWText->setText(tr("%1%2k").arg(QChar(0xB1, 0x00)).arg(s));
}
else
{
ui->BWText->setText(tr("%1k").arg(s));
}
ui->lowCut->setValue(m_settings.m_lowCutoff / 100.0);
ui->lowCutText->setText(tr("%1k").arg(m_settings.m_lowCutoff / 1000.0));
ui->volume->setValue(m_settings.m_volume * 10.0);
ui->volumeText->setText(QString("%1").arg(m_settings.m_volume, 0, 'f', 1));
ui->agcTimeLog2->setValue(m_settings.m_agcTimeLog2);
s = QString::number((1<<ui->agcTimeLog2->value()), 'f', 0);
ui->agcTimeText->setText(s); ui->agcTimeText->setText(s);
ui->agcPowerThreshold->setValue(m_settings.m_agcPowerThreshold);
displayAGCPowerThreshold(ui->agcPowerThreshold->value()); displayAGCPowerThreshold(ui->agcPowerThreshold->value());
ui->agcThresholdGate->setValue(m_settings.m_agcThresholdGate);
s = QString::number(ui->agcThresholdGate->value(), 'f', 0); s = QString::number(ui->agcThresholdGate->value(), 'f', 0);
ui->agcThresholdGateText->setText(s); ui->agcThresholdGateText->setText(s);
blockApplySettings(false);
}
void SSBDemodGUI::displayUDPAddress()
{
//TODO: ui->copyAudioToUDP->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort()));
}
void SSBDemodGUI::updateChannelMarker()
{
m_channelMarker.blockSignals(true);
//m_channelMarker.deserialize(m_settings.m_channelMarkerBytes);
this->setWindowTitle(m_channelMarker.getTitle());
m_channelMarker.blockSignals(false);
} }
void SSBDemodGUI::displayAGCPowerThreshold(int value) void SSBDemodGUI::displayAGCPowerThreshold(int value)

View File

@ -1,18 +1,17 @@
#ifndef INCLUDE_SSBDEMODGUI_H #ifndef INCLUDE_SSBDEMODGUI_H
#define INCLUDE_SSBDEMODGUI_H #define INCLUDE_SSBDEMODGUI_H
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
#include "ssbdemodsettings.h"
class PluginAPI; class PluginAPI;
class DeviceSourceAPI; class DeviceSourceAPI;
class AudioFifo; class AudioFifo;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class SSBDemod; class SSBDemod;
class SpectrumVis; class SpectrumVis;
@ -20,7 +19,7 @@ namespace Ui {
class SSBDemodGUI; class SSBDemodGUI;
} }
class SSBDemodGUI : public RollupWidget, public PluginInstanceUI { class SSBDemodGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:
@ -65,6 +64,7 @@ private:
PluginAPI* m_pluginAPI; PluginAPI* m_pluginAPI;
DeviceSourceAPI* m_deviceAPI; DeviceSourceAPI* m_deviceAPI;
ChannelMarker m_channelMarker; ChannelMarker m_channelMarker;
SSBDemodSettings m_settings;
bool m_basicSettingsShown; bool m_basicSettingsShown;
bool m_doApplySettings; bool m_doApplySettings;
int m_rate; int m_rate;
@ -76,8 +76,6 @@ private:
bool m_squelchOpen; bool m_squelchOpen;
uint32_t m_tickCount; uint32_t m_tickCount;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
SSBDemod* m_ssbDemod; SSBDemod* m_ssbDemod;
SpectrumVis* m_spectrumVis; SpectrumVis* m_spectrumVis;
MessageQueue m_inputMessageQueue; MessageQueue m_inputMessageQueue;
@ -89,8 +87,10 @@ private:
bool setNewRate(int spanLog2); bool setNewRate(int spanLog2);
void blockApplySettings(bool block); void blockApplySettings(bool block);
void applySettings(); void applySettings(bool force = false);
void displaySettings(); void displaySettings();
void displayUDPAddress();
void updateChannelMarker();
void displayAGCPowerThreshold(int value); void displayAGCPowerThreshold(int value);

View File

@ -0,0 +1,124 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QColor>
#include "dsp/dspengine.h"
#include "util/simpleserializer.h"
#include "settings/serializable.h"
#include "ssbdemodsettings.h"
SSBDemodSettings::SSBDemodSettings() :
m_channelMarker(0),
m_spectrumGUI(0)
{
resetToDefaults();
}
void SSBDemodSettings::resetToDefaults()
{
m_audioBinaural = false;
m_audioFlipChannels = false;
m_dsb = false;
m_audioMute = false;
m_agc = false;
m_agcClamping = false;
m_agcPowerThreshold = -40;
m_agcThresholdGate = 4;
m_agcTimeLog2 = 7;
m_rfBandwidth = 3000;
m_lowCutoff = 300;
m_volume = 3.0;
m_spanLog2 = 3;
m_inputSampleRate = 96000;
m_inputFrequencyOffset = 0;
m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
m_rgbColor = QColor(0, 255, 0).rgb();
}
QByteArray SSBDemodSettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_inputFrequencyOffset);
s.writeS32(2, m_rfBandwidth / 100.0);
s.writeS32(3, m_volume * 10.0);
if (m_spectrumGUI) {
s.writeBlob(4, m_spectrumGUI->serialize());
}
s.writeU32(5, m_rgbColor);
s.writeS32(6, m_lowCutoff / 100.0);
s.writeS32(7, m_spanLog2);
s.writeBool(8, m_audioBinaural);
s.writeBool(9, m_audioFlipChannels);
s.writeBool(10, m_dsb);
s.writeBool(11, m_agc);
s.writeS32(12, m_agcTimeLog2);
s.writeS32(13, m_agcPowerThreshold);
s.writeS32(14, m_agcThresholdGate);
s.writeBool(15, m_agcClamping);
return s.final();
}
bool SSBDemodSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1)
{
QByteArray bytetmp;
qint32 tmp;
QString strtmp;
d.readS32(1, &m_inputFrequencyOffset, 0);
d.readS32(2, &tmp, 30);
m_rfBandwidth = tmp * 100.0;
d.readS32(3, &tmp, 30);
m_volume = tmp / 10.0;
if (m_spectrumGUI) {
d.readBlob(4, &bytetmp);
m_spectrumGUI->deserialize(bytetmp);
}
d.readU32(5, &m_rgbColor);
d.readS32(6, &tmp, 30);
m_lowCutoff = tmp * 100.0;
d.readS32(7, &m_spanLog2, 3);
d.readBool(8, &m_audioBinaural, false);
d.readBool(9, &m_audioFlipChannels, false);
d.readBool(10, &m_dsb, false);
d.readBool(11, &m_agc, false);
d.readS32(12, &m_agcTimeLog2, 7);
d.readS32(13, &m_agcPowerThreshold, -40);
d.readS32(14, &m_agcThresholdGate, 4);
d.readBool(15, &m_agcClamping, false);
return true;
}
else
{
resetToDefaults();
return false;
}
}

View File

@ -0,0 +1,58 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_CHANNELRX_DEMODSSB_SSBDEMODSETTINGS_H_
#define PLUGINS_CHANNELRX_DEMODSSB_SSBDEMODSETTINGS_H_
#include <QByteArray>
class Serializable;
struct SSBDemodSettings
{
int m_inputSampleRate;
qint32 m_inputFrequencyOffset;
quint32 m_audioSampleRate;
Real m_rfBandwidth;
Real m_lowCutoff;
Real m_volume;
int m_spanLog2;
bool m_audioBinaural;
bool m_audioFlipChannels;
bool m_dsb;
bool m_audioMute;
bool m_agc;
bool m_agcClamping;
int m_agcTimeLog2;
int m_agcPowerThreshold;
int m_agcThresholdGate;
QString m_udpAddress;
quint16 m_udpPort;
quint32 m_rgbColor;
Serializable *m_channelMarker;
Serializable *m_spectrumGUI;
SSBDemodSettings();
void resetToDefaults();
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
void setSpectrumGUI(Serializable *spectrumGUI) { m_spectrumGUI = spectrumGUI; }
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif /* PLUGINS_CHANNELRX_DEMODSSB_SSBDEMODSETTINGS_H_ */

View File

@ -7,7 +7,7 @@
const PluginDescriptor SSBPlugin::m_pluginDescriptor = { const PluginDescriptor SSBPlugin::m_pluginDescriptor = {
QString("SSB Demodulator"), QString("SSB Demodulator"),
QString("3.5.4"), QString("3.7.3"),
QString("(c) Edouard Griffiths, F4EXB"), QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"), QString("https://github.com/f4exb/sdrangel"),
true, true,
@ -33,7 +33,7 @@ void SSBPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerRxChannel(SSBDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(SSBDemodGUI::m_channelID, this);
} }
PluginInstanceUI* SSBPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) PluginInstanceGUI* SSBPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{ {
if(channelName == SSBDemodGUI::m_channelID) if(channelName == SSBDemodGUI::m_channelID)
{ {

View File

@ -17,7 +17,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -1,10 +1,10 @@
#ifndef INCLUDE_WFMDEMODGUI_H #ifndef INCLUDE_WFMDEMODGUI_H
#define INCLUDE_WFMDEMODGUI_H #define INCLUDE_WFMDEMODGUI_H
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
class PluginAPI; class PluginAPI;
@ -18,7 +18,7 @@ namespace Ui {
class WFMDemodGUI; class WFMDemodGUI;
} }
class WFMDemodGUI : public RollupWidget, public PluginInstanceUI { class WFMDemodGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:

View File

@ -33,7 +33,7 @@ void WFMPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerRxChannel(WFMDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(WFMDemodGUI::m_channelID, this);
} }
PluginInstanceUI* WFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) PluginInstanceGUI* WFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{ {
if(channelName == WFMDemodGUI::m_channelID) if(channelName == WFMDemodGUI::m_channelID)
{ {

View File

@ -17,7 +17,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -1,12 +1,12 @@
#ifndef INCLUDE_TCPSRCGUI_H #ifndef INCLUDE_TCPSRCGUI_H
#define INCLUDE_TCPSRCGUI_H #define INCLUDE_TCPSRCGUI_H
#include <plugin/plugininstancegui.h>
#include <QHostAddress> #include <QHostAddress>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
#include "tcpsrc.h" #include "tcpsrc.h"
@ -22,7 +22,7 @@ namespace Ui {
class TCPSrcGUI; class TCPSrcGUI;
} }
class TCPSrcGUI : public RollupWidget, public PluginInstanceUI { class TCPSrcGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:

View File

@ -33,7 +33,7 @@ void TCPSrcPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerRxChannel(TCPSrcGUI::m_channelID, this); m_pluginAPI->registerRxChannel(TCPSrcGUI::m_channelID, this);
} }
PluginInstanceUI* TCPSrcPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) PluginInstanceGUI* TCPSrcPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{ {
if(channelName == TCPSrcGUI::m_channelID) if(channelName == TCPSrcGUI::m_channelID)
{ {

View File

@ -17,7 +17,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -476,7 +476,7 @@ void UDPSrc::apply(bool force)
m_outMovingAverage.resize(m_config.m_outputSampleRate * 0.01, 1e-10); // 10 ms m_outMovingAverage.resize(m_config.m_outputSampleRate * 0.01, 1e-10); // 10 ms
} }
if ((m_config.m_audioActive != m_config.m_audioActive) || force) if ((m_config.m_audioActive != m_running.m_audioActive) || force)
{ {
if (m_config.m_audioActive) if (m_config.m_audioActive)
{ {

View File

@ -18,11 +18,11 @@
#ifndef INCLUDE_UDPSRCGUI_H #ifndef INCLUDE_UDPSRCGUI_H
#define INCLUDE_UDPSRCGUI_H #define INCLUDE_UDPSRCGUI_H
#include <plugin/plugininstancegui.h>
#include <QHostAddress> #include <QHostAddress>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
#include "udpsrc.h" #include "udpsrc.h"
@ -38,7 +38,7 @@ namespace Ui {
class UDPSrcGUI; class UDPSrcGUI;
} }
class UDPSrcGUI : public RollupWidget, public PluginInstanceUI { class UDPSrcGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:

View File

@ -50,7 +50,7 @@ void UDPSrcPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerRxChannel(UDPSrcGUI::m_channelID, this); m_pluginAPI->registerRxChannel(UDPSrcGUI::m_channelID, this);
} }
PluginInstanceUI* UDPSrcPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) PluginInstanceGUI* UDPSrcPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{ {
if(channelName == UDPSrcGUI::m_channelID) if(channelName == UDPSrcGUI::m_channelID)
{ {

View File

@ -34,7 +34,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -338,7 +338,7 @@ bool AMMod::handleMessage(const Message& cmd)
MsgReportFileSourceStreamTiming *report; MsgReportFileSourceStreamTiming *report;
report = MsgReportFileSourceStreamTiming::create(samplesCount); report = MsgReportFileSourceStreamTiming::create(samplesCount);
getOutputMessageQueue()->push(report); getMessageQueueToGUI()->push(report);
return true; return true;
} }
@ -415,7 +415,7 @@ void AMMod::openFileStream()
MsgReportFileSourceStreamData *report; MsgReportFileSourceStreamData *report;
report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength); report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength);
getOutputMessageQueue()->push(report); getMessageQueueToGUI()->push(report);
} }
void AMMod::seekFileStream(int seekPercentage) void AMMod::seekFileStream(int seekPercentage)

View File

@ -178,7 +178,7 @@ void AMModGUI::handleSourceMessages()
{ {
Message* message; Message* message;
while ((message = m_amMod->getOutputMessageQueue()->pop()) != 0) while ((message = getInputMessageQueue()->pop()) != 0)
{ {
if (handleMessage(*message)) if (handleMessage(*message))
{ {
@ -339,6 +339,7 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pare
connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked()));
m_amMod = new AMMod(); m_amMod = new AMMod();
m_amMod->setMessageQueueToGUI(getInputMessageQueue());
m_channelizer = new UpChannelizer(m_amMod); m_channelizer = new UpChannelizer(m_amMod);
m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this); m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this);
//m_pluginAPI->addThreadedSink(m_threadedChannelizer); //m_pluginAPI->addThreadedSink(m_threadedChannelizer);
@ -372,7 +373,7 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pare
applySettings(); applySettings();
connect(m_amMod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
connect(m_amMod, SIGNAL(levelChanged(qreal, qreal, int)), ui->volumeMeter, SLOT(levelChanged(qreal, qreal, int))); connect(m_amMod, SIGNAL(levelChanged(qreal, qreal, int)), ui->volumeMeter, SLOT(levelChanged(qreal, qreal, int)));
} }

View File

@ -17,10 +17,10 @@
#ifndef PLUGINS_CHANNELTX_MODAM_AMMODGUI_H_ #ifndef PLUGINS_CHANNELTX_MODAM_AMMODGUI_H_
#define PLUGINS_CHANNELTX_MODAM_AMMODGUI_H_ #define PLUGINS_CHANNELTX_MODAM_AMMODGUI_H_
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
#include "ammod.h" #include "ammod.h"
@ -36,7 +36,7 @@ namespace Ui {
class AMModGUI; class AMModGUI;
} }
class AMModGUI : public RollupWidget, public PluginInstanceUI { class AMModGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:

View File

@ -49,7 +49,7 @@ void AMModPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerTxChannel(AMModGUI::m_channelID, this); m_pluginAPI->registerTxChannel(AMModGUI::m_channelID, this);
} }
PluginInstanceUI* AMModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) PluginInstanceGUI* AMModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI)
{ {
if(channelName == AMModGUI::m_channelID) if(channelName == AMModGUI::m_channelID)
{ {

View File

@ -33,7 +33,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); PluginInstanceGUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -385,16 +385,20 @@ void ATVMod::pullVideo(Real& sample)
time_t start, end; time_t start, end;
cv::Mat frame; cv::Mat frame;
MsgReportCameraData *report; if (getMessageQueueToGUI())
report = MsgReportCameraData::create( {
camera.m_cameraNumber, MsgReportCameraData *report;
0.0f, report = MsgReportCameraData::create(
camera.m_videoFPSManual, camera.m_cameraNumber,
camera.m_videoFPSManualEnable, 0.0f,
camera.m_videoWidth, camera.m_videoFPSManual,
camera.m_videoHeight, camera.m_videoFPSManualEnable,
1); // open splash screen on GUI side camera.m_videoWidth,
getOutputMessageQueue()->push(report); camera.m_videoHeight,
1); // open splash screen on GUI side
getMessageQueueToGUI()->push(report);
}
int nbFrames = 0; int nbFrames = 0;
time(&start); time(&start);
@ -414,15 +418,19 @@ void ATVMod::pullVideo(Real& sample)
camera.m_videoFPSCount = camera.m_videoFPSq; camera.m_videoFPSCount = camera.m_videoFPSq;
camera.m_videoPrevFPSCount = 0; camera.m_videoPrevFPSCount = 0;
report = MsgReportCameraData::create( if (getMessageQueueToGUI())
camera.m_cameraNumber, {
camera.m_videoFPS, MsgReportCameraData *report;
camera.m_videoFPSManual, report = MsgReportCameraData::create(
camera.m_videoFPSManualEnable, camera.m_cameraNumber,
camera.m_videoWidth, camera.m_videoFPS,
camera.m_videoHeight, camera.m_videoFPSManual,
2); // close splash screen on GUI side camera.m_videoFPSManualEnable,
getOutputMessageQueue()->push(report); camera.m_videoWidth,
camera.m_videoHeight,
2); // close splash screen on GUI side
getMessageQueueToGUI()->push(report);
}
} }
else if (camera.m_videoFPS == 0.0f) // Hideous hack for windows else if (camera.m_videoFPS == 0.0f) // Hideous hack for windows
{ {
@ -431,16 +439,19 @@ void ATVMod::pullVideo(Real& sample)
camera.m_videoFPSCount = camera.m_videoFPSq; camera.m_videoFPSCount = camera.m_videoFPSq;
camera.m_videoPrevFPSCount = 0; camera.m_videoPrevFPSCount = 0;
MsgReportCameraData *report; if (getMessageQueueToGUI())
report = MsgReportCameraData::create( {
camera.m_cameraNumber, MsgReportCameraData *report;
camera.m_videoFPS, report = MsgReportCameraData::create(
camera.m_videoFPSManual, camera.m_cameraNumber,
camera.m_videoFPSManualEnable, camera.m_videoFPS,
camera.m_videoWidth, camera.m_videoFPSManual,
camera.m_videoHeight, camera.m_videoFPSManualEnable,
0); camera.m_videoWidth,
getOutputMessageQueue()->push(report); camera.m_videoHeight,
0);
getMessageQueueToGUI()->push(report);
}
} }
int fpsIncrement = (int) camera.m_videoFPSCount - camera.m_videoPrevFPSCount; int fpsIncrement = (int) camera.m_videoFPSCount - camera.m_videoPrevFPSCount;
@ -601,9 +612,12 @@ bool ATVMod::handleMessage(const Message& cmd)
framesCount = 0; framesCount = 0;
} }
MsgReportVideoFileSourceStreamTiming *report; if (getMessageQueueToGUI())
report = MsgReportVideoFileSourceStreamTiming::create(framesCount); {
getOutputMessageQueue()->push(report); MsgReportVideoFileSourceStreamTiming *report;
report = MsgReportVideoFileSourceStreamTiming::create(framesCount);
getMessageQueueToGUI()->push(report);
}
return true; return true;
} }
@ -615,16 +629,20 @@ bool ATVMod::handleMessage(const Message& cmd)
if (index < m_cameras.size()) if (index < m_cameras.size())
{ {
m_cameraIndex = index; m_cameraIndex = index;
MsgReportCameraData *report;
report = MsgReportCameraData::create( if (getMessageQueueToGUI())
m_cameras[m_cameraIndex].m_cameraNumber, {
m_cameras[m_cameraIndex].m_videoFPS, MsgReportCameraData *report;
m_cameras[m_cameraIndex].m_videoFPSManual, report = MsgReportCameraData::create(
m_cameras[m_cameraIndex].m_videoFPSManualEnable, m_cameras[m_cameraIndex].m_cameraNumber,
m_cameras[m_cameraIndex].m_videoWidth, m_cameras[m_cameraIndex].m_videoFPS,
m_cameras[m_cameraIndex].m_videoHeight, m_cameras[m_cameraIndex].m_videoFPSManual,
0); m_cameras[m_cameraIndex].m_videoFPSManualEnable,
getOutputMessageQueue()->push(report); m_cameras[m_cameraIndex].m_videoWidth,
m_cameras[m_cameraIndex].m_videoHeight,
0);
getMessageQueueToGUI()->push(report);
}
} }
return true; return true;
@ -721,9 +739,12 @@ void ATVMod::apply(bool force)
applyStandard(); // set all timings applyStandard(); // set all timings
m_settingsMutex.unlock(); m_settingsMutex.unlock();
MsgReportEffectiveSampleRate *report; if (getMessageQueueToGUI())
report = MsgReportEffectiveSampleRate::create(m_tvSampleRate, m_pointsPerLine); {
getOutputMessageQueue()->push(report); MsgReportEffectiveSampleRate *report;
report = MsgReportEffectiveSampleRate::create(m_tvSampleRate, m_pointsPerLine);
getMessageQueueToGUI()->push(report);
}
} }
if ((m_config.m_outputSampleRate != m_running.m_outputSampleRate) if ((m_config.m_outputSampleRate != m_running.m_outputSampleRate)
@ -977,9 +998,12 @@ void ATVMod::openVideo(const QString& fileName)
calculateVideoSizes(); calculateVideoSizes();
m_videoEOF = false; m_videoEOF = false;
MsgReportVideoFileSourceStreamData *report; if (getMessageQueueToGUI())
report = MsgReportVideoFileSourceStreamData::create(m_videoFPS, m_videoLength); {
getOutputMessageQueue()->push(report); MsgReportVideoFileSourceStreamData *report;
report = MsgReportVideoFileSourceStreamData::create(m_videoFPS, m_videoLength);
getMessageQueueToGUI()->push(report);
}
} }
else else
{ {
@ -1114,16 +1138,20 @@ void ATVMod::getCameraNumbers(std::vector<int>& numbers)
if (m_cameras.size() > 0) if (m_cameras.size() > 0)
{ {
m_cameraIndex = 0; m_cameraIndex = 0;
MsgReportCameraData *report;
report = MsgReportCameraData::create( if (getMessageQueueToGUI())
m_cameras[0].m_cameraNumber, {
m_cameras[0].m_videoFPS, MsgReportCameraData *report;
m_cameras[0].m_videoFPSManual, report = MsgReportCameraData::create(
m_cameras[0].m_videoFPSManualEnable, m_cameras[0].m_cameraNumber,
m_cameras[0].m_videoWidth, m_cameras[0].m_videoFPS,
m_cameras[0].m_videoHeight, m_cameras[0].m_videoFPSManual,
0); m_cameras[0].m_videoFPSManualEnable,
getOutputMessageQueue()->push(report); m_cameras[0].m_videoWidth,
m_cameras[0].m_videoHeight,
0);
getMessageQueueToGUI()->push(report);
}
} }
} }

View File

@ -363,7 +363,7 @@ void ATVModGUI::handleSourceMessages()
{ {
Message* message; Message* message;
while ((message = m_atvMod->getOutputMessageQueue()->pop()) != 0) while ((message = getInputMessageQueue()->pop()) != 0)
{ {
if (handleMessage(*message)) if (handleMessage(*message))
{ {
@ -622,6 +622,7 @@ ATVModGUI::ATVModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa
connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked()));
m_atvMod = new ATVMod(); m_atvMod = new ATVMod();
m_atvMod->setMessageQueueToGUI(getInputMessageQueue());
m_channelizer = new UpChannelizer(m_atvMod); m_channelizer = new UpChannelizer(m_atvMod);
m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this); m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this);
//m_pluginAPI->addThreadedSink(m_threadedChannelizer); //m_pluginAPI->addThreadedSink(m_threadedChannelizer);
@ -648,7 +649,7 @@ ATVModGUI::ATVModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa
resetToDefaults(); resetToDefaults();
connect(m_atvMod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
connect(m_atvMod, SIGNAL(levelChanged(qreal, qreal, int)), ui->volumeMeter, SLOT(levelChanged(qreal, qreal, int))); connect(m_atvMod, SIGNAL(levelChanged(qreal, qreal, int)), ui->volumeMeter, SLOT(levelChanged(qreal, qreal, int)));
std::vector<int> cameraNumbers; std::vector<int> cameraNumbers;

View File

@ -17,10 +17,10 @@
#ifndef PLUGINS_CHANNELTX_MODTV_ATVMODGUI_H_ #ifndef PLUGINS_CHANNELTX_MODTV_ATVMODGUI_H_
#define PLUGINS_CHANNELTX_MODTV_ATVMODGUI_H_ #define PLUGINS_CHANNELTX_MODTV_ATVMODGUI_H_
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h" #include "gui/rollupwidget.h"
#include "dsp/channelmarker.h" #include "dsp/channelmarker.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
#include "atvmod.h" #include "atvmod.h"
@ -37,7 +37,7 @@ namespace Ui {
class ATVModGUI; class ATVModGUI;
} }
class ATVModGUI : public RollupWidget, public PluginInstanceUI { class ATVModGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT Q_OBJECT
public: public:

View File

@ -23,7 +23,7 @@
const PluginDescriptor ATVModPlugin::m_pluginDescriptor = { const PluginDescriptor ATVModPlugin::m_pluginDescriptor = {
QString("ATV Modulator"), QString("ATV Modulator"),
QString("3.5.0"), QString("3.7.3"),
QString("(c) Edouard Griffiths, F4EXB"), QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"), QString("https://github.com/f4exb/sdrangel"),
true, true,
@ -49,7 +49,7 @@ void ATVModPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI->registerTxChannel(ATVModGUI::m_channelID, this); m_pluginAPI->registerTxChannel(ATVModGUI::m_channelID, this);
} }
PluginInstanceUI* ATVModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) PluginInstanceGUI* ATVModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI)
{ {
if(channelName == ATVModGUI::m_channelID) if(channelName == ATVModGUI::m_channelID)
{ {

View File

@ -33,7 +33,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const; const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); PluginInstanceGUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -367,7 +367,7 @@ bool NFMMod::handleMessage(const Message& cmd)
MsgReportFileSourceStreamTiming *report; MsgReportFileSourceStreamTiming *report;
report = MsgReportFileSourceStreamTiming::create(samplesCount); report = MsgReportFileSourceStreamTiming::create(samplesCount);
getOutputMessageQueue()->push(report); getMessageQueueToGUI()->push(report);
return true; return true;
} }
@ -462,7 +462,7 @@ void NFMMod::openFileStream()
MsgReportFileSourceStreamData *report; MsgReportFileSourceStreamData *report;
report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength); report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength);
getOutputMessageQueue()->push(report); getMessageQueueToGUI()->push(report);
} }
void NFMMod::seekFileStream(int seekPercentage) void NFMMod::seekFileStream(int seekPercentage)

Some files were not shown because too many files have changed in this diff Show More