1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-04 16:01:14 -05: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/scale.cpp
sdrbase/gui/scaleengine.cpp
sdrbase/gui/transverterbutton.cpp
sdrbase/gui/transverterdialog.cpp
sdrbase/gui/valuedial.cpp
sdrbase/gui/valuedialz.cpp
@ -386,6 +388,8 @@ set(sdrbase_HEADERS
sdrbase/gui/samplingdevicecontrol.h
sdrbase/gui/scale.h
sdrbase/gui/scaleengine.h
sdrbase/gui/transverterbutton.h
sdrbase/gui/transverterdialog.h
sdrbase/gui/valuedial.h
sdrbase/gui/valuedialz.h
@ -393,7 +397,7 @@ set(sdrbase_HEADERS
sdrbase/dsp/devicesamplesink.h
sdrbase/plugin/pluginapi.h
sdrbase/plugin/plugininstanceui.h
sdrbase/plugin/plugininstancegui.h
sdrbase/plugin/plugininterface.h
sdrbase/plugin/pluginmanager.h
@ -439,6 +443,7 @@ set(sdrbase_FORMS
sdrbase/gui/audiodialog.ui
sdrbase/gui/samplingdevicecontrol.ui
sdrbase/gui/myposdialog.ui
sdrbase/gui/transverterdialog.ui
)
set(sdrbase_RESOURCES

View File

@ -6,6 +6,7 @@
QT += core gui multimedia opengl
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
QMAKE_CXXFLAGS += -std=c++11
TEMPLATE = app
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
* 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
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
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.

View File

@ -56,20 +56,41 @@ bool DeviceLimeSDR::setNCOFrequency(lms_device_t *device, bool dir_tx, std::size
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;
}
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");
return false;
if (LMS_WriteParam(device,LMS7param(CMIX_BYP_TXTSP),1) < 0) {
fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot disable Tx NCO\n");
return false;
}
}
else
{
fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: NCO disabled\n");
return true;
if (LMS_WriteParam(device,LMS7param(CMIX_BYP_RXTSP),1) < 0) {
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)
# 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<ProPlus>::pluginDisplayedName = "FunCube Pro+ Input";
const char *fcd_traits<Pro>::pluginVersion = "3.5.0";
const char *fcd_traits<ProPlus>::pluginVersion = "3.5.0";
const char *fcd_traits<Pro>::pluginVersion = "3.7.3";
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 *pluginDisplayedName;
static const char *pluginVersion;
static const int64_t loLowLimitFreq;
static const int64_t loHighLimitFreq;
};
template<>
@ -46,6 +48,8 @@ struct fcd_traits<Pro>
static const char *displayedName;
static const char *pluginDisplayedName;
static const char *pluginVersion;
static const int64_t loLowLimitFreq;
static const int64_t loHighLimitFreq;
};
template<>
@ -62,6 +66,8 @@ struct fcd_traits<ProPlus>
static const char *displayedName;
static const char *pluginDisplayedName;
static const char *pluginVersion;
static const int64_t loLowLimitFreq;
static const int64_t loHighLimitFreq;
};
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/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "../../channelrx/chanalyzer/chanalyzer.h"
#include "chanalyzer.h"
#include <dsp/downchannelizer.h>
#include <QTime>
#include <QDebug>
#include <stdio.h>
#include <dsp/downchannelizer.h>
#include "dsp/threadedbasebandsamplesink.h"
#include "device/devicesourceapi.h"
#include "audio/audiooutput.h"
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelAnalyzer, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgReportChannelSampleRateChanged, Message)
ChannelAnalyzer::ChannelAnalyzer(BasebandSampleSink* sampleSink) :
m_sampleSink(sampleSink),
ChannelAnalyzer::ChannelAnalyzer(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_sampleSink(0),
m_settingsMutex(QMutex::Recursive)
{
m_Bandwidth = 5000;
@ -42,12 +48,20 @@ ChannelAnalyzer::ChannelAnalyzer(BasebandSampleSink* sampleSink) :
m_magsq = 0;
SSBFilter = new fftfilt(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate, 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()
{
if (SSBFilter) delete SSBFilter;
if (DSBFilter) delete DSBFilter;
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
}
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)
{
float band, lowCutoff;
@ -148,6 +168,16 @@ bool ChannelAnalyzer::handleMessage(const Message& cmd)
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))
{
MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd;

View File

@ -27,10 +27,87 @@
#define ssbFftLen 1024
class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class ChannelAnalyzer : public BasebandSampleSink {
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();
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
void configure(MessageQueue* messageQueue,
Real Bandwidth,
@ -46,41 +123,13 @@ public:
virtual void stop();
virtual bool handleMessage(const Message& cmd);
private slots:
void channelSampleRateChanged();
private:
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)
{ }
};
DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
Real m_Bandwidth;
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;
}
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()
{
applySettings();
@ -171,11 +192,6 @@ void ChannelAnalyzerGUI::tick()
ui->channelPower->setText(QString::number(m_channelPowerDbAvg.average(), 'f', 1));
}
void ChannelAnalyzerGUI::channelSampleRateChanged()
{
setNewRate(m_spanLog2);
}
void ChannelAnalyzerGUI::on_deltaMinus_toggled(bool minus)
{
int deltaFrequency = m_channelMarker.getCenterFrequency();
@ -326,11 +342,9 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceSourceAPI *de
m_spectrumVis = new SpectrumVis(ui->glSpectrum);
m_scopeVis = new ScopeVis(ui->glScope);
m_spectrumScopeComboVis = new SpectrumScopeComboVis(m_spectrumVis, m_scopeVis);
m_channelAnalyzer = new ChannelAnalyzer(m_spectrumScopeComboVis);
m_channelizer = new DownChannelizer(m_channelAnalyzer);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged()));
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
m_channelAnalyzer = new ChannelAnalyzer(m_deviceAPI);
m_channelAnalyzer->setSampleSink(m_spectrumScopeComboVis);
m_channelAnalyzer->setMessageQueueToGUI(getInputMessageQueue());
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold));
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->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
applySettings();
setNewRate(m_spanLog2);
}
@ -368,9 +384,6 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceSourceAPI *de
ChannelAnalyzerGUI::~ChannelAnalyzerGUI()
{
m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
delete m_channelAnalyzer;
delete m_spectrumVis;
delete m_scopeVis;
@ -457,9 +470,8 @@ void ChannelAnalyzerGUI::applySettings()
ui->deltaFrequency->setValue(abs(m_channelMarker.getCenterFrequency()));
ui->deltaMinus->setChecked(m_channelMarker.getCenterFrequency() < 0);
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
m_channelizer->getInputSampleRate(),
m_channelMarker.getCenterFrequency());
ChannelAnalyzer::MsgConfigureChannelizer *msg = ChannelAnalyzer::MsgConfigureChannelizer::create(m_channelMarker.getCenterFrequency());
m_channelAnalyzer->getInputMessageQueue()->push(msg);
m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(),
ui->BW->value() * 100.0,

View File

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

View File

@ -33,7 +33,7 @@ void ChannelAnalyzerPlugin::initPlugin(PluginAPI* pluginAPI)
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)
{

View File

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

View File

@ -16,17 +16,23 @@
#include "chanalyzerng.h"
#include <dsp/downchannelizer.h>
#include <QTime>
#include <QDebug>
#include <stdio.h>
#include "device/devicesourceapi.h"
#include "audio/audiooutput.h"
#include "dsp/threadedbasebandsamplesink.h"
#include "dsp/downchannelizer.h"
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelAnalyzer, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgReportChannelSampleRateChanged, Message)
ChannelAnalyzerNG::ChannelAnalyzerNG(BasebandSampleSink* sampleSink) :
m_sampleSink(sampleSink),
ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_sampleSink(0),
m_settingsMutex(QMutex::Recursive)
{
m_undersampleCount = 0;
@ -38,6 +44,12 @@ ChannelAnalyzerNG::ChannelAnalyzerNG(BasebandSampleSink* sampleSink) :
m_interpolatorDistanceRemain = 0.0f;
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);
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);
}
@ -45,6 +57,9 @@ ChannelAnalyzerNG::~ChannelAnalyzerNG()
{
if (SSBFilter) delete SSBFilter;
if (DSBFilter) delete DSBFilter;
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
}
void ChannelAnalyzerNG::configure(MessageQueue* messageQueue,
@ -54,7 +69,7 @@ void ChannelAnalyzerNG::configure(MessageQueue* messageQueue,
int spanLog2,
bool ssb)
{
Message* cmd = MsgConfigureChannelAnalyzer::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb);
Message* cmd = MsgConfigureChannelAnalyzer::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb);
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)
{
qDebug() << "ChannelAnalyzerNG::handleMessage: " << cmd.getIdentifier();
@ -120,11 +141,19 @@ bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
apply();
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))
{
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_LowCutoff = cfg.getLoCutoff();
m_config.m_spanLog2 = cfg.getSpanLog2();
@ -153,6 +182,8 @@ bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
}
}
void ChannelAnalyzerNG::apply(bool force)
{
if ((m_running.m_frequency != m_config.m_frequency) ||

View File

@ -29,10 +29,102 @@
#define ssbFftLen 1024
class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class ChannelAnalyzerNG : public BasebandSampleSink {
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();
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
void configure(MessageQueue* messageQueue,
int channelSampleRate,
@ -41,6 +133,7 @@ public:
int spanLog2,
bool ssb);
DownChannelizer *getChannelizer() { return m_channelizer; }
int getInputSampleRate() const { return m_running.m_inputSampleRate; }
int getChannelSampleRate() const { return m_running.m_channelSampleRate; }
double getMagSq() const { return m_magsq; }
@ -50,48 +143,10 @@ public:
virtual void stop();
virtual bool handleMessage(const Message& cmd);
private slots:
void channelizerInputSampleRateChanged();
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
{
@ -117,6 +172,10 @@ private:
Config m_config;
Config m_running;
DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
int m_undersampleCount;
fftfilt::cmplx m_sum;
bool m_usb;

View File

@ -159,7 +159,29 @@ bool ChannelAnalyzerNGGUI::deserialize(const QByteArray& data)
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()
@ -174,12 +196,12 @@ void ChannelAnalyzerNGGUI::tick()
ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.average(), 0, 'f', 1));
}
void ChannelAnalyzerNGGUI::channelizerInputSampleRateChanged()
{
//ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate());
setNewFinalRate(m_spanLog2);
applySettings();
}
//void ChannelAnalyzerNGGUI::channelizerInputSampleRateChanged()
//{
// //ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate());
// setNewFinalRate(m_spanLog2);
// applySettings();
//}
void ChannelAnalyzerNGGUI::on_channelSampleRate_changed(quint64 value)
{
@ -204,7 +226,7 @@ int ChannelAnalyzerNGGUI::getRequestedChannelSampleRate()
if (ui->useRationalDownsampler->isChecked()) {
return ui->channelSampleRate->getValueNew();
} 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_scopeVis = new ScopeVisNG(ui->glScope);
m_spectrumScopeComboVis = new SpectrumScopeNGComboVis(m_spectrumVis, m_scopeVis);
m_channelAnalyzer = new ChannelAnalyzerNG(m_spectrumScopeComboVis);
m_channelizer = new DownChannelizer(m_channelAnalyzer);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged()));
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
m_channelAnalyzer = new ChannelAnalyzerNG(m_deviceAPI);
m_channelAnalyzer->setSampleSink(m_spectrumScopeComboVis);
m_channelAnalyzer->setMessageQueueToGUI(getInputMessageQueue());
// m_channelizer = new DownChannelizer(m_channelAnalyzer);
// 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->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->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
applySettings();
setNewFinalRate(m_spanLog2);
}
@ -396,9 +422,9 @@ ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceSourceAPI
ChannelAnalyzerNGGUI::~ChannelAnalyzerNGGUI()
{
m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
// m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
// delete m_threadedChannelizer;
// delete m_channelizer;
delete m_channelAnalyzer;
delete m_spectrumVis;
delete m_scopeVis;
@ -514,14 +540,25 @@ void ChannelAnalyzerNGGUI::applySettings()
setTitleColor(m_channelMarker.getColor());
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
//m_channelizer->getInputSampleRate(),
getRequestedChannelSampleRate(),
m_channelMarker.getCenterFrequency());
int sampleRate = getRequestedChannelSampleRate();
ChannelAnalyzerNG::MsgConfigureChannelizer *msgChannelizer = ChannelAnalyzerNG::MsgConfigureChannelizer::create(sampleRate, 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_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->lowCut->value() * 100.0,
m_spanLog2,

View File

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

View File

@ -48,7 +48,7 @@ void ChannelAnalyzerNGPlugin::initPlugin(PluginAPI* pluginAPI)
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)
{

View File

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

View File

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

View File

@ -26,12 +26,16 @@
#include "audio/audiooutput.h"
#include "dsp/dspengine.h"
#include "dsp/pidcontroller.h"
#include "dsp/threadedbasebandsamplesink.h"
#include "device/devicesourceapi.h"
MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message)
MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureChannelizer, Message)
const int AMDemod::m_udpBlockSize = 512;
AMDemod::AMDemod() :
AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_squelchOpen(false),
m_magsqSum(0.0f),
m_magsqPeak(0.0f),
@ -43,14 +47,9 @@ AMDemod::AMDemod() :
{
setObjectName("AMDemod");
m_config.m_inputSampleRate = 96000;
m_config.m_inputFrequencyOffset = 0;
m_config.m_rfBandwidth = 5000;
m_config.m_squelch = -40.0;
m_config.m_volume = 2.0;
m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
apply();
m_channelizer = new DownChannelizer(this);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
m_audioBuffer.resize(1<<14);
m_audioBufferFill = 0;
@ -60,7 +59,9 @@ AMDemod::AMDemod() :
m_magsq = 0.0;
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()
@ -69,29 +70,6 @@ AMDemod::~AMDemod()
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)))
{
Complex ci;
@ -142,8 +120,8 @@ void AMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector
void AMDemod::start()
{
qDebug() << "AMDemod::start: m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset;
qDebug() << "AMDemod::start: m_inputSampleRate: " << m_settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_settings.m_inputFrequencyOffset;
m_squelchCount = 0;
m_audioFifo.clear();
@ -161,41 +139,51 @@ bool AMDemod::handleMessage(const Message& cmd)
{
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
m_config.m_inputSampleRate = notif.getSampleRate();
m_config.m_inputFrequencyOffset = notif.getFrequencyOffset();
AMDemodSettings settings = m_settings;
apply();
settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
qDebug() << "AMDemod::handleMessage: MsgChannelizerNotification:"
<< " m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset;
applySettings(settings);
qDebug() << "AMDemod::handleMessage: MsgChannelizerNotification:"
<< " m_inputSampleRate: " << settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset;
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))
{
MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd;
MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd;
m_config.m_rfBandwidth = cfg.getRFBandwidth();
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();
AMDemodSettings settings = cfg.getSettings();
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:"
<< " m_rfBandwidth: " << m_config.m_rfBandwidth
<< " m_volume: " << m_config.m_volume
<< " m_squelch: " << m_config.m_squelch
<< " m_audioMute: " << m_config.m_audioMute
<< " m_bandpassEnable: " << m_config.m_bandpassEnable
<< " m_copyAudioToUDP: " << m_config.m_copyAudioToUDP
<< " m_udpAddress: " << m_config.m_udpAddress
<< " m_udpPort: " << m_config.m_udpPort;
applySettings(settings, cfg.getForce());
qDebug() << "AMDemod::handleMessage: MsgConfigureAMDemod:"
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_volume: " << settings.m_volume
<< " m_squelch: " << settings.m_squelch
<< " m_audioMute: " << settings.m_audioMute
<< " m_bandpassEnable: " << settings.m_bandpassEnable
<< " m_copyAudioToUDP: " << settings.m_copyAudioToUDP
<< " m_udpAddress: " << settings.m_udpAddress
<< " m_udpPort: " << settings.m_udpPort
<< " force: " << cfg.getForce();
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_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) ||
(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)
if ((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) ||
(m_settings.m_inputSampleRate != settings.m_inputSampleRate) || force)
{
m_udpBufferAudio->setAddress(m_config.m_udpAddress);
m_udpBufferAudio->setPort(m_config.m_udpPort);
m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate);
}
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 "audio/audiofifo.h"
#include "util/message.h"
#include "amdemodsettings.h"
class DeviceSourceAPI;
class DownChannelizer;
class ThreadedBasebandSampleSink;
class AMDemod : public BasebandSampleSink {
Q_OBJECT
public:
AMDemod();
~AMDemod();
class MsgConfigureAMDemod : public Message {
MESSAGE_CLASS_DECLARATION
void configure(MessageQueue* messageQueue,
Real rfBandwidth,
Real volume,
Real squelch,
bool audioMute,
bool bandpassEnable,
bool copyAudioToUDP,
const QString& udpAddress,
quint16 udpPort,
bool force);
public:
const AMDemodSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureAMDemod* create(const AMDemodSettings& settings, bool force)
{
return new MsgConfigureAMDemod(settings, 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 start();
@ -64,109 +104,16 @@ public:
}
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 {
RSInitialFill,
RSRunning
};
struct Config {
int m_inputSampleRate;
qint64 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;
DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
Config() :
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;
AMDemodSettings m_settings;
NCO m_nco;
Interpolator m_interpolator;
@ -194,7 +141,8 @@ private:
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)
{
@ -213,9 +161,9 @@ private:
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);
}
@ -232,28 +180,28 @@ private:
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);
m_volumeAGC.feed(demod);
demod = (demod - m_volumeAGC.getValue()) / m_volumeAGC.getValue();
if (m_running.m_bandpassEnable)
if (m_settings.m_bandpassEnable)
{
demod = m_bandpass.filter(demod);
demod /= 301.0f;
}
Real attack = (m_squelchCount - 0.05f * m_running.m_audioSampleRate) / (0.05f * m_running.m_audioSampleRate);
sample = demod * attack * 2048 * m_running.m_volume;
if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(demod * attack * 32768);
Real attack = (m_squelchCount - 0.05f * m_settings.m_audioSampleRate) / (0.05f * m_settings.m_audioSampleRate);
sample = demod * attack * 2048 * m_settings.m_volume;
if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(demod * attack * 32768);
m_squelchOpen = true;
}
else
{
sample = 0;
if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(0);
if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(0);
m_squelchOpen = false;
}
@ -273,6 +221,7 @@ private:
m_audioBufferFill = 0;
}
}
};
#endif // INCLUDE_AMDEMOD_H

View File

@ -68,83 +68,27 @@ void AMDemodGUI::setCenterFrequency(qint64 centerFrequency)
void AMDemodGUI::resetToDefaults()
{
blockApplySettings(true);
ui->rfBW->setValue(50);
ui->volume->setValue(20);
ui->squelch->setValue(-40);
ui->deltaFrequency->setValue(0);
blockApplySettings(false);
applySettings();
m_settings.resetToDefaults();
displaySettings();
applySettings(true);
}
QByteArray AMDemodGUI::serialize() const
{
SimpleSerializer s(1);
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();
return m_settings.serialize();
}
bool AMDemodGUI::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid())
{
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;
}
if(m_settings.deserialize(data)) {
updateChannelMarker();
displaySettings();
applySettings(true);
return true;
} else {
resetToDefaults();
return false;
}
}
bool AMDemodGUI::handleMessage(const Message& message __attribute__((unused)))
@ -155,17 +99,25 @@ bool AMDemodGUI::handleMessage(const Message& message __attribute__((unused)))
void AMDemodGUI::channelMarkerChanged()
{
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();
//m_settings.m_channelMarkerBytes = m_channelMarker.serialize();
applySettings();
}
void AMDemodGUI::on_deltaFrequency_changed(qint64 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();
}
@ -173,28 +125,33 @@ void AMDemodGUI::on_rfBW_valueChanged(int value)
{
ui->rfBWText->setText(QString("%1 kHz").arg(value / 10.0, 0, 'f', 1));
m_channelMarker.setBandwidth(value * 100);
m_settings.m_rfBandwidth = value * 100;
applySettings();
}
void AMDemodGUI::on_volume_valueChanged(int value)
{
ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
m_settings.m_volume = value / 10.0;
applySettings();
}
void AMDemodGUI::on_squelch_valueChanged(int value)
{
ui->squelchText->setText(QString("%1 dB").arg(value));
m_settings.m_squelch = value;
applySettings();
}
void AMDemodGUI::on_audioMute_toggled(bool checked __attribute__((unused)))
void AMDemodGUI::on_audioMute_toggled(bool checked)
{
m_settings.m_audioMute = checked;
applySettings();
}
void AMDemodGUI::on_copyAudioToUDP_toggled(bool checked __attribute__((unused)))
void AMDemodGUI::on_copyAudioToUDP_toggled(bool checked)
{
m_settings.m_copyAudioToUDP = checked;
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(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
m_amDemod = new AMDemod();
m_channelizer = new DownChannelizer(m_amDemod);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
//m_pluginAPI->addThreadedSink(m_threadedChannelizer);
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
m_amDemod = new AMDemod(m_deviceAPI);
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->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue);
//m_channelMarker = new ChannelMarker(this);
m_channelMarker.setColor(Qt::yellow);
m_channelMarker.setBandwidth(5000);
m_channelMarker.setCenterFrequency(0);
@ -250,6 +202,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget
m_channelMarker.setUDPSendPort(9999);
m_channelMarker.setVisible(true);
setTitleColor(m_channelMarker.getColor());
m_settings.setChannelMarker(&m_channelMarker);
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->addRollupWidget(this);
displaySettings();
applySettings(true);
}
AMDemodGUI::~AMDemodGUI()
{
m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
delete m_amDemod;
//delete m_channelMarker;
delete ui;
}
@ -282,30 +232,62 @@ void AMDemodGUI::applySettings(bool force)
{
setTitleColor(m_channelMarker.getColor());
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
48000,
m_channelMarker.getCenterFrequency());
AMDemod::MsgConfigureChannelizer* channelConfigMsg = AMDemod::MsgConfigureChannelizer::create(
48000, m_channelMarker.getCenterFrequency());
m_amDemod->getInputMessageQueue()->push(channelConfigMsg);
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_amDemod->configure(m_amDemod->getInputMessageQueue(),
ui->rfBW->value() * 100.0,
ui->volume->value() / 10.0,
ui->squelch->value(),
ui->audioMute->isChecked(),
ui->bandpassEnable->isChecked(),
ui->copyAudioToUDP->isChecked(),
m_channelMarker.getUDPAddress(),
m_channelMarker.getUDPSendPort(),
force);
AMDemod::MsgConfigureAMDemod* message = AMDemod::MsgConfigureAMDemod::create( m_settings, force);
m_amDemod->getInputMessageQueue()->push(message);
}
}
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()
{
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*)
{
blockApplySettings(true);

View File

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

View File

@ -7,7 +7,7 @@
const PluginDescriptor AMDemodPlugin::m_pluginDescriptor = {
QString("AM Demodulator"),
QString("3.6.1"),
QString("3.7.3"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
@ -33,7 +33,7 @@ void AMDemodPlugin::initPlugin(PluginAPI* pluginAPI)
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)
{

View File

@ -33,7 +33,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private:
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\
amdemodgui.cpp\
amdemodplugin.cpp
amdemodplugin.cpp\
amdemodsettings.cpp
HEADERS += amdemod.h\
amdemodgui.h\
amdemodplugin.h
amdemodplugin.h\
amdemodsettings.h
FORMS += amdemodgui.ui

View File

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

View File

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

View File

@ -61,12 +61,12 @@ QString ATVDemodGUI::getName() const
qint64 ATVDemodGUI::getCenterFrequency() const
{
return m_objChannelMarker.getCenterFrequency();
return m_channelMarker.getCenterFrequency();
}
void ATVDemodGUI::setCenterFrequency(qint64 intCenterFrequency)
{
m_objChannelMarker.setCenterFrequency(intCenterFrequency);
m_channelMarker.setCenterFrequency(intCenterFrequency);
applySettings();
}
@ -105,8 +105,8 @@ QByteArray ATVDemodGUI::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_objChannelMarker.getCenterFrequency());
s.writeU32(2, m_objChannelMarker.getColor().rgb());
s.writeS32(1, m_channelMarker.getCenterFrequency());
s.writeU32(2, m_channelMarker.getColor().rgb());
s.writeS32(3, ui->synchLevel->value());
s.writeS32(4, ui->blackLevel->value());
s.writeS32(5, ui->lineTime->value());
@ -144,10 +144,10 @@ bool ATVDemodGUI::deserialize(const QByteArray& arrData)
bool booltmp;
blockApplySettings(true);
m_objChannelMarker.blockSignals(true);
m_channelMarker.blockSignals(true);
d.readS32(1, &tmp, 0);
m_objChannelMarker.setCenterFrequency(tmp);
m_channelMarker.setCenterFrequency(tmp);
// if (d.readU32(2, &u32tmp)) {
// m_objChannelMarker.setColor(u32tmp);
@ -189,7 +189,7 @@ bool ATVDemodGUI::deserialize(const QByteArray& arrData)
ui->standard->setCurrentIndex(tmp);
blockApplySettings(false);
m_objChannelMarker.blockSignals(false);
m_channelMarker.blockSignals(false);
lineTimeUpdate();
topTimeUpdate();
@ -211,7 +211,7 @@ bool ATVDemodGUI::handleMessage(const Message& objMessage)
int nbPointsPerLine = ((ATVDemod::MsgReportEffectiveSampleRate&)objMessage).getNbPointsPerLine();
ui->channelSampleRateText->setText(tr("%1k").arg(sampleRate/1000.0f, 0, 'f', 2));
ui->nbPointsPerLineText->setText(tr("%1p").arg(nbPointsPerLine));
m_objScopeVis->setSampleRate(sampleRate);
m_scopeVis->setSampleRate(sampleRate);
setRFFiltersSlidersRange(sampleRate);
lineTimeUpdate();
topTimeUpdate();
@ -242,7 +242,7 @@ void ATVDemodGUI::handleSourceMessages()
{
Message* message;
while ((message = m_objATVDemod->getOutputMessageQueue()->pop()) != 0)
while ((message = getInputMessageQueue()->pop()) != 0)
{
if (handleMessage(*message))
{
@ -261,7 +261,7 @@ void ATVDemodGUI::onMenuDoubleClicked()
{
m_blnBasicSettingsShown = true;
BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(
&m_objChannelMarker, this);
&m_channelMarker, this);
bcsw->show();
}
}
@ -270,9 +270,9 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI,
QWidget* objParent) :
RollupWidget(objParent),
ui(new Ui::ATVDemodGUI),
m_objPluginAPI(objPluginAPI),
m_objDeviceAPI(objDeviceAPI),
m_objChannelMarker(this),
m_pluginAPI(objPluginAPI),
m_deviceAPI(objDeviceAPI),
m_channelMarker(this),
m_blnBasicSettingsShown(false),
m_blnDoApplySettings(true),
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(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked()));
m_objScopeVis = new ScopeVisNG(ui->glScope);
m_objATVDemod = new ATVDemod(m_objScopeVis);
m_objATVDemod->setATVScreen(ui->screenTV);
m_scopeVis = new ScopeVisNG(ui->glScope);
m_atvDemod = new ATVDemod(m_deviceAPI);
m_atvDemod->setScopeSink(m_scopeVis);
m_atvDemod->setMessageQueueToGUI(getInputMessageQueue());
m_atvDemod->setATVScreen(ui->screenTV);
m_objChannelizer = new DownChannelizer(m_objATVDemod);
m_objThreadedChannelizer = new ThreadedBasebandSampleSink(m_objChannelizer, this);
m_objDeviceAPI->addThreadedSink(m_objThreadedChannelizer);
m_channelizer = new DownChannelizer(m_atvDemod);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
ui->glScope->connectTimer(m_objPluginAPI->getMainWindow()->getMasterTimer());
connect(&m_objPluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
ui->glScope->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer());
connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
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_objChannelMarker.setColor(Qt::white);
m_objChannelMarker.setMovable(false);
m_objChannelMarker.setBandwidth(6000000);
m_objChannelMarker.setCenterFrequency(0);
m_objChannelMarker.setVisible(true);
setTitleColor(m_objChannelMarker.getColor());
m_channelMarker.setColor(Qt::white);
m_channelMarker.setMovable(false);
m_channelMarker.setBandwidth(6000000);
m_channelMarker.setCenterFrequency(0);
m_channelMarker.setVisible(true);
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_objDeviceAPI->addChannelMarker(&m_objChannelMarker);
m_objDeviceAPI->addRollupWidget(this);
m_deviceAPI->registerChannelInstance(m_strChannelID, this);
m_deviceAPI->addChannelMarker(&m_channelMarker);
m_deviceAPI->addRollupWidget(this);
//ui->screenTV->connectTimer(m_objPluginAPI->getMainWindow()->getMasterTimer());
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()
@ -337,7 +339,7 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI,
ui->scopeGUI->changeTrigger(0, triggerData);
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);
ui->fmDeviationLabel->setText(delta);
@ -345,12 +347,12 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI,
ATVDemodGUI::~ATVDemodGUI()
{
m_objDeviceAPI->removeChannelInstance(this);
m_objDeviceAPI->removeThreadedSink(m_objThreadedChannelizer);
delete m_objThreadedChannelizer;
delete m_objChannelizer;
delete m_objATVDemod;
delete m_objScopeVis;
m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
delete m_atvDemod;
delete m_scopeVis;
delete ui;
}
@ -363,13 +365,13 @@ void ATVDemodGUI::applySettings()
{
if (m_blnDoApplySettings)
{
ui->deltaFrequency->setValue(m_objChannelMarker.getCenterFrequency());
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_objChannelizer->configure(m_objChannelizer->getInputMessageQueue(),
m_objChannelizer->getInputSampleRate(), // always use maximum available bandwidth
m_objChannelMarker.getCenterFrequency());
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
m_channelizer->getInputSampleRate(), // always use maximum available bandwidth
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()) * (4.7f / 64.0f) + ui->topTime->value() * m_fltTopTimeMultiplier,
getFps(ui->fps->currentIndex()),
@ -384,8 +386,8 @@ void ATVDemodGUI::applySettings()
ui->screenTabWidget->currentIndex());
qDebug() << "ATVDemodGUI::applySettings:"
<< " m_objChannelizer.inputSampleRate: " << m_objChannelizer->getInputSampleRate()
<< " m_objATVDemod.sampleRate: " << m_objATVDemod->getSampleRate();
<< " m_objChannelizer.inputSampleRate: " << m_channelizer->getInputSampleRate()
<< " m_objATVDemod.sampleRate: " << m_atvDemod->getSampleRate();
}
}
@ -393,7 +395,7 @@ void ATVDemodGUI::applyRFSettings()
{
if (m_blnDoApplySettings)
{
m_objATVDemod->configureRF(m_objATVDemod->getInputMessageQueue(),
m_atvDemod->configureRF(m_atvDemod->getInputMessageQueue(),
(ATVDemod::ATVModulation) ui->modulation->currentIndex(),
ui->rfBW->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
{
m_objChannelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor);
m_objChannelMarker.setOppositeBandwidth(ui->rfOppBW->value()*m_rfSliderDivisor);
m_channelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor);
m_channelMarker.setOppositeBandwidth(ui->rfOppBW->value()*m_rfSliderDivisor);
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) {
m_objChannelMarker.setSidebands(ChannelMarker::vusb);
m_channelMarker.setSidebands(ChannelMarker::vusb);
} else {
m_objChannelMarker.setSidebands(ChannelMarker::vusb);
m_channelMarker.setSidebands(ChannelMarker::vusb);
}
}
else
{
if (ui->decimatorEnable->isChecked()) {
m_objChannelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor);
m_channelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor);
} 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;
@ -463,14 +465,14 @@ void ATVDemodGUI::setRFFiltersSlidersRange(int sampleRate)
void ATVDemodGUI::leaveEvent(QEvent*)
{
blockApplySettings(true);
m_objChannelMarker.setHighlighted(false);
m_channelMarker.setHighlighted(false);
blockApplySettings(false);
}
void ATVDemodGUI::enterEvent(QEvent*)
{
blockApplySettings(true);
m_objChannelMarker.setHighlighted(true);
m_channelMarker.setHighlighted(true);
blockApplySettings(false);
}
@ -482,13 +484,13 @@ void ATVDemodGUI::tick()
}
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));
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; }");
} else {
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)))
{
setRFFiltersSlidersRange(m_objATVDemod->getEffectiveSampleRate());
setRFFiltersSlidersRange(m_atvDemod->getEffectiveSampleRate());
setChannelMarkerBandwidth();
applyRFSettings();
}
@ -594,7 +596,7 @@ void ATVDemodGUI::on_rfOppBW_valueChanged(int value)
void ATVDemodGUI::on_rfFiltering_toggled(bool checked __attribute__((unused)))
{
setRFFiltersSlidersRange(m_objATVDemod->getEffectiveSampleRate());
setRFFiltersSlidersRange(m_atvDemod->getEffectiveSampleRate());
setChannelMarkerBandwidth();
applyRFSettings();
}
@ -607,7 +609,7 @@ void ATVDemodGUI::on_decimatorEnable_toggled(bool checked __attribute__((unused)
void ATVDemodGUI::on_deltaFrequency_changed(qint64 value)
{
m_objChannelMarker.setCenterFrequency(value);
m_channelMarker.setCenterFrequency(value);
}
void ATVDemodGUI::on_bfo_valueChanged(int value)
@ -632,10 +634,10 @@ void ATVDemodGUI::lineTimeUpdate()
float nominalLineTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex());
int lineTimeScaleFactor = (int) std::log10(nominalLineTime);
if (m_objATVDemod->getEffectiveSampleRate() == 0) {
if (m_atvDemod->getEffectiveSampleRate() == 0) {
m_fltLineTimeMultiplier = std::pow(10.0, lineTimeScaleFactor-3);
} else {
m_fltLineTimeMultiplier = 1.0f / m_objATVDemod->getEffectiveSampleRate();
m_fltLineTimeMultiplier = 1.0f / m_atvDemod->getEffectiveSampleRate();
}
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);
int topTimeScaleFactor = (int) std::log10(nominalTopTime);
if (m_objATVDemod->getEffectiveSampleRate() == 0) {
if (m_atvDemod->getEffectiveSampleRate() == 0) {
m_fltTopTimeMultiplier = std::pow(10.0, topTimeScaleFactor-3);
} else {
m_fltTopTimeMultiplier = 1.0f / m_objATVDemod->getEffectiveSampleRate();
m_fltTopTimeMultiplier = 1.0f / m_atvDemod->getEffectiveSampleRate();
}
float topTime = nominalTopTime + m_fltTopTimeMultiplier * ui->topTime->value();

View File

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

View File

@ -26,7 +26,7 @@
const PluginDescriptor ATVDemodPlugin::m_ptrPluginDescriptor =
{
QString("ATV Demodulator"),
QString("3.5.0"),
QString("3.7.3"),
QString("(c) F4HKW for F4EXB / SDRAngel"),
QString("https://github.com/f4exb/sdrangel"),
true,
@ -53,7 +53,7 @@ void ATVDemodPlugin::initPlugin(PluginAPI* ptrPluginAPI)
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)
{

View File

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

View File

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

View File

@ -15,63 +15,77 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "../../channelrx/demodbfm/bfmdemod.h"
#include <QTime>
#include <QDebug>
#include <stdio.h>
#include <complex.h>
#include "audio/audiooutput.h"
#include "dsp/dspengine.h"
#include "dsp/pidcontroller.h"
#include "bfmdemod.h"
#include <dsp/downchannelizer.h>
#include "dsp/threadedbasebandsamplesink.h"
#include "device/devicesourceapi.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)
const Real BFMDemod::default_deemphasis = 50.0; // 50 us
const int BFMDemod::m_udpBlockSize = 512;
BFMDemod::BFMDemod(BasebandSampleSink* sampleSink, RDSParser *rdsParser) :
m_sampleSink(sampleSink),
BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_audioFifo(250000),
m_settingsMutex(QMutex::Recursive),
m_pilotPLL(19000/384000, 50/384000, 0.01),
m_rdsParser(rdsParser),
m_deemphasisFilterX(default_deemphasis * 48000 * 1.0e-6),
m_deemphasisFilterY(default_deemphasis * 48000 * 1.0e-6),
m_fmExcursion(default_excursion)
{
setObjectName("BFMDemod");
m_config.m_inputSampleRate = 384000;
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_magsq = 0.0f;
m_magsqSum = 0.0f;
m_magsqPeak = 0.0f;
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);
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()
@ -83,35 +97,10 @@ BFMDemod::~BFMDemod()
DSPEngine::instance()->removeAudioSink(&m_audioFifo);
delete m_udpBufferAudio;
}
void BFMDemod::configure(MessageQueue* messageQueue,
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* cmd = MsgConfigureBFMDemod::create(rfBandwidth,
afBandwidth,
volume,
squelch,
audioStereo,
lsbStereo,
showPilot,
rdsActive,
copyAudioToUDP,
udpAddress,
udpPort,
force);
messageQueue->push(cmd);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
}
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);
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)
@ -164,12 +153,12 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
demod = 0;
}
if (!m_running.m_showPilot)
if (!m_settings.m_showPilot)
{
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);
@ -182,10 +171,7 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
{
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
if (m_running.m_audioStereo)
if (m_settings.m_audioStereo)
{
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
}
if (m_running.m_lsbStereo)
if (m_settings.m_lsbStereo)
{
// 1.17 * 0.7 = 0.819
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_running.m_audioStereo)
if (m_settings.m_audioStereo)
{
Real deemph_l, deemph_r; // Pre-emphasis is applied on each channel before multiplexing
m_deemphasisFilterX.process(ci.real() + sampleStereo, deemph_l);
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].r = (qint16)(deemph_r * (1<<12) * m_running.m_volume);
if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]);
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_settings.m_volume);
if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]);
}
else
{
m_audioBuffer[m_audioBufferFill].l = (qint16)(deemph_l * (1<<12) * m_running.m_volume);
m_audioBuffer[m_audioBufferFill].r = (qint16)(deemph_r * (1<<12) * m_running.m_volume);
if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]);
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_settings.m_volume);
if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]);
}
}
else
{
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].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;
@ -313,54 +299,58 @@ void BFMDemod::stop()
{
}
void BFMDemod::channelSampleRateChanged()
{
MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create(getSampleRate());
getMessageQueueToGUI()->push(msg);
}
bool BFMDemod::handleMessage(const Message& cmd)
{
if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
m_config.m_inputSampleRate = notif.getSampleRate();
m_config.m_inputFrequencyOffset = notif.getFrequencyOffset();
BFMDemodSettings settings = m_settings;
apply();
settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
qDebug() << "BFMDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset;
applySettings(settings);
qDebug() << "BFMDemod::handleMessage: MsgChannelizerNotification:"
<< " m_inputSampleRate: " << settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset;
return true;
}
else if (MsgConfigureBFMDemod::match(cmd))
{
MsgConfigureBFMDemod& cfg = (MsgConfigureBFMDemod&) cmd;
else if (MsgConfigureBFMDemod::match(cmd))
{
MsgConfigureBFMDemod& cfg = (MsgConfigureBFMDemod&) cmd;
m_config.m_rfBandwidth = cfg.getRFBandwidth();
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();
BFMDemodSettings settings = cfg.getSettings();
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
<< " 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;
applySettings(settings, cfg.getForce());
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
{
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)
|| (m_config.m_audioStereo && (m_config.m_audioStereo != m_running.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)
if ((settings.m_inputSampleRate != m_settings.m_inputSampleRate)
|| (settings.m_audioStereo && (settings.m_audioStereo != m_settings.m_audioStereo)) || force)
{
m_udpBufferAudio->setAddress(m_config.m_udpAddress);
m_udpBufferAudio->setPort(m_config.m_udpPort);
m_pilotPLL.configure(19000.0/settings.m_inputSampleRate, 50.0/settings.m_inputSampleRate, 0.01);
}
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/udpsink.h"
#include "rdsparser.h"
#include "rdsdecoder.h"
#include "rdsdemod.h"
#include "bfmdemodsettings.h"
class RDSParser;
class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class BFMDemod : public BasebandSampleSink {
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();
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
void configure(MessageQueue* messageQueue,
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; }
int getSampleRate() const { return m_settings.m_inputSampleRate; }
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
virtual void start();
virtual void stop();
@ -85,134 +142,22 @@ public:
m_magsqCount = 0;
}
RDSParser& getRDSParser() { return m_rdsParser; }
private slots:
void channelSampleRateChanged();
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 {
RSInitialFill,
RSRunning
};
struct Config {
int m_inputSampleRate;
qint64 m_inputFrequencyOffset;
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;
DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
Config() :
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;
BFMDemodSettings m_settings;
NCO m_nco;
Interpolator m_interpolator; //!< Interpolator between fixed demod bandwidth and audio bandwidth (rational)
@ -254,7 +199,7 @@ private:
RDSDemod m_rdsDemod;
RDSDecoder m_rdsDecoder;
RDSParser *m_rdsParser;
RDSParser m_rdsParser;
LowPassFilterRC m_deemphasisFilterX;
LowPassFilterRC m_deemphasisFilterY;
@ -268,7 +213,7 @@ private:
static const int m_udpBlockSize;
void apply(bool force = false);
void applySettings(const BFMDemodSettings& settings, bool force = false);
};
#endif // INCLUDE_BFMDEMOD_H

View File

@ -37,26 +37,13 @@
#include "gui/basicchannelsettingsdialog.h"
#include "mainwindow.h"
#include "bfmdemodsettings.h"
#include "bfmdemod.h"
#include "rdstmc.h"
#include "ui_bfmdemodgui.h"
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* gui = new BFMDemodGUI(pluginAPI, deviceAPI);
@ -91,119 +78,65 @@ void BFMDemodGUI::setCenterFrequency(qint64 centerFrequency)
void BFMDemodGUI::resetToDefaults()
{
blockApplySettings(true);
m_settings.resetToDefaults();
displaySettings();
ui->rfBW->setValue(4);
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());
blockApplySettings(true);
ui->g00AltFrequenciesBox->setEnabled(false);
ui->g14MappedFrequencies->setEnabled(false);
ui->g14AltFrequencies->setEnabled(false);
blockApplySettings(false);
applySettings();
}
QByteArray BFMDemodGUI::serialize() const
{
SimpleSerializer s(1);
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();
return m_settings.serialize();
}
bool BFMDemodGUI::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
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;
}
if(m_settings.deserialize(data)) {
updateChannelMarker();
displaySettings();
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()
@ -216,30 +149,36 @@ void BFMDemodGUI::channelMarkerChanged()
void BFMDemodGUI::on_deltaFrequency_changed(qint64 value)
{
m_channelMarker.setCenterFrequency(value);
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
applySettings();
}
void BFMDemodGUI::on_rfBW_valueChanged(int value)
{
ui->rfBWText->setText(QString("%1 kHz").arg(m_rfBW[value] / 1000.0));
m_channelMarker.setBandwidth(m_rfBW[value]);
ui->rfBWText->setText(QString("%1 kHz").arg(BFMDemodSettings::getRFBW(value) / 1000.0));
m_channelMarker.setBandwidth(BFMDemodSettings::getRFBW(value));
m_settings.m_rfBandwidth = BFMDemodSettings::getRFBW(value);
applySettings();
}
void BFMDemodGUI::on_afBW_valueChanged(int value)
{
ui->afBWText->setText(QString("%1 kHz").arg(value));
m_settings.m_afBandwidth = value * 1000.0;
applySettings();
}
void BFMDemodGUI::on_volume_valueChanged(int value)
{
ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
m_settings.m_volume = value / 10.0;
applySettings();
}
void BFMDemodGUI::on_squelch_valueChanged(int value)
{
ui->squelchText->setText(QString("%1 dB").arg(value));
m_settings.m_squelch = value;
applySettings();
}
@ -250,26 +189,31 @@ void BFMDemodGUI::on_audioStereo_toggled(bool stereo)
ui->audioStereo->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
}
m_settings.m_audioStereo = stereo;
applySettings();
}
void BFMDemodGUI::on_lsbStereo_toggled(bool lsb __attribute__((unused)))
void BFMDemodGUI::on_lsbStereo_toggled(bool lsb)
{
m_settings.m_lsbStereo = lsb;
applySettings();
}
void BFMDemodGUI::on_copyAudioToUDP_toggled(bool copy __attribute__((unused)))
void BFMDemodGUI::on_copyAudioToUDP_toggled(bool copy)
{
m_settings.m_copyAudioToUDP = copy;
applySettings();
}
void BFMDemodGUI::on_showPilot_clicked()
{
m_settings.m_showPilot = ui->showPilot->isChecked();
applySettings();
}
void BFMDemodGUI::on_rds_clicked()
{
m_settings.m_rdsActive = ui->rds->isChecked();
applySettings();
}
@ -277,7 +221,7 @@ void BFMDemodGUI::on_clearData_clicked(bool checked __attribute__((unused)))
{
if (ui->rds->isChecked())
{
m_rdsParser.clearAllFields();
m_bfmDemod->getRDSParser().clearAllFields();
ui->g14ProgServiceNames->clear();
ui->g14MappedFrequencies->clear();
@ -298,9 +242,9 @@ void BFMDemodGUI::on_g14ProgServiceNames_currentIndexChanged(int _index)
if (index < m_g14ComboIndex.size())
{
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();
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);
}
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();
RDSParser::freqs_set_t::iterator sIt = (mIt->second).begin();
@ -354,7 +298,6 @@ void BFMDemodGUI::on_g14AltFrequencies_activated(int index __attribute__((unused
changeFrequency(f);
}
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);
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
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_bfmDemod = new BFMDemod(m_spectrumVis, &m_rdsParser);
m_channelizer = new DownChannelizer(m_bfmDemod);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged()));
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
m_bfmDemod = new BFMDemod(m_deviceAPI);
m_bfmDemod->setMessageQueueToGUI(getInputMessageQueue());
m_bfmDemod->setSampleSink(m_spectrumVis);
ui->glSpectrum->setCenterFrequency(m_rate / 4);
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);
connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
//m_channelMarker = new ChannelMarker(this);
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);
m_channelMarker.setVisible(true);
m_channelMarker.setColor(m_settings.m_rgbColor);
setTitleColor(m_channelMarker.getColor());
m_settings.setChannelMarker(&m_channelMarker);
m_settings.setSpectrumGUI(ui->spectrumGUI);
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
m_deviceAPI->registerChannelInstance(m_channelID, this);
@ -425,6 +369,7 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
rdsUpdateFixedFields();
rdsUpdate(true);
displaySettings();
displayUDPAddress();
applySettings(true);
}
@ -432,11 +377,7 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
BFMDemodGUI::~BFMDemodGUI()
{
m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
delete m_bfmDemod;
//delete m_channelMarker;
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()));
}
void BFMDemodGUI::updateChannelMarker()
{
m_channelMarker.blockSignals(true);
this->setWindowTitle(m_channelMarker.getTitle());
m_channelMarker.blockSignals(false);
}
void BFMDemodGUI::blockApplySettings(bool block)
{
m_doApplySettings = !block;
@ -456,28 +404,54 @@ void BFMDemodGUI::applySettings(bool force)
{
setTitleColor(m_channelMarker.getColor());
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
requiredBW(m_rfBW[ui->rfBW->value()]), // TODO: this is where requested sample rate is specified
m_channelMarker.getCenterFrequency());
BFMDemod::MsgConfigureChannelizer *msgChan = BFMDemod::MsgConfigureChannelizer::create(
requiredBW(BFMDemodSettings::getRFBW(ui->rfBW->value())),
m_channelMarker.getCenterFrequency());
m_bfmDemod->getInputMessageQueue()->push(msgChan);
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_bfmDemod->configure(m_bfmDemod->getInputMessageQueue(),
m_rfBW[ui->rfBW->value()],
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);
BFMDemod::MsgConfigureBFMDemod* msgConfig = BFMDemod::MsgConfigureBFMDemod::create( m_settings, force);
m_bfmDemod->getInputMessageQueue()->push(msgConfig);
}
}
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*)
{
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
}
void BFMDemodGUI::channelSampleRateChanged()
{
m_rate = m_bfmDemod->getSampleRate();
ui->glSpectrum->setCenterFrequency(m_rate / 4);
ui->glSpectrum->setSampleRate(m_rate / 2);
}
void BFMDemodGUI::rdsUpdateFixedFields()
{
ui->g00Label->setText(m_rdsParser.rds_group_acronym_tags[0].c_str());
ui->g01Label->setText(m_rdsParser.rds_group_acronym_tags[1].c_str());
ui->g02Label->setText(m_rdsParser.rds_group_acronym_tags[2].c_str());
ui->g03Label->setText(m_rdsParser.rds_group_acronym_tags[3].c_str());
ui->g04Label->setText(m_rdsParser.rds_group_acronym_tags[4].c_str());
//ui->g05Label->setText(m_rdsParser.rds_group_acronym_tags[5].c_str());
//ui->g06Label->setText(m_rdsParser.rds_group_acronym_tags[6].c_str());
//ui->g07Label->setText(m_rdsParser.rds_group_acronym_tags[7].c_str());
ui->g08Label->setText(m_rdsParser.rds_group_acronym_tags[8].c_str());
ui->g09Label->setText(m_rdsParser.rds_group_acronym_tags[9].c_str());
ui->g14Label->setText(m_rdsParser.rds_group_acronym_tags[14].c_str());
ui->g00Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[0].c_str());
ui->g01Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[1].c_str());
ui->g02Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[2].c_str());
ui->g03Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[3].c_str());
ui->g04Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[4].c_str());
//ui->g05Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[5].c_str());
//ui->g06Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[6].c_str());
//ui->g07Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[7].c_str());
ui->g08Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[8].c_str());
ui->g09Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[9].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->g01CountLabel->setText(m_rdsParser.rds_group_acronym_tags[1].c_str());
ui->g02CountLabel->setText(m_rdsParser.rds_group_acronym_tags[2].c_str());
ui->g03CountLabel->setText(m_rdsParser.rds_group_acronym_tags[3].c_str());
ui->g04CountLabel->setText(m_rdsParser.rds_group_acronym_tags[4].c_str());
ui->g05CountLabel->setText(m_rdsParser.rds_group_acronym_tags[5].c_str());
ui->g06CountLabel->setText(m_rdsParser.rds_group_acronym_tags[6].c_str());
ui->g07CountLabel->setText(m_rdsParser.rds_group_acronym_tags[7].c_str());
ui->g08CountLabel->setText(m_rdsParser.rds_group_acronym_tags[8].c_str());
ui->g09CountLabel->setText(m_rdsParser.rds_group_acronym_tags[9].c_str());
ui->g14CountLabel->setText(m_rdsParser.rds_group_acronym_tags[14].c_str());
ui->g00CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[0].c_str());
ui->g01CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[1].c_str());
ui->g02CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[2].c_str());
ui->g03CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[3].c_str());
ui->g04CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[4].c_str());
ui->g05CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[5].c_str());
ui->g06CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[6].c_str());
ui->g07CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[7].c_str());
ui->g08CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[8].c_str());
ui->g09CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[9].c_str());
ui->g14CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[14].c_str());
}
void BFMDemodGUI::rdsUpdate(bool force)
@ -591,21 +558,21 @@ void BFMDemodGUI::rdsUpdate(bool force)
}
// 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->piCountText->setNum((int) m_rdsParser.m_pi_count);
QString pistring(str(boost::format("%04X") % m_rdsParser.m_pi_program_identification).c_str());
ui->piCountText->setNum((int) m_bfmDemod->getRDSParser().m_pi_count);
QString pistring(str(boost::format("%04X") % m_bfmDemod->getRDSParser().m_pi_program_identification).c_str());
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; }");
} else {
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->piCoverage->setText(QString(m_rdsParser.coverage_area_codes[m_rdsParser.m_pi_area_coverage_index].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_bfmDemod->getRDSParser().coverage_area_codes[m_bfmDemod->getRDSParser().m_pi_area_coverage_index].c_str()));
}
else
{
@ -613,29 +580,29 @@ void BFMDemodGUI::rdsUpdate(bool force)
}
// 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->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) {
ui->g00ProgServiceName->setText(QString(m_rdsParser.m_g0_program_service_name));
if (m_bfmDemod->getRDSParser().m_g0_psn_bitmap == 0b1111) {
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; }");
} else {
ui->g00TrafficAnnouncement->setStyleSheet("QLabel { background:rgb(79,79,79); }");
}
ui->g00MusicSpeech->setText(QString((m_rdsParser.m_g0_music_speech ? "Music" : "Speech")));
ui->g00MonoStereo->setText(QString((m_rdsParser.m_g0_mono_stereo ? "Mono" : "Stereo")));
ui->g00MusicSpeech->setText(QString((m_bfmDemod->getRDSParser().m_g0_music_speech ? "Music" : "Speech")));
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();
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)
{
@ -654,20 +621,20 @@ void BFMDemodGUI::rdsUpdate(bool force)
}
// 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->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)) {
ui->g01CountryCode->setText(QString((m_rdsParser.pi_country_codes[m_rdsParser.m_g1_country_page_index][m_rdsParser.m_g1_country_index]).c_str()));
if ((m_bfmDemod->getRDSParser().m_g1_country_page_index >= 0) && (m_bfmDemod->getRDSParser().m_g1_country_index >= 0)) {
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) {
ui->g01Language->setText(QString(m_rdsParser.language_codes[m_rdsParser.m_g1_language_index].c_str()));
if (m_bfmDemod->getRDSParser().m_g1_language_index >= 0) {
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
{
@ -675,11 +642,11 @@ void BFMDemodGUI::rdsUpdate(bool force)
}
// 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->g02CountText->setNum((int) m_rdsParser.m_g2_count);
ui->go2Text->setText(QString(m_rdsParser.m_g2_radiotext));
ui->g02CountText->setNum((int) m_bfmDemod->getRDSParser().m_g2_count);
ui->go2Text->setText(QString(m_bfmDemod->getRDSParser().m_g2_radiotext));
}
else
{
@ -687,11 +654,11 @@ void BFMDemodGUI::rdsUpdate(bool force)
}
// 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->g03CountText->setNum((int) m_rdsParser.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);
ui->g03CountText->setNum((int) m_bfmDemod->getRDSParser().m_g3_count);
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()));
}
else
@ -700,12 +667,12 @@ void BFMDemodGUI::rdsUpdate(bool force)
}
// 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->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)")\
% 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()));
}
else
@ -714,42 +681,42 @@ void BFMDemodGUI::rdsUpdate(bool force)
}
// 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
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
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
if (m_rdsParser.m_g8_updated || force)
if (m_bfmDemod->getRDSParser().m_g8_updated || force)
{
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;
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()));
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()));
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);
if (m_rdsParser.m_g8_label_index >= 0) {
ui->g08Description->setText(QString(m_rdsParser.label_descriptions[m_rdsParser.m_g8_label_index].c_str()));
if (m_bfmDemod->getRDSParser().m_g8_label_index >= 0) {
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
{
@ -757,11 +724,11 @@ void BFMDemodGUI::rdsUpdate(bool force)
}
// 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->g09CountText->setNum((int) m_rdsParser.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);
ui->g09CountText->setNum((int) m_bfmDemod->getRDSParser().m_g9_count);
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()));
}
else
@ -770,18 +737,18 @@ void BFMDemodGUI::rdsUpdate(bool force)
}
// 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; }");
m_g14ComboIndex.clear();
ui->g14ProgServiceNames->clear();
RDSParser::psns_map_t::iterator it = m_rdsParser.m_g14_program_service_names.begin();
const RDSParser::psns_map_t::iterator itEnd = m_rdsParser.m_g14_program_service_names.end();
RDSParser::psns_map_t::iterator it = m_bfmDemod->getRDSParser().m_g14_program_service_names.begin();
const RDSParser::psns_map_t::iterator itEnd = m_bfmDemod->getRDSParser().m_g14_program_service_names.end();
int i = 0;
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)
{
qint64 df = m_channelMarker.getCenterFrequency();
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
#define INCLUDE_BFMDEMODGUI_H
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h"
#include "dsp/channelmarker.h"
#include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h"
#include "rdsparser.h"
#include "bfmdemodsettings.h"
class PluginAPI;
class DeviceSourceAPI;
class RDSParser;
class ThreadedBasebandSampleSink;
class DownChannelizer;
@ -38,7 +38,7 @@ namespace Ui {
class BFMDemodGUI;
}
class BFMDemodGUI : public RollupWidget, public PluginInstanceUI {
class BFMDemodGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT
public:
@ -60,7 +60,6 @@ public:
private slots:
void channelMarkerChanged();
void channelSampleRateChanged();
void on_deltaFrequency_changed(qint64 value);
void on_rfBW_valueChanged(int value);
void on_afBW_valueChanged(int value);
@ -78,6 +77,7 @@ private slots:
void on_g14AltFrequencies_activated(int index);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void handleInputMessages();
void tick();
private:
@ -85,13 +85,11 @@ private:
PluginAPI* m_pluginAPI;
DeviceSourceAPI* m_deviceAPI;
ChannelMarker m_channelMarker;
BFMDemodSettings m_settings;
bool m_doApplySettings;
int m_rdsTimerCount;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
SpectrumVis* m_spectrumVis;
RDSParser m_rdsParser;
BFMDemod* m_bfmDemod;
MovingAverage<double> m_channelPowerDbAvg;
@ -99,14 +97,14 @@ private:
std::vector<unsigned int> m_g14ComboIndex;
MessageQueue m_inputMessageQueue;
static const int m_rfBW[];
explicit BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent = NULL);
virtual ~BFMDemodGUI();
void blockApplySettings(bool block);
void applySettings(bool force = false);
void displaySettings();
void displayUDPAddress();
void updateChannelMarker();
void rdsUpdate(bool force);
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 = {
QString("Broadcast FM Demodulator"),
QString("3.6.1"),
QString("3.7.3"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
@ -50,7 +50,7 @@ void BFMPlugin::initPlugin(PluginAPI* pluginAPI)
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)
{

View File

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

View File

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

View File

@ -22,6 +22,10 @@
#include <stdio.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_fsc = 1187.5;
@ -77,7 +81,7 @@ bool RDSDemod::process(Real demod, bool& bit)
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;
// Clock phase recovery

View File

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

View File

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

View File

@ -15,51 +15,48 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "../../channelrx/demoddsd/dsddemod.h"
#include <QTime>
#include <QDebug>
#include <stdio.h>
#include <complex.h>
#include <dsp/downchannelizer.h>
#include "audio/audiooutput.h"
#include "dsp/pidcontroller.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::MsgConfigureMyPosition, Message)
const int DSDDemod::m_udpBlockSize = 512;
DSDDemod::DSDDemod(BasebandSampleSink* sampleSink) :
m_sampleCount(0),
m_squelchCount(0),
m_squelchOpen(false),
DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_interpolatorDistance(0.0f),
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_fmExcursion(24),
m_audioFifo1(48000),
m_audioFifo1(48000),
m_audioFifo2(48000),
m_scope(sampleSink),
m_scope(0),
m_scopeEnabled(true),
m_dsdDecoder(),
m_settingsMutex(QMutex::Recursive)
{
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_audioBufferFill = 0;
@ -75,11 +72,15 @@ DSDDemod::DSDDemod(BasebandSampleSink* sampleSink) :
DSPEngine::instance()->addAudioSink(&m_audioFifo1);
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_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()
@ -88,47 +89,10 @@ DSDDemod::~DSDDemod()
DSPEngine::instance()->removeAudioSink(&m_audioFifo1);
DSPEngine::instance()->removeAudioSink(&m_audioFifo2);
delete m_udpBufferAudio;
}
void DSDDemod::configure(MessageQueue* messageQueue,
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* cmd = MsgConfigureDSDDemod::create(rfBandwidth,
demodGain,
fmDeviation,
volume,
baudRate,
squelchGate,
squelch,
audioMute,
enableCosineFiltering,
syncOrConstellation,
slot1On,
slot2On,
tdmaStereo,
pllLock,
udpCopyAudio,
udpAddress,
udpPort,
force);
messageQueue->push(cmd);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
}
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++;
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++;
// AF processing
@ -205,7 +169,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
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();
}
@ -223,7 +187,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
delayedSample = m_sampleBuffer[m_sampleBufferIndex - samplesPerSymbol];
}
if (m_running.m_syncOrConstellation)
if (m_settings.m_syncOrConstellation)
{
Sample s(sample, m_dsdDecoder.getSymbolSyncSample());
m_scopeSampleBuffer.push_back(s);
@ -236,30 +200,30 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
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(
m_dsdDecoder.getMbeDVFrame1(),
m_dsdDecoder.getMbeRateIndex(),
m_running.m_volume,
m_running.m_tdmaStereo ? 1 : 3, // left or both channels
m_settings.m_volume,
m_settings.m_tdmaStereo ? 1 : 3, // left or both channels
&m_audioFifo1);
}
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(
m_dsdDecoder.getMbeDVFrame2(),
m_dsdDecoder.getMbeRateIndex(),
m_running.m_volume,
m_running.m_tdmaStereo ? 2 : 3, // right or both channels
m_settings.m_volume,
m_settings.m_tdmaStereo ? 2 : 3, // right or both channels
&m_audioFifo2);
}
@ -269,9 +233,9 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
// 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();
@ -283,14 +247,14 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
if (!DSPEngine::instance()->hasDVSerialSupport())
{
if (m_running.m_slot1On)
if (m_settings.m_slot1On)
{
int nbAudioSamples;
short *dsdAudio = m_dsdDecoder.getAudio1(nbAudioSamples);
if (nbAudioSamples > 0)
{
if (!m_running.m_audioMute) {
if (!m_settings.m_audioMute) {
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;
short *dsdAudio = m_dsdDecoder.getAudio2(nbAudioSamples);
if (nbAudioSamples > 0)
{
if (!m_running.m_audioMute) {
if (!m_settings.m_audioMute) {
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 (!m_running.m_audioMute) {
// if (!m_settings.m_audioMute) {
// 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;
m_config.m_inputSampleRate = notif.getSampleRate();
m_config.m_inputFrequencyOffset = notif.getFrequencyOffset();
DSDDemodSettings settings = m_settings;
settings.m_inputSampleRate = notif.getSampleRate();
settings.m_inputFrequencyOffset = notif.getFrequencyOffset();
apply();
applySettings(settings);
qDebug() << "DSDDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset;
qDebug() << "DSDDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << settings.m_inputSampleRate
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset;
return true;
}
else if (MsgConfigureDSDDemod::match(cmd))
{
MsgConfigureDSDDemod& cfg = (MsgConfigureDSDDemod&) cmd;
else if (MsgConfigureChannelizer::match(cmd))
{
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
m_config.m_rfBandwidth = cfg.getRFBandwidth();
m_config.m_demodGain = cfg.getDemodGain();
m_config.m_fmDeviation = cfg.getFMDeviation();
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();
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(),
cfg.getCenterFrequency());
apply();
return true;
}
else if (MsgConfigureDSDDemod::match(cmd))
{
MsgConfigureDSDDemod& cfg = (MsgConfigureDSDDemod&) cmd;
qDebug() << "DSDDemod::handleMessage: MsgConfigureDSDDemod: m_rfBandwidth: " << m_config.m_rfBandwidth * 100
<< " 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;
DSDDemodSettings settings = cfg.getSettings();
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))
{
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) ||
(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) || 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)
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) ||
(settings.m_inputSampleRate != m_settings.m_inputSampleRate) || 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)
|| (m_config.m_udpPort != m_running.m_udpPort) || force)
if ((settings.m_volume != m_settings.m_volume) || force)
{
m_udpBufferAudio->setAddress(m_config.m_udpAddress);
m_udpBufferAudio->setPort(m_config.m_udpPort);
m_dsdDecoder.setAudioGain(settings.m_volume);
}
if ((m_config.m_udpCopyAudio != m_running.m_udpCopyAudio)
|| (m_config.m_slot1On != m_running.m_slot1On)
|| (m_config.m_slot2On != m_running.m_slot2On) || force)
if ((settings.m_baudRate != m_settings.m_baudRate) || force)
{
m_audioFifo1.setCopyToUDP(m_config.m_slot1On && m_config.m_udpCopyAudio);
m_audioFifo2.setCopyToUDP(m_config.m_slot2On && !m_config.m_slot1On && m_config.m_udpCopyAudio);
m_dsdDecoder.setBaudRate(settings.m_baudRate);
}
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/udpsink.h"
#include "dsddemodsettings.h"
#include "dsddecoder.h"
class DSDDemodGUI;
class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class DSDDemod : public BasebandSampleSink {
public:
DSDDemod(BasebandSampleSink* sampleSink);
~DSDDemod();
class MsgConfigureDSDDemod : public Message {
MESSAGE_CLASS_DECLARATION
void configure(MessageQueue* messageQueue,
int rfBandwidth,
int demodGain,
int volume,
int baudRate,
int fmDeviation,
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);
public:
const DSDDemodSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureDSDDemod* create(const DSDDemodSettings& settings, bool force)
{
return new MsgConfigureDSDDemod(settings, force);
}
private:
DSDDemodSettings m_settings;
bool m_force;
MsgConfigureDSDDemod(const DSDDemodSettings& 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)
{ }
};
DSDDemod(DeviceSourceAPI *deviceAPI);
~DSDDemod();
void setScopeSink(BasebandSampleSink* sampleSink) { m_scope = sampleSink; }
void configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude);
@ -69,10 +99,6 @@ public:
virtual void stop();
virtual bool handleMessage(const Message& cmd);
void registerGUI(DSDDemodGUI *dsdDemodGUI) {
m_dsdDemodGUI = dsdDemodGUI;
}
double getMagSq() { return m_magsq; }
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 {
RSInitialFill,
RSRunning
};
struct Config {
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;
DSDDemodSettings m_settings;
Config() :
m_inputSampleRate(-1),
m_inputFrequencyOffset(0),
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;
DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
NCO m_nco;
Interpolator m_interpolator;
@ -299,7 +161,6 @@ private:
double m_squelchLevel;
bool m_squelchOpen;
Real m_lastArgument;
MovingAverage<double> m_movingAverage;
double m_magsq;
double m_magsqSum;
@ -320,7 +181,6 @@ private:
bool m_scopeEnabled;
DSDDecoder m_dsdDecoder;
DSDDemodGUI *m_dsdDemodGUI;
QMutex m_settingsMutex;
PhaseDiscriminators m_phaseDiscri;
@ -328,7 +188,7 @@ private:
static const int m_udpBlockSize;
void apply(bool force = false);
void applySettings(DSDDemodSettings& settings, bool force = false);
};
#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 "mainwindow.h"
#include "dsddemodbaudrates.h"
#include "dsddemod.h"
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* gui = new DSDDemodGUI(pluginAPI, deviceAPI);
@ -76,112 +73,31 @@ void DSDDemodGUI::setCenterFrequency(qint64 centerFrequency)
void DSDDemodGUI::resetToDefaults()
{
m_settings.resetToDefaults();
blockApplySettings(true);
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);
displaySettings();
blockApplySettings(false);
applySettings();
}
QByteArray DSDDemodGUI::serialize() const
{
SimpleSerializer s(1);
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();
return m_settings.serialize();
}
bool DSDDemodGUI::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
resetToDefaults();
return false;
}
if (d.getVersion() == 1)
{
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;
}
if (m_settings.deserialize(data))
{
displaySettings();
applySettings(true);
return true;
}
else
{
resetToDefaults();
return false;
}
}
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)
{
m_channelMarker.setCenterFrequency(value);
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
applySettings();
}
void DSDDemodGUI::on_rfBW_valueChanged(int value)
{
qDebug() << "DSDDemodGUI::on_rfBW_valueChanged" << 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();
}
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();
}
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();
}
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();
}
void DSDDemodGUI::on_baudRate_currentIndexChanged(int index __attribute__((unused)))
void DSDDemodGUI::on_baudRate_currentIndexChanged(int index)
{
m_settings.m_baudRate = DSDDemodBaudRates::getRate(index);
applySettings();
}
void DSDDemodGUI::on_enableCosineFiltering_toggled(bool enable)
{
m_enableCosineFiltering = enable;
m_settings.m_enableCosineFiltering = enable;
applySettings();
}
void DSDDemodGUI::on_syncOrConstellation_toggled(bool checked)
{
m_syncOrConstellation = checked;
m_settings.m_syncOrConstellation = checked;
applySettings();
}
void DSDDemodGUI::on_slot1On_toggled(bool checked)
{
m_slot1On = checked;
m_settings.m_slot1On = checked;
applySettings();
}
void DSDDemodGUI::on_slot2On_toggled(bool checked)
{
m_slot2On = checked;
m_settings.m_slot2On = checked;
applySettings();
}
void DSDDemodGUI::on_tdmaStereoSplit_toggled(bool checked)
{
m_tdmaStereo = checked;
m_settings.m_tdmaStereo = checked;
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();
}
void DSDDemodGUI::on_squelch_valueChanged(int value)
{
ui->squelchText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
m_settings.m_squelch = value / 10.0;
applySettings();
}
void DSDDemodGUI::on_audioMute_toggled(bool checked)
{
m_audioMute = checked;
m_settings.m_audioMute = checked;
applySettings();
}
@ -275,11 +204,13 @@ void DSDDemodGUI::on_symbolPLLLock_toggled(bool checked)
} else {
ui->symbolPLLLock->setStyleSheet("QToolButton { background:rgb(53,53,53); }");
}
m_settings.m_pllLock = checked;
applySettings();
}
void DSDDemodGUI::on_udpOutput_toggled(bool checked __attribute__((unused)))
void DSDDemodGUI::on_udpOutput_toggled(bool checked)
{
m_settings.m_udpCopyAudio = checked;
applySettings();
}
@ -322,8 +253,9 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
m_scopeVis = new ScopeVis(ui->glScope);
m_dsdDemod = new DSDDemod(m_scopeVis);
m_dsdDemod->registerGUI(this);
m_dsdDemod = new DSDDemod(m_deviceAPI);
m_dsdDemod->setScopeSink(m_scopeVis);
m_dsdDemod->setMessageQueueToGUI(getInputMessageQueue());
ui->glScope->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->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.setColor(Qt::cyan);
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);
m_settings.setChannelMarker(&m_channelMarker);
m_settings.setScopeGUI(ui->scopeGUI);
updateMyPosition();
displaySettings();
displayUDPAddress();
applySettings(true);
}
@ -366,11 +298,7 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
DSDDemodGUI::~DSDDemodGUI()
{
m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
delete m_dsdDemod;
//delete m_channelMarker;
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()));
}
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)
{
if (m_doApplySettings)
{
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(),
48000,
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);
DSDDemod::MsgConfigureDSDDemod* message = DSDDemod::MsgConfigureDSDDemod::create( m_settings, force);
m_dsdDemod->getInputMessageQueue()->push(message);
}
}
@ -683,28 +627,3 @@ void DSDDemodGUI::tick()
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
#define INCLUDE_DSDDEMODGUI_H
#include <plugin/plugininstancegui.h>
#include <QMenu>
#include "gui/rollupwidget.h"
#include "dsp/dsptypes.h"
#include "dsp/channelmarker.h"
#include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h"
#include "dsddemodsettings.h"
class PluginAPI;
class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class ScopeVis;
class DSDDemod;
@ -39,7 +39,7 @@ namespace Ui {
class DSDDemodGUI;
}
class DSDDemodGUI : public RollupWidget, public PluginInstanceUI {
class DSDDemodGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT
public:
@ -96,12 +96,11 @@ private:
PluginAPI* m_pluginAPI;
DeviceSourceAPI* m_deviceAPI;
ChannelMarker m_channelMarker;
DSDDemodSettings m_settings;
bool m_doApplySettings;
char m_formatStatusText[82+1]; //!< Fixed signal format dependent status text
SignalFormat m_signalFormat;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
ScopeVis* m_scopeVis;
DSDDemod* m_dsdDemod;
@ -124,6 +123,7 @@ private:
void blockApplySettings(bool block);
void applySettings(bool force = false);
void displaySettings();
void updateMyPosition();
void displayUDPAddress();
@ -131,18 +131,4 @@ private:
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

View File

@ -24,7 +24,7 @@
const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = {
QString("DSD Demodulator"),
QString("3.6.1"),
QString("3.7.3"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
@ -50,7 +50,7 @@ void DSDDemodPlugin::initPlugin(PluginAPI* pluginAPI)
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)
{

View File

@ -34,7 +34,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private:
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
#define INCLUDE_LoRaDEMODGUI_H
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h"
#include "dsp/channelmarker.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h"
#define BANDWIDTHSTRING {7813,15625,20833,31250,62500}
@ -19,7 +19,7 @@ namespace Ui {
class LoRaDemodGUI;
}
class LoRaDemodGUI : public RollupWidget, public PluginInstanceUI {
class LoRaDemodGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT
public:

View File

@ -33,7 +33,7 @@ void LoRaPlugin::initPlugin(PluginAPI* pluginAPI)
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)
{

View File

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

View File

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

View File

@ -33,7 +33,7 @@ void NFMPlugin::initPlugin(PluginAPI* pluginAPI)
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) {
NFMDemodGUI* gui = NFMDemodGUI::create(m_pluginAPI, deviceAPI);

View File

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

View File

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

View File

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

View File

@ -16,19 +16,26 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "ssbdemod.h"
#include <dsp/downchannelizer.h>
#include <QTime>
#include <QDebug>
#include <stdio.h>
#include "audio/audiooutput.h"
#include "dsp/dspengine.h"
#include <dsp/downchannelizer.h>
#include "dsp/threadedbasebandsamplesink.h"
#include "device/devicesourceapi.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_audioFlipChannels(false),
m_dsb(false),
@ -40,7 +47,7 @@ SSBDemod::SSBDemod(BasebandSampleSink* sampleSink) :
m_agcPowerThreshold(1e-2),
m_agcThresholdGate(0),
m_audioActive(false),
m_sampleSink(sampleSink),
m_sampleSink(0),
m_audioFifo(24000),
m_settingsMutex(QMutex::Recursive)
{
@ -75,7 +82,13 @@ SSBDemod::SSBDemod(BasebandSampleSink* sampleSink) :
SSBFilter = new fftfilt(m_LowCutoff / m_audioSampleRate, m_Bandwidth / m_audioSampleRate, 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);
applySettings(m_settings, true);
}
SSBDemod::~SSBDemod()
@ -84,6 +97,10 @@ SSBDemod::~SSBDemod()
if (DSBFilter) delete DSBFilter;
DSPEngine::instance()->removeAudioSink(&m_audioFifo);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
}
void SSBDemod::configure(MessageQueue* messageQueue,
@ -101,7 +118,7 @@ void SSBDemod::configure(MessageQueue* messageQueue,
int agcPowerThreshold,
int agcThresholdGate)
{
Message* cmd = MsgConfigureSSBDemod::create(
Message* cmd = MsgConfigureSSBDemodPrivate::create(
Bandwidth,
LowCutoff,
volume,
@ -262,10 +279,6 @@ void SSBDemod::stop()
bool SSBDemod::handleMessage(const Message& cmd)
{
float band, lowCutoff;
qDebug() << "SSBDemod::handleMessage";
if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
@ -284,94 +297,48 @@ bool SSBDemod::handleMessage(const Message& cmd)
return true;
}
else if (MsgConfigureSSBDemod::match(cmd))
{
MsgConfigureSSBDemod& cfg = (MsgConfigureSSBDemod&) cmd;
else if (MsgConfigureChannelizer::match(cmd))
{
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
m_settingsMutex.lock();
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getSampleRate(),
cfg.getCenterFrequency());
band = cfg.getBandwidth();
lowCutoff = cfg.getLoCutoff();
qDebug() << "SSBDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << cfg.getSampleRate()
<< " centerFrequency: " << cfg.getCenterFrequency();
if (band < 0) {
band = -band;
lowCutoff = -lowCutoff;
m_usb = false;
} else
m_usb = true;
return true;
}
else if (MsgConfigureSSBDemod::match(cmd))
{
MsgConfigureSSBDemod& cfg = (MsgConfigureSSBDemod&) cmd;
if (band < 100.0f)
{
band = 100.0f;
lowCutoff = 0;
}
m_Bandwidth = band;
m_LowCutoff = lowCutoff;
SSBDemodSettings settings = cfg.getSettings();
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);
// These settings are set with DownChannelizer::MsgChannelizerNotification
settings.m_inputSampleRate = m_settings.m_inputSampleRate;
settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset;
m_volume = cfg.getVolume();
//m_volume *= 2.0; // for 327.68
m_volume /= 4.0; // for 3276.8
applySettings(settings, cfg.getForce());
m_spanLog2 = cfg.getSpanLog2();
m_audioBinaual = cfg.getAudioBinaural();
m_audioFlipChannels = cfg.getAudioFlipChannels();
m_dsb = cfg.getDSB();
m_audioMute = cfg.getAudioMute();
m_agcActive = cfg.getAGC();
qDebug() << "SSBDemod::handleMessage: MsgConfigureSSBDemod:"
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_lowCutoff: " << settings.m_lowCutoff
<< " m_volume: " << settings.m_volume
<< " 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_agcClamping: " << settings.m_agcClamping
<< " m_agcTimeLog2: " << settings.m_agcTimeLog2
<< " agcPowerThreshold: " << settings.m_agcPowerThreshold
<< " agcThresholdGate: " << settings.m_agcThresholdGate;
int agcNbSamples = 48 * (1<<cfg.getAGCTimeLog2());
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;
}
return true;
}
else
{
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
#define INCLUDE_SSBDEMOD_H
#include <dsp/basebandsamplesink.h>
#include <QMutex>
#include <vector>
#include <dsp/basebandsamplesink.h>
#include "dsp/ncof.h"
#include "dsp/interpolator.h"
#include "dsp/fftfilt.h"
@ -28,13 +29,66 @@
#include "audio/audiofifo.h"
#include "util/message.h"
#include "ssbdemodsettings.h"
#define ssbFftLen 1024
#define agcTarget 3276.8 // -10 dB amplitude => -20 dB power: center of normal signal
class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class SSBDemod : public BasebandSampleSink {
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();
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
void configure(MessageQueue* messageQueue,
Real Bandwidth,
@ -71,7 +125,7 @@ public:
}
private:
class MsgConfigureSSBDemod : public Message {
class MsgConfigureSSBDemodPrivate : public Message {
MESSAGE_CLASS_DECLARATION
public:
@ -89,7 +143,7 @@ private:
int getAGCPowerThershold() const { return m_agcPowerThreshold; }
int getAGCThersholdGate() const { return m_agcThresholdGate; }
static MsgConfigureSSBDemod* create(Real Bandwidth,
static MsgConfigureSSBDemodPrivate* create(Real Bandwidth,
Real LowCutoff,
Real volume,
int spanLog2,
@ -103,7 +157,7 @@ private:
int agcPowerThreshold,
int agcThresholdGate)
{
return new MsgConfigureSSBDemod(
return new MsgConfigureSSBDemodPrivate(
Bandwidth,
LowCutoff,
volume,
@ -134,7 +188,7 @@ private:
int m_agcPowerThreshold;
int m_agcThresholdGate;
MsgConfigureSSBDemod(Real Bandwidth,
MsgConfigureSSBDemodPrivate(Real Bandwidth,
Real LowCutoff,
Real volume,
int spanLog2,
@ -164,6 +218,11 @@ private:
{ }
};
DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
SSBDemodSettings m_settings;
Real m_Bandwidth;
Real m_LowCutoff;
Real m_volume;
@ -204,6 +263,8 @@ private:
quint32 m_audioSampleRate;
QMutex m_settingsMutex;
void applySettings(const SSBDemodSettings& settings, bool force = false);
};
#endif // INCLUDE_SSBDEMOD_H

View File

@ -2,12 +2,9 @@
#include "ssbdemodgui.h"
#include <device/devicesourceapi.h>
#include <dsp/downchannelizer.h>
#include <QDockWidget>
#include <QMainWindow>
#include "dsp/threadedbasebandsamplesink.h"
#include "ui_ssbdemodgui.h"
#include "ui_ssbdemodgui.h"
#include "dsp/spectrumvis.h"
#include "gui/glspectrum.h"
@ -50,113 +47,36 @@ qint64 SSBDemodGUI::getCenterFrequency() const
void SSBDemodGUI::setCenterFrequency(qint64 centerFrequency)
{
m_channelMarker.setCenterFrequency(centerFrequency);
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
applySettings();
}
void SSBDemodGUI::resetToDefaults()
{
blockApplySettings(true);
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);
m_settings.resetToDefaults();
}
QByteArray SSBDemodGUI::serialize() const
{
SimpleSerializer s(1);
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();
return m_settings.serialize();
}
bool SSBDemodGUI::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
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);
if(m_settings.deserialize(data))
{
updateChannelMarker();
displaySettings();
blockApplySettings(false);
m_channelMarker.blockSignals(false);
applySettings();
return true;
}
else
{
resetToDefaults();
applySettings();
return false;
}
applySettings(true); // will have true
return true;
}
else
{
m_settings.resetToDefaults();
displaySettings();
applySettings(true); // will have true
return false;
}
}
bool SSBDemodGUI::handleMessage(const Message& message __attribute__((unused)))
@ -172,18 +92,21 @@ void SSBDemodGUI::viewChanged()
void SSBDemodGUI::on_audioBinaural_toggled(bool binaural)
{
m_audioBinaural = binaural;
m_settings.m_audioBinaural = binaural;
applySettings();
}
void SSBDemodGUI::on_audioFlipChannels_toggled(bool flip)
{
m_audioFlipChannels = flip;
m_settings.m_audioFlipChannels = flip;
applySettings();
}
void SSBDemodGUI::on_dsb_toggled(bool dsb)
{
m_dsb = dsb;
m_settings.m_dsb = dsb;
if (m_dsb)
{
@ -220,6 +143,8 @@ void SSBDemodGUI::on_dsb_toggled(bool dsb)
void SSBDemodGUI::on_deltaFrequency_changed(qint64 value)
{
m_channelMarker.setCenterFrequency(value);
m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency();
applySettings();
}
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));
}
m_settings.m_rfBandwidth = value * 100;
on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100);
setNewRate(m_spanLog2);
}
@ -279,22 +205,26 @@ void SSBDemodGUI::on_lowCut_valueChanged(int value)
QString s = QString::number(lowCutoff/1000.0, 'f', 1);
ui->lowCutText->setText(tr("%1k").arg(s));
ui->lowCut->setValue(lowCutoff/100);
m_settings.m_lowCutoff = lowCutoff;
applySettings();
}
void SSBDemodGUI::on_volume_valueChanged(int value)
{
ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1));
m_settings.m_volume = value / 10.0;
applySettings();
}
void SSBDemodGUI::on_agc_toggled(bool checked __attribute((__unused__)))
void SSBDemodGUI::on_agc_toggled(bool checked)
{
m_settings.m_agc = checked;
applySettings();
}
void SSBDemodGUI::on_agcClamping_toggled(bool checked __attribute((__unused__)))
void SSBDemodGUI::on_agcClamping_toggled(bool checked)
{
m_settings.m_agcClamping = checked;
applySettings();
}
@ -302,12 +232,14 @@ void SSBDemodGUI::on_agcTimeLog2_valueChanged(int value)
{
QString s = QString::number((1<<value), 'f', 0);
ui->agcTimeText->setText(s);
m_settings.m_agcTimeLog2 = value;
applySettings();
}
void SSBDemodGUI::on_agcPowerThreshold_valueChanged(int value)
{
displayAGCPowerThreshold(value);
m_settings.m_agcPowerThreshold = value;
applySettings();
}
@ -315,12 +247,14 @@ void SSBDemodGUI::on_agcThresholdGate_valueChanged(int value)
{
QString s = QString::number(value, 'f', 0);
ui->agcThresholdGateText->setText(s);
m_settings.m_agcThresholdGate = value;
applySettings();
}
void SSBDemodGUI::on_audioMute_toggled(bool checked)
{
m_audioMute = checked;
m_settings.m_audioMute = checked;
applySettings();
}
@ -328,6 +262,7 @@ void SSBDemodGUI::on_spanLog2_valueChanged(int value)
{
if (setNewRate(value))
{
m_settings.m_spanLog2 = value;
applySettings();
}
@ -373,10 +308,9 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked()));
m_spectrumVis = new SpectrumVis(ui->glSpectrum);
m_ssbDemod = new SSBDemod(m_spectrumVis);
m_channelizer = new DownChannelizer(m_ssbDemod);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
m_ssbDemod = new SSBDemod(m_deviceAPI);
m_ssbDemod->setMessageQueueToGUI(getInputMessageQueue());
m_ssbDemod->setSampleSink(m_spectrumVis);
ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03)));
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()));
//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_settings.setChannelMarker(&m_channelMarker);
m_settings.setSpectrumGUI(ui->spectrumGUI);
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
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);
resetToDefaults();
displaySettings();
applySettings();
applySettings(true);
setNewRate(m_spanLog2);
}
SSBDemodGUI::~SSBDemodGUI()
{
m_deviceAPI->removeChannelInstance(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
delete m_ssbDemod;
delete m_spectrumVis;
//delete m_channelMarker;
delete ui;
}
@ -454,7 +381,6 @@ bool SSBDemodGUI::setNewRate(int spanLog2)
m_channelMarker.setLowCutoff(m_rate);
}
QString s = QString::number(m_rate/1000.0, 'f', 1);
if (m_dsb)
@ -504,41 +430,101 @@ void SSBDemodGUI::blockApplySettings(bool block)
m_doApplySettings = !block;
}
void SSBDemodGUI::applySettings()
void SSBDemodGUI::applySettings(bool force)
{
if (m_doApplySettings)
{
setTitleColor(m_channelMarker.getColor());
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
48000,
m_channelMarker.getCenterFrequency());
SSBDemod::MsgConfigureChannelizer* channelConfigMsg = SSBDemod::MsgConfigureChannelizer::create(
48000, m_channelMarker.getCenterFrequency());
m_ssbDemod->getInputMessageQueue()->push(channelConfigMsg);
m_ssbDemod->configure(m_ssbDemod->getInputMessageQueue(),
ui->BW->value() * 100.0,
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());
SSBDemod::MsgConfigureSSBDemod* message = SSBDemod::MsgConfigureSSBDemod::create( m_settings, force);
m_ssbDemod->getInputMessageQueue()->push(message);
}
}
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->agcPowerThreshold->setValue(m_settings.m_agcPowerThreshold);
displayAGCPowerThreshold(ui->agcPowerThreshold->value());
ui->agcThresholdGate->setValue(m_settings.m_agcThresholdGate);
s = QString::number(ui->agcThresholdGate->value(), 'f', 0);
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)

View File

@ -1,18 +1,17 @@
#ifndef INCLUDE_SSBDEMODGUI_H
#define INCLUDE_SSBDEMODGUI_H
#include <plugin/plugininstancegui.h>
#include "gui/rollupwidget.h"
#include "dsp/channelmarker.h"
#include "dsp/movingaverage.h"
#include "plugin/plugininstanceui.h"
#include "util/messagequeue.h"
#include "ssbdemodsettings.h"
class PluginAPI;
class DeviceSourceAPI;
class AudioFifo;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class SSBDemod;
class SpectrumVis;
@ -20,7 +19,7 @@ namespace Ui {
class SSBDemodGUI;
}
class SSBDemodGUI : public RollupWidget, public PluginInstanceUI {
class SSBDemodGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT
public:
@ -65,6 +64,7 @@ private:
PluginAPI* m_pluginAPI;
DeviceSourceAPI* m_deviceAPI;
ChannelMarker m_channelMarker;
SSBDemodSettings m_settings;
bool m_basicSettingsShown;
bool m_doApplySettings;
int m_rate;
@ -76,8 +76,6 @@ private:
bool m_squelchOpen;
uint32_t m_tickCount;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
SSBDemod* m_ssbDemod;
SpectrumVis* m_spectrumVis;
MessageQueue m_inputMessageQueue;
@ -89,8 +87,10 @@ private:
bool setNewRate(int spanLog2);
void blockApplySettings(bool block);
void applySettings();
void applySettings(bool force = false);
void displaySettings();
void displayUDPAddress();
void updateChannelMarker();
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 = {
QString("SSB Demodulator"),
QString("3.5.4"),
QString("3.7.3"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
@ -33,7 +33,7 @@ void SSBPlugin::initPlugin(PluginAPI* pluginAPI)
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)
{

View File

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

View File

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

View File

@ -33,7 +33,7 @@ void WFMPlugin::initPlugin(PluginAPI* pluginAPI)
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)
{

View File

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

View File

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

View File

@ -33,7 +33,7 @@ void TCPSrcPlugin::initPlugin(PluginAPI* pluginAPI)
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)
{

View File

@ -17,7 +17,7 @@ public:
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private:
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
}
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)
{

View File

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

View File

@ -50,7 +50,7 @@ void UDPSrcPlugin::initPlugin(PluginAPI* pluginAPI)
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)
{

View File

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

View File

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

View File

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

View File

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

View File

@ -49,7 +49,7 @@ void AMModPlugin::initPlugin(PluginAPI* pluginAPI)
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)
{

View File

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

View File

@ -385,16 +385,20 @@ void ATVMod::pullVideo(Real& sample)
time_t start, end;
cv::Mat frame;
MsgReportCameraData *report;
report = MsgReportCameraData::create(
camera.m_cameraNumber,
0.0f,
camera.m_videoFPSManual,
camera.m_videoFPSManualEnable,
camera.m_videoWidth,
camera.m_videoHeight,
1); // open splash screen on GUI side
getOutputMessageQueue()->push(report);
if (getMessageQueueToGUI())
{
MsgReportCameraData *report;
report = MsgReportCameraData::create(
camera.m_cameraNumber,
0.0f,
camera.m_videoFPSManual,
camera.m_videoFPSManualEnable,
camera.m_videoWidth,
camera.m_videoHeight,
1); // open splash screen on GUI side
getMessageQueueToGUI()->push(report);
}
int nbFrames = 0;
time(&start);
@ -414,15 +418,19 @@ void ATVMod::pullVideo(Real& sample)
camera.m_videoFPSCount = camera.m_videoFPSq;
camera.m_videoPrevFPSCount = 0;
report = MsgReportCameraData::create(
camera.m_cameraNumber,
camera.m_videoFPS,
camera.m_videoFPSManual,
camera.m_videoFPSManualEnable,
camera.m_videoWidth,
camera.m_videoHeight,
2); // close splash screen on GUI side
getOutputMessageQueue()->push(report);
if (getMessageQueueToGUI())
{
MsgReportCameraData *report;
report = MsgReportCameraData::create(
camera.m_cameraNumber,
camera.m_videoFPS,
camera.m_videoFPSManual,
camera.m_videoFPSManualEnable,
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
{
@ -431,16 +439,19 @@ void ATVMod::pullVideo(Real& sample)
camera.m_videoFPSCount = camera.m_videoFPSq;
camera.m_videoPrevFPSCount = 0;
MsgReportCameraData *report;
report = MsgReportCameraData::create(
camera.m_cameraNumber,
camera.m_videoFPS,
camera.m_videoFPSManual,
camera.m_videoFPSManualEnable,
camera.m_videoWidth,
camera.m_videoHeight,
0);
getOutputMessageQueue()->push(report);
if (getMessageQueueToGUI())
{
MsgReportCameraData *report;
report = MsgReportCameraData::create(
camera.m_cameraNumber,
camera.m_videoFPS,
camera.m_videoFPSManual,
camera.m_videoFPSManualEnable,
camera.m_videoWidth,
camera.m_videoHeight,
0);
getMessageQueueToGUI()->push(report);
}
}
int fpsIncrement = (int) camera.m_videoFPSCount - camera.m_videoPrevFPSCount;
@ -601,9 +612,12 @@ bool ATVMod::handleMessage(const Message& cmd)
framesCount = 0;
}
MsgReportVideoFileSourceStreamTiming *report;
report = MsgReportVideoFileSourceStreamTiming::create(framesCount);
getOutputMessageQueue()->push(report);
if (getMessageQueueToGUI())
{
MsgReportVideoFileSourceStreamTiming *report;
report = MsgReportVideoFileSourceStreamTiming::create(framesCount);
getMessageQueueToGUI()->push(report);
}
return true;
}
@ -615,16 +629,20 @@ bool ATVMod::handleMessage(const Message& cmd)
if (index < m_cameras.size())
{
m_cameraIndex = index;
MsgReportCameraData *report;
report = MsgReportCameraData::create(
m_cameras[m_cameraIndex].m_cameraNumber,
m_cameras[m_cameraIndex].m_videoFPS,
m_cameras[m_cameraIndex].m_videoFPSManual,
m_cameras[m_cameraIndex].m_videoFPSManualEnable,
m_cameras[m_cameraIndex].m_videoWidth,
m_cameras[m_cameraIndex].m_videoHeight,
0);
getOutputMessageQueue()->push(report);
if (getMessageQueueToGUI())
{
MsgReportCameraData *report;
report = MsgReportCameraData::create(
m_cameras[m_cameraIndex].m_cameraNumber,
m_cameras[m_cameraIndex].m_videoFPS,
m_cameras[m_cameraIndex].m_videoFPSManual,
m_cameras[m_cameraIndex].m_videoFPSManualEnable,
m_cameras[m_cameraIndex].m_videoWidth,
m_cameras[m_cameraIndex].m_videoHeight,
0);
getMessageQueueToGUI()->push(report);
}
}
return true;
@ -721,9 +739,12 @@ void ATVMod::apply(bool force)
applyStandard(); // set all timings
m_settingsMutex.unlock();
MsgReportEffectiveSampleRate *report;
report = MsgReportEffectiveSampleRate::create(m_tvSampleRate, m_pointsPerLine);
getOutputMessageQueue()->push(report);
if (getMessageQueueToGUI())
{
MsgReportEffectiveSampleRate *report;
report = MsgReportEffectiveSampleRate::create(m_tvSampleRate, m_pointsPerLine);
getMessageQueueToGUI()->push(report);
}
}
if ((m_config.m_outputSampleRate != m_running.m_outputSampleRate)
@ -977,9 +998,12 @@ void ATVMod::openVideo(const QString& fileName)
calculateVideoSizes();
m_videoEOF = false;
MsgReportVideoFileSourceStreamData *report;
report = MsgReportVideoFileSourceStreamData::create(m_videoFPS, m_videoLength);
getOutputMessageQueue()->push(report);
if (getMessageQueueToGUI())
{
MsgReportVideoFileSourceStreamData *report;
report = MsgReportVideoFileSourceStreamData::create(m_videoFPS, m_videoLength);
getMessageQueueToGUI()->push(report);
}
}
else
{
@ -1114,16 +1138,20 @@ void ATVMod::getCameraNumbers(std::vector<int>& numbers)
if (m_cameras.size() > 0)
{
m_cameraIndex = 0;
MsgReportCameraData *report;
report = MsgReportCameraData::create(
m_cameras[0].m_cameraNumber,
m_cameras[0].m_videoFPS,
m_cameras[0].m_videoFPSManual,
m_cameras[0].m_videoFPSManualEnable,
m_cameras[0].m_videoWidth,
m_cameras[0].m_videoHeight,
0);
getOutputMessageQueue()->push(report);
if (getMessageQueueToGUI())
{
MsgReportCameraData *report;
report = MsgReportCameraData::create(
m_cameras[0].m_cameraNumber,
m_cameras[0].m_videoFPS,
m_cameras[0].m_videoFPSManual,
m_cameras[0].m_videoFPSManualEnable,
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;
while ((message = m_atvMod->getOutputMessageQueue()->pop()) != 0)
while ((message = getInputMessageQueue()->pop()) != 0)
{
if (handleMessage(*message))
{
@ -622,6 +622,7 @@ ATVModGUI::ATVModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa
connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked()));
m_atvMod = new ATVMod();
m_atvMod->setMessageQueueToGUI(getInputMessageQueue());
m_channelizer = new UpChannelizer(m_atvMod);
m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this);
//m_pluginAPI->addThreadedSink(m_threadedChannelizer);
@ -648,7 +649,7 @@ ATVModGUI::ATVModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa
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)));
std::vector<int> cameraNumbers;

View File

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

View File

@ -23,7 +23,7 @@
const PluginDescriptor ATVModPlugin::m_pluginDescriptor = {
QString("ATV Modulator"),
QString("3.5.0"),
QString("3.7.3"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
@ -49,7 +49,7 @@ void ATVModPlugin::initPlugin(PluginAPI* pluginAPI)
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)
{

View File

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

View File

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

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