Created demod constructor method in all Rx channel plugins

This commit is contained in:
f4exb 2017-11-08 14:23:49 +01:00
parent cef9d5d7bc
commit 4ad038ed9d
71 changed files with 2036 additions and 1887 deletions

View File

@ -1,236 +1,237 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Edouard Griffiths, F4EXB // // Copyright (C) 2015 Edouard Griffiths, F4EXB //
// // // //
// This program is free software; you can redistribute it and/or modify // // 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 // // it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or // // the Free Software Foundation as version 3 of the License, or //
// // // //
// This program is distributed in the hope that it will be useful, // // This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of // // but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. // // GNU General Public License V3 for more details. //
// // // //
// You should have received a copy of the GNU General Public License // // You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#include "chanalyzer.h" #include "chanalyzer.h"
#include <QTime> #include <QTime>
#include <QDebug> #include <QDebug>
#include <stdio.h> #include <stdio.h>
#include <dsp/downchannelizer.h> #include <dsp/downchannelizer.h>
#include "dsp/threadedbasebandsamplesink.h" #include "dsp/threadedbasebandsamplesink.h"
#include "device/devicesourceapi.h" #include "device/devicesourceapi.h"
#include "audio/audiooutput.h" #include "audio/audiooutput.h"
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelAnalyzer, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelAnalyzer, Message) MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgReportChannelSampleRateChanged, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgReportChannelSampleRateChanged, Message)
const QString ChannelAnalyzer::m_channelID = "org.f4exb.sdrangelove.channel.chanalyzer";
ChannelAnalyzer::ChannelAnalyzer(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI), ChannelAnalyzer::ChannelAnalyzer(DeviceSourceAPI *deviceAPI) :
m_sampleSink(0), m_deviceAPI(deviceAPI),
m_settingsMutex(QMutex::Recursive) m_sampleSink(0),
{ m_settingsMutex(QMutex::Recursive)
m_Bandwidth = 5000; {
m_LowCutoff = 300; m_Bandwidth = 5000;
m_spanLog2 = 3; m_LowCutoff = 300;
m_sampleRate = 96000; m_spanLog2 = 3;
m_frequency = 0; m_sampleRate = 96000;
m_nco.setFreq(m_frequency, m_sampleRate); m_frequency = 0;
m_undersampleCount = 0; m_nco.setFreq(m_frequency, m_sampleRate);
m_sum = 0; m_undersampleCount = 0;
m_usb = true; m_sum = 0;
m_ssb = true; m_usb = true;
m_magsq = 0; m_ssb = true;
SSBFilter = new fftfilt(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate, ssbFftLen); m_magsq = 0;
DSBFilter = new fftfilt(m_Bandwidth / m_sampleRate, 2*ssbFftLen); 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); m_channelizer = new DownChannelizer(this);
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
m_deviceAPI->addThreadedSink(m_threadedChannelizer); connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged()));
} m_deviceAPI->addThreadedSink(m_threadedChannelizer);
}
ChannelAnalyzer::~ChannelAnalyzer()
{ ChannelAnalyzer::~ChannelAnalyzer()
if (SSBFilter) delete SSBFilter; {
if (DSBFilter) delete DSBFilter; if (SSBFilter) delete SSBFilter;
m_deviceAPI->removeThreadedSink(m_threadedChannelizer); if (DSBFilter) delete DSBFilter;
delete m_threadedChannelizer; m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_channelizer; delete m_threadedChannelizer;
} delete m_channelizer;
}
void ChannelAnalyzer::configure(MessageQueue* messageQueue,
Real Bandwidth, void ChannelAnalyzer::configure(MessageQueue* messageQueue,
Real LowCutoff, Real Bandwidth,
int spanLog2, Real LowCutoff,
bool ssb) int spanLog2,
{ bool ssb)
Message* cmd = MsgConfigureChannelAnalyzer::create(Bandwidth, LowCutoff, spanLog2, ssb); {
messageQueue->push(cmd); Message* cmd = MsgConfigureChannelAnalyzer::create(Bandwidth, LowCutoff, spanLog2, ssb);
} messageQueue->push(cmd);
}
void ChannelAnalyzer::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly __attribute__((unused)))
{ void ChannelAnalyzer::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly __attribute__((unused)))
fftfilt::cmplx *sideband; {
int n_out; fftfilt::cmplx *sideband;
int decim = 1<<m_spanLog2; int n_out;
unsigned char decim_mask = decim - 1; // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1) int decim = 1<<m_spanLog2;
unsigned char decim_mask = decim - 1; // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
m_settingsMutex.lock();
m_settingsMutex.lock();
for(SampleVector::const_iterator it = begin; it < end; ++it)
{ for(SampleVector::const_iterator it = begin; it < end; ++it)
//Complex c(it->real() / 32768.0f, it->imag() / 32768.0f); {
Complex c(it->real(), it->imag()); //Complex c(it->real() / 32768.0f, it->imag() / 32768.0f);
c *= m_nco.nextIQ(); Complex c(it->real(), it->imag());
c *= m_nco.nextIQ();
if (m_ssb)
{ if (m_ssb)
n_out = SSBFilter->runSSB(c, &sideband, m_usb); {
} n_out = SSBFilter->runSSB(c, &sideband, m_usb);
else }
{ else
n_out = DSBFilter->runDSB(c, &sideband); {
} n_out = DSBFilter->runDSB(c, &sideband);
}
for (int i = 0; i < n_out; i++)
{ for (int i = 0; i < n_out; i++)
// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display {
// smart decimation with bit gain using float arithmetic (23 bits significand) // Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
// smart decimation with bit gain using float arithmetic (23 bits significand)
m_sum += sideband[i];
m_sum += sideband[i];
if (!(m_undersampleCount++ & decim_mask))
{ if (!(m_undersampleCount++ & decim_mask))
m_sum /= decim; {
m_magsq = (m_sum.real() * m_sum.real() + m_sum.imag() * m_sum.imag())/ (1<<30); m_sum /= decim;
m_magsq = (m_sum.real() * m_sum.real() + m_sum.imag() * m_sum.imag())/ (1<<30);
if (m_ssb & !m_usb)
{ // invert spectrum for LSB if (m_ssb & !m_usb)
//m_sampleBuffer.push_back(Sample(m_sum.imag() * 32768.0, m_sum.real() * 32768.0)); { // invert spectrum for LSB
m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real())); //m_sampleBuffer.push_back(Sample(m_sum.imag() * 32768.0, m_sum.real() * 32768.0));
} m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real()));
else }
{ else
//m_sampleBuffer.push_back(Sample(m_sum.real() * 32768.0, m_sum.imag() * 32768.0)); {
m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag())); //m_sampleBuffer.push_back(Sample(m_sum.real() * 32768.0, m_sum.imag() * 32768.0));
} m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag()));
}
m_sum = 0;
} m_sum = 0;
} }
} }
}
if(m_sampleSink != NULL)
{ if(m_sampleSink != NULL)
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_ssb); // m_ssb = positive only {
} m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_ssb); // m_ssb = positive only
}
m_sampleBuffer.clear();
m_sampleBuffer.clear();
m_settingsMutex.unlock();
} m_settingsMutex.unlock();
}
void ChannelAnalyzer::start()
{ void ChannelAnalyzer::start()
} {
}
void ChannelAnalyzer::stop()
{ void ChannelAnalyzer::stop()
} {
}
void ChannelAnalyzer::channelSampleRateChanged()
{ void ChannelAnalyzer::channelSampleRateChanged()
MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create(); {
getMessageQueueToGUI()->push(msg); MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create();
} getMessageQueueToGUI()->push(msg);
}
bool ChannelAnalyzer::handleMessage(const Message& cmd)
{ bool ChannelAnalyzer::handleMessage(const Message& cmd)
float band, lowCutoff; {
float band, lowCutoff;
qDebug() << "ChannelAnalyzer::handleMessage";
qDebug() << "ChannelAnalyzer::handleMessage";
if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{ if (DownChannelizer::MsgChannelizerNotification::match(cmd))
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; {
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
m_sampleRate = notif.getSampleRate();
m_nco.setFreq(-notif.getFrequencyOffset(), m_sampleRate); m_sampleRate = notif.getSampleRate();
m_nco.setFreq(-notif.getFrequencyOffset(), m_sampleRate);
qDebug() << "ChannelAnalyzer::handleMessage: MsgChannelizerNotification: m_sampleRate: " << m_sampleRate
<< " frequencyOffset: " << notif.getFrequencyOffset(); qDebug() << "ChannelAnalyzer::handleMessage: MsgChannelizerNotification: m_sampleRate: " << m_sampleRate
<< " frequencyOffset: " << notif.getFrequencyOffset();
return true;
} return true;
else if (MsgConfigureChannelizer::match(cmd)) }
{ else if (MsgConfigureChannelizer::match(cmd))
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; {
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
m_channelizer->getInputSampleRate(), m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getCenterFrequency()); m_channelizer->getInputSampleRate(),
cfg.getCenterFrequency());
return true;
} return true;
else if (MsgConfigureChannelAnalyzer::match(cmd)) }
{ else if (MsgConfigureChannelAnalyzer::match(cmd))
MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd; {
MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd;
band = cfg.getBandwidth();
lowCutoff = cfg.getLoCutoff(); band = cfg.getBandwidth();
lowCutoff = cfg.getLoCutoff();
if (band < 0)
{ if (band < 0)
band = -band; {
lowCutoff = -lowCutoff; band = -band;
m_usb = false; lowCutoff = -lowCutoff;
} m_usb = false;
else }
{ else
m_usb = true; {
} m_usb = true;
}
if (band < 100.0f)
{ if (band < 100.0f)
band = 100.0f; {
lowCutoff = 0; band = 100.0f;
} lowCutoff = 0;
}
m_settingsMutex.lock();
m_settingsMutex.lock();
m_Bandwidth = band;
m_LowCutoff = lowCutoff; m_Bandwidth = band;
m_LowCutoff = lowCutoff;
SSBFilter->create_filter(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate);
DSBFilter->create_dsb_filter(m_Bandwidth / m_sampleRate); SSBFilter->create_filter(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate);
DSBFilter->create_dsb_filter(m_Bandwidth / m_sampleRate);
m_spanLog2 = cfg.getSpanLog2();
m_ssb = cfg.getSSB(); m_spanLog2 = cfg.getSpanLog2();
m_ssb = cfg.getSSB();
m_settingsMutex.unlock();
m_settingsMutex.unlock();
qDebug() << " - MsgConfigureChannelAnalyzer: m_Bandwidth: " << m_Bandwidth
<< " m_LowCutoff: " << m_LowCutoff qDebug() << " - MsgConfigureChannelAnalyzer: m_Bandwidth: " << m_Bandwidth
<< " m_spanLog2: " << m_spanLog2 << " m_LowCutoff: " << m_LowCutoff
<< " m_ssb: " << m_ssb; << " m_spanLog2: " << m_spanLog2
<< " m_ssb: " << m_ssb;
return true;
} return true;
else }
{ else
if (m_sampleSink != 0) {
{ if (m_sampleSink != 0)
return m_sampleSink->handleMessage(cmd); {
} return m_sampleSink->handleMessage(cmd);
else }
{ else
return false; {
} return false;
} }
} }
}

View File

@ -1,154 +1,156 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Edouard Griffiths, F4EXB // // Copyright (C) 2015 Edouard Griffiths, F4EXB //
// // // //
// This program is free software; you can redistribute it and/or modify // // 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 // // it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or // // the Free Software Foundation as version 3 of the License, or //
// // // //
// This program is distributed in the hope that it will be useful, // // This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of // // but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. // // GNU General Public License V3 for more details. //
// // // //
// You should have received a copy of the GNU General Public License // // You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_CHANALYZER_H #ifndef INCLUDE_CHANALYZER_H
#define INCLUDE_CHANALYZER_H #define INCLUDE_CHANALYZER_H
#include <dsp/basebandsamplesink.h> #include <dsp/basebandsamplesink.h>
#include <QMutex> #include <QMutex>
#include <vector> #include <vector>
#include "dsp/ncof.h" #include "dsp/ncof.h"
#include "dsp/fftfilt.h" #include "dsp/fftfilt.h"
#include "audio/audiofifo.h" #include "audio/audiofifo.h"
#include "util/message.h" #include "util/message.h"
#define ssbFftLen 1024 #define ssbFftLen 1024
class DeviceSourceAPI; class DeviceSourceAPI;
class ThreadedBasebandSampleSink; class ThreadedBasebandSampleSink;
class DownChannelizer; class DownChannelizer;
class ChannelAnalyzer : public BasebandSampleSink { class ChannelAnalyzer : public BasebandSampleSink {
public: public:
class MsgConfigureChannelAnalyzer : public Message { class MsgConfigureChannelAnalyzer : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
Real getBandwidth() const { return m_Bandwidth; } Real getBandwidth() const { return m_Bandwidth; }
Real getLoCutoff() const { return m_LowCutoff; } Real getLoCutoff() const { return m_LowCutoff; }
int getSpanLog2() const { return m_spanLog2; } int getSpanLog2() const { return m_spanLog2; }
bool getSSB() const { return m_ssb; } bool getSSB() const { return m_ssb; }
static MsgConfigureChannelAnalyzer* create(Real Bandwidth, static MsgConfigureChannelAnalyzer* create(Real Bandwidth,
Real LowCutoff, Real LowCutoff,
int spanLog2, int spanLog2,
bool ssb) bool ssb)
{ {
return new MsgConfigureChannelAnalyzer(Bandwidth, LowCutoff, spanLog2, ssb); return new MsgConfigureChannelAnalyzer(Bandwidth, LowCutoff, spanLog2, ssb);
} }
private: private:
Real m_Bandwidth; Real m_Bandwidth;
Real m_LowCutoff; Real m_LowCutoff;
int m_spanLog2; int m_spanLog2;
bool m_ssb; bool m_ssb;
MsgConfigureChannelAnalyzer(Real Bandwidth, MsgConfigureChannelAnalyzer(Real Bandwidth,
Real LowCutoff, Real LowCutoff,
int spanLog2, int spanLog2,
bool ssb) : bool ssb) :
Message(), Message(),
m_Bandwidth(Bandwidth), m_Bandwidth(Bandwidth),
m_LowCutoff(LowCutoff), m_LowCutoff(LowCutoff),
m_spanLog2(spanLog2), m_spanLog2(spanLog2),
m_ssb(ssb) m_ssb(ssb)
{ } { }
}; };
class MsgConfigureChannelizer : public Message { class MsgConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getCenterFrequency() const { return m_centerFrequency; } int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int centerFrequency) static MsgConfigureChannelizer* create(int centerFrequency)
{ {
return new MsgConfigureChannelizer(centerFrequency); return new MsgConfigureChannelizer(centerFrequency);
} }
private: private:
int m_centerFrequency; int m_centerFrequency;
MsgConfigureChannelizer(int centerFrequency) : MsgConfigureChannelizer(int centerFrequency) :
Message(), Message(),
m_centerFrequency(centerFrequency) m_centerFrequency(centerFrequency)
{ } { }
}; };
class MsgReportChannelSampleRateChanged : public Message { class MsgReportChannelSampleRateChanged : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
static MsgReportChannelSampleRateChanged* create() static MsgReportChannelSampleRateChanged* create()
{ {
return new MsgReportChannelSampleRateChanged(); return new MsgReportChannelSampleRateChanged();
} }
private: private:
MsgReportChannelSampleRateChanged() : MsgReportChannelSampleRateChanged() :
Message() Message()
{ } { }
}; };
ChannelAnalyzer(DeviceSourceAPI *deviceAPI); ChannelAnalyzer(DeviceSourceAPI *deviceAPI);
virtual ~ChannelAnalyzer(); virtual ~ChannelAnalyzer();
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
void configure(MessageQueue* messageQueue, void configure(MessageQueue* messageQueue,
Real Bandwidth, Real Bandwidth,
Real LowCutoff, Real LowCutoff,
int spanLog2, int spanLog2,
bool ssb); bool ssb);
int getSampleRate() const { return m_sampleRate; } int getSampleRate() const { return m_sampleRate; }
Real getMagSq() const { return m_magsq; } Real getMagSq() const { return m_magsq; }
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
virtual void start(); virtual void start();
virtual void stop(); virtual void stop();
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
private slots: static const QString m_channelID;
void channelSampleRateChanged();
private slots:
private: void channelSampleRateChanged();
DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer; private:
DownChannelizer* m_channelizer; DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
Real m_Bandwidth; DownChannelizer* m_channelizer;
Real m_LowCutoff;
int m_spanLog2; Real m_Bandwidth;
int m_undersampleCount; Real m_LowCutoff;
fftfilt::cmplx m_sum; int m_spanLog2;
int m_sampleRate; int m_undersampleCount;
int m_frequency; fftfilt::cmplx m_sum;
bool m_usb; int m_sampleRate;
bool m_ssb; int m_frequency;
Real m_magsq; bool m_usb;
bool m_ssb;
NCOF m_nco; Real m_magsq;
fftfilt* SSBFilter;
fftfilt* DSBFilter; NCOF m_nco;
fftfilt* SSBFilter;
BasebandSampleSink* m_sampleSink; fftfilt* DSBFilter;
SampleVector m_sampleBuffer;
QMutex m_settingsMutex; BasebandSampleSink* m_sampleSink;
}; SampleVector m_sampleBuffer;
QMutex m_settingsMutex;
#endif // INCLUDE_CHANALYZER_H };
#endif // INCLUDE_CHANALYZER_H

View File

@ -38,8 +38,6 @@
#include "chanalyzer.h" #include "chanalyzer.h"
const QString ChannelAnalyzerGUI::m_channelID = "org.f4exb.sdrangelove.channel.chanalyzer";
ChannelAnalyzerGUI* ChannelAnalyzerGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet) ChannelAnalyzerGUI* ChannelAnalyzerGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
{ {
ChannelAnalyzerGUI* gui = new ChannelAnalyzerGUI(pluginAPI, deviceUISet); ChannelAnalyzerGUI* gui = new ChannelAnalyzerGUI(pluginAPI, deviceUISet);
@ -370,7 +368,7 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceUISet *device
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
m_deviceUISet->registerRxChannelInstance(m_channelID, this); m_deviceUISet->registerRxChannelInstance(ChannelAnalyzer::m_channelID, this);
m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this); m_deviceUISet->addRollupWidget(this);

View File

@ -55,8 +55,6 @@ public:
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message); virtual bool handleMessage(const Message& message);
static const QString m_channelID;
private slots: private slots:
void viewChanged(); void viewChanged();
void on_deltaFrequency_changed(quint64 value); void on_deltaFrequency_changed(quint64 value);

View File

@ -4,6 +4,7 @@
#include "plugin/pluginapi.h" #include "plugin/pluginapi.h"
#include "chanalyzergui.h" #include "chanalyzergui.h"
#include "chanalyzer.h"
const PluginDescriptor ChannelAnalyzerPlugin::m_pluginDescriptor = { const PluginDescriptor ChannelAnalyzerPlugin::m_pluginDescriptor = {
QString("Channel Analyzer"), QString("Channel Analyzer"),
@ -30,12 +31,12 @@ void ChannelAnalyzerPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI = pluginAPI; m_pluginAPI = pluginAPI;
// register demodulator // register demodulator
m_pluginAPI->registerRxChannel(ChannelAnalyzerGUI::m_channelID, this); m_pluginAPI->registerRxChannel(ChannelAnalyzer::m_channelID, this);
} }
PluginInstanceGUI* ChannelAnalyzerPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet) PluginInstanceGUI* ChannelAnalyzerPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
{ {
if(channelName == ChannelAnalyzerGUI::m_channelID) if(channelName == ChannelAnalyzer::m_channelID)
{ {
ChannelAnalyzerGUI* gui = ChannelAnalyzerGUI::create(m_pluginAPI, deviceUISet); ChannelAnalyzerGUI* gui = ChannelAnalyzerGUI::create(m_pluginAPI, deviceUISet);
return gui; return gui;
@ -43,3 +44,15 @@ PluginInstanceGUI* ChannelAnalyzerPlugin::createRxChannelGUI(const QString& chan
return NULL; return NULL;
} }
} }
BasebandSampleSink* ChannelAnalyzerPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{
if(channelName == ChannelAnalyzer::m_channelID)
{
ChannelAnalyzer* sink = new ChannelAnalyzer(deviceAPI);
return sink;
} else {
return 0;
}
}

View File

@ -5,6 +5,7 @@
#include "plugin/plugininterface.h" #include "plugin/plugininterface.h"
class DeviceUISet; class DeviceUISet;
class BasebandSampleSink;
class ChannelAnalyzerPlugin : public QObject, PluginInterface { class ChannelAnalyzerPlugin : public QObject, PluginInterface {
Q_OBJECT Q_OBJECT
@ -18,6 +19,7 @@ public:
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet); PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -1,251 +1,252 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB // // Copyright (C) 2017 Edouard Griffiths, F4EXB //
// // // //
// This program is free software; you can redistribute it and/or modify // // 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 // // it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or // // the Free Software Foundation as version 3 of the License, or //
// // // //
// This program is distributed in the hope that it will be useful, // // This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of // // but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. // // GNU General Public License V3 for more details. //
// // // //
// You should have received a copy of the GNU General Public License // // You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#include "chanalyzerng.h" #include "chanalyzerng.h"
#include <QTime> #include <QTime>
#include <QDebug> #include <QDebug>
#include <stdio.h> #include <stdio.h>
#include "device/devicesourceapi.h" #include "device/devicesourceapi.h"
#include "audio/audiooutput.h" #include "audio/audiooutput.h"
#include "dsp/threadedbasebandsamplesink.h" #include "dsp/threadedbasebandsamplesink.h"
#include "dsp/downchannelizer.h" #include "dsp/downchannelizer.h"
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelAnalyzer, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelAnalyzer, Message) MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgReportChannelSampleRateChanged, Message)
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgReportChannelSampleRateChanged, Message)
const QString ChannelAnalyzerNG::m_channelID = "sdrangel.channel.chanalyzerng";
ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI), ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) :
m_sampleSink(0), m_deviceAPI(deviceAPI),
m_settingsMutex(QMutex::Recursive) m_sampleSink(0),
{ m_settingsMutex(QMutex::Recursive)
m_undersampleCount = 0; {
m_sum = 0; m_undersampleCount = 0;
m_usb = true; m_sum = 0;
m_magsq = 0; m_usb = true;
m_useInterpolator = false; m_magsq = 0;
m_interpolatorDistance = 1.0f; m_useInterpolator = false;
m_interpolatorDistanceRemain = 0.0f; m_interpolatorDistance = 1.0f;
SSBFilter = new fftfilt(m_config.m_LowCutoff / m_config.m_inputSampleRate, m_config.m_Bandwidth / m_config.m_inputSampleRate, ssbFftLen); m_interpolatorDistanceRemain = 0.0f;
DSBFilter = new fftfilt(m_config.m_Bandwidth / m_config.m_inputSampleRate, 2*ssbFftLen); SSBFilter = new fftfilt(m_config.m_LowCutoff / m_config.m_inputSampleRate, m_config.m_Bandwidth / m_config.m_inputSampleRate, ssbFftLen);
DSBFilter = new fftfilt(m_config.m_Bandwidth / m_config.m_inputSampleRate, 2*ssbFftLen);
m_channelizer = new DownChannelizer(this);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); m_channelizer = new DownChannelizer(this);
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged())); m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
m_deviceAPI->addThreadedSink(m_threadedChannelizer); connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged()));
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
apply(true);
} apply(true);
}
ChannelAnalyzerNG::~ChannelAnalyzerNG()
{ ChannelAnalyzerNG::~ChannelAnalyzerNG()
if (SSBFilter) delete SSBFilter; {
if (DSBFilter) delete DSBFilter; if (SSBFilter) delete SSBFilter;
m_deviceAPI->removeThreadedSink(m_threadedChannelizer); if (DSBFilter) delete DSBFilter;
delete m_threadedChannelizer; m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_channelizer; delete m_threadedChannelizer;
} delete m_channelizer;
}
void ChannelAnalyzerNG::configure(MessageQueue* messageQueue,
int channelSampleRate, void ChannelAnalyzerNG::configure(MessageQueue* messageQueue,
Real Bandwidth, int channelSampleRate,
Real LowCutoff, Real Bandwidth,
int spanLog2, Real LowCutoff,
bool ssb) int spanLog2,
{ bool ssb)
Message* cmd = MsgConfigureChannelAnalyzer::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb); {
messageQueue->push(cmd); Message* cmd = MsgConfigureChannelAnalyzer::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb);
} messageQueue->push(cmd);
}
void ChannelAnalyzerNG::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly __attribute__((unused)))
{ void ChannelAnalyzerNG::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly __attribute__((unused)))
fftfilt::cmplx *sideband = 0; {
Complex ci; fftfilt::cmplx *sideband = 0;
Complex ci;
m_settingsMutex.lock();
m_settingsMutex.lock();
for(SampleVector::const_iterator it = begin; it < end; ++it)
{ for(SampleVector::const_iterator it = begin; it < end; ++it)
Complex c(it->real(), it->imag()); {
c *= m_nco.nextIQ(); Complex c(it->real(), it->imag());
c *= m_nco.nextIQ();
if (m_useInterpolator)
{ if (m_useInterpolator)
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci)) {
{ if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci))
processOneSample(ci, sideband); {
m_interpolatorDistanceRemain += m_interpolatorDistance; processOneSample(ci, sideband);
} m_interpolatorDistanceRemain += m_interpolatorDistance;
} }
else }
{ else
processOneSample(c, sideband); {
} processOneSample(c, sideband);
} }
}
if(m_sampleSink != 0)
{ if(m_sampleSink != 0)
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_running.m_ssb); // m_ssb = positive only {
} m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_running.m_ssb); // m_ssb = positive only
}
m_sampleBuffer.clear();
m_sampleBuffer.clear();
m_settingsMutex.unlock();
} m_settingsMutex.unlock();
}
void ChannelAnalyzerNG::start()
{ void ChannelAnalyzerNG::start()
} {
}
void ChannelAnalyzerNG::stop()
{ void ChannelAnalyzerNG::stop()
} {
}
void ChannelAnalyzerNG::channelizerInputSampleRateChanged()
{ void ChannelAnalyzerNG::channelizerInputSampleRateChanged()
MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create(); {
getMessageQueueToGUI()->push(msg); MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create();
} getMessageQueueToGUI()->push(msg);
}
bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
{ bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
qDebug() << "ChannelAnalyzerNG::handleMessage: " << cmd.getIdentifier(); {
qDebug() << "ChannelAnalyzerNG::handleMessage: " << cmd.getIdentifier();
if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{ if (DownChannelizer::MsgChannelizerNotification::match(cmd))
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; {
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
m_config.m_inputSampleRate = notif.getSampleRate();
m_config.m_frequency = notif.getFrequencyOffset(); m_config.m_inputSampleRate = notif.getSampleRate();
m_config.m_frequency = notif.getFrequencyOffset();
qDebug() << "ChannelAnalyzerNG::handleMessage: MsgChannelizerNotification:"
<< " m_sampleRate: " << m_config.m_inputSampleRate qDebug() << "ChannelAnalyzerNG::handleMessage: MsgChannelizerNotification:"
<< " frequencyOffset: " << m_config.m_frequency; << " m_sampleRate: " << m_config.m_inputSampleRate
<< " frequencyOffset: " << m_config.m_frequency;
apply();
return true; apply();
} return true;
else if (MsgConfigureChannelizer::match(cmd)) }
{ else if (MsgConfigureChannelizer::match(cmd))
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; {
m_channelizer->configure(m_channelizer->getInputMessageQueue(), MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
cfg.getSampleRate(), m_channelizer->configure(m_channelizer->getInputMessageQueue(),
cfg.getCenterFrequency()); cfg.getSampleRate(),
return true; cfg.getCenterFrequency());
} return true;
else if (MsgConfigureChannelAnalyzer::match(cmd)) }
{ else if (MsgConfigureChannelAnalyzer::match(cmd))
MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd; {
MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd;
m_config.m_channelSampleRate = cfg.getChannelSampleRate();
m_config.m_Bandwidth = cfg.getBandwidth(); m_config.m_channelSampleRate = cfg.getChannelSampleRate();
m_config.m_LowCutoff = cfg.getLoCutoff(); m_config.m_Bandwidth = cfg.getBandwidth();
m_config.m_spanLog2 = cfg.getSpanLog2(); m_config.m_LowCutoff = cfg.getLoCutoff();
m_config.m_ssb = cfg.getSSB(); m_config.m_spanLog2 = cfg.getSpanLog2();
m_config.m_ssb = cfg.getSSB();
qDebug() << "ChannelAnalyzerNG::handleMessage: MsgConfigureChannelAnalyzer:"
<< " m_channelSampleRate: " << m_config.m_channelSampleRate qDebug() << "ChannelAnalyzerNG::handleMessage: MsgConfigureChannelAnalyzer:"
<< " m_Bandwidth: " << m_config.m_Bandwidth << " m_channelSampleRate: " << m_config.m_channelSampleRate
<< " m_LowCutoff: " << m_config.m_LowCutoff << " m_Bandwidth: " << m_config.m_Bandwidth
<< " m_spanLog2: " << m_config.m_spanLog2 << " m_LowCutoff: " << m_config.m_LowCutoff
<< " m_ssb: " << m_config.m_ssb; << " m_spanLog2: " << m_config.m_spanLog2
<< " m_ssb: " << m_config.m_ssb;
apply();
return true; apply();
} return true;
else }
{ else
if (m_sampleSink != 0) {
{ if (m_sampleSink != 0)
return m_sampleSink->handleMessage(cmd); {
} return m_sampleSink->handleMessage(cmd);
else }
{ else
return false; {
} return false;
} }
} }
}
void ChannelAnalyzerNG::apply(bool force)
{ void ChannelAnalyzerNG::apply(bool force)
if ((m_running.m_frequency != m_config.m_frequency) || {
(m_running.m_inputSampleRate != m_config.m_inputSampleRate) || if ((m_running.m_frequency != m_config.m_frequency) ||
force) (m_running.m_inputSampleRate != m_config.m_inputSampleRate) ||
{ force)
m_nco.setFreq(-m_config.m_frequency, m_config.m_inputSampleRate); {
} m_nco.setFreq(-m_config.m_frequency, m_config.m_inputSampleRate);
}
if ((m_running.m_inputSampleRate != m_config.m_inputSampleRate) ||
(m_running.m_channelSampleRate != m_config.m_channelSampleRate) || if ((m_running.m_inputSampleRate != m_config.m_inputSampleRate) ||
force) (m_running.m_channelSampleRate != m_config.m_channelSampleRate) ||
{ force)
m_settingsMutex.lock(); {
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_inputSampleRate / 2.2); m_settingsMutex.lock();
m_interpolatorDistanceRemain = 0.0f; m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_inputSampleRate / 2.2);
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_channelSampleRate; m_interpolatorDistanceRemain = 0.0f;
m_useInterpolator = (m_config.m_inputSampleRate != m_config.m_channelSampleRate); // optim m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_channelSampleRate;
m_settingsMutex.unlock(); m_useInterpolator = (m_config.m_inputSampleRate != m_config.m_channelSampleRate); // optim
} m_settingsMutex.unlock();
}
if ((m_running.m_channelSampleRate != m_config.m_channelSampleRate) ||
(m_running.m_Bandwidth != m_config.m_Bandwidth) || if ((m_running.m_channelSampleRate != m_config.m_channelSampleRate) ||
(m_running.m_LowCutoff != m_config.m_LowCutoff) || (m_running.m_Bandwidth != m_config.m_Bandwidth) ||
force) (m_running.m_LowCutoff != m_config.m_LowCutoff) ||
{ force)
float bandwidth = m_config.m_Bandwidth; {
float lowCutoff = m_config.m_LowCutoff; float bandwidth = m_config.m_Bandwidth;
float lowCutoff = m_config.m_LowCutoff;
if (bandwidth < 0)
{ if (bandwidth < 0)
bandwidth = -bandwidth; {
lowCutoff = -lowCutoff; bandwidth = -bandwidth;
m_usb = false; lowCutoff = -lowCutoff;
} m_usb = false;
else }
{ else
m_usb = true; {
} m_usb = true;
}
if (bandwidth < 100.0f)
{ if (bandwidth < 100.0f)
bandwidth = 100.0f; {
lowCutoff = 0; bandwidth = 100.0f;
} lowCutoff = 0;
}
m_settingsMutex.lock();
m_settingsMutex.lock();
SSBFilter->create_filter(lowCutoff / m_config.m_channelSampleRate, bandwidth / m_config.m_channelSampleRate);
DSBFilter->create_dsb_filter(bandwidth / m_config.m_channelSampleRate); SSBFilter->create_filter(lowCutoff / m_config.m_channelSampleRate, bandwidth / m_config.m_channelSampleRate);
DSBFilter->create_dsb_filter(bandwidth / m_config.m_channelSampleRate);
m_settingsMutex.unlock();
} m_settingsMutex.unlock();
}
m_running.m_frequency = m_config.m_frequency;
m_running.m_channelSampleRate = m_config.m_channelSampleRate; m_running.m_frequency = m_config.m_frequency;
m_running.m_inputSampleRate = m_config.m_inputSampleRate; m_running.m_channelSampleRate = m_config.m_channelSampleRate;
m_running.m_Bandwidth = m_config.m_Bandwidth; m_running.m_inputSampleRate = m_config.m_inputSampleRate;
m_running.m_LowCutoff = m_config.m_LowCutoff; m_running.m_Bandwidth = m_config.m_Bandwidth;
m_running.m_LowCutoff = m_config.m_LowCutoff;
//m_settingsMutex.lock();
m_running.m_spanLog2 = m_config.m_spanLog2; //m_settingsMutex.lock();
m_running.m_ssb = m_config.m_ssb; m_running.m_spanLog2 = m_config.m_spanLog2;
//m_settingsMutex.unlock(); m_running.m_ssb = m_config.m_ssb;
} //m_settingsMutex.unlock();
}

View File

@ -1,242 +1,244 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB // // Copyright (C) 2017 Edouard Griffiths, F4EXB //
// // // //
// This program is free software; you can redistribute it and/or modify // // 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 // // it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or // // the Free Software Foundation as version 3 of the License, or //
// // // //
// This program is distributed in the hope that it will be useful, // // This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of // // but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. // // GNU General Public License V3 for more details. //
// // // //
// You should have received a copy of the GNU General Public License // // You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_CHANALYZERNG_H #ifndef INCLUDE_CHANALYZERNG_H
#define INCLUDE_CHANALYZERNG_H #define INCLUDE_CHANALYZERNG_H
#include <dsp/basebandsamplesink.h> #include <dsp/basebandsamplesink.h>
#include <QMutex> #include <QMutex>
#include <vector> #include <vector>
#include "dsp/interpolator.h" #include "dsp/interpolator.h"
#include "dsp/ncof.h" #include "dsp/ncof.h"
#include "dsp/fftfilt.h" #include "dsp/fftfilt.h"
#include "audio/audiofifo.h" #include "audio/audiofifo.h"
#include "util/message.h" #include "util/message.h"
#define ssbFftLen 1024 #define ssbFftLen 1024
class DeviceSourceAPI; class DeviceSourceAPI;
class ThreadedBasebandSampleSink; class ThreadedBasebandSampleSink;
class DownChannelizer; class DownChannelizer;
class ChannelAnalyzerNG : public BasebandSampleSink { class ChannelAnalyzerNG : public BasebandSampleSink {
public: public:
class MsgConfigureChannelAnalyzer : public Message { class MsgConfigureChannelAnalyzer : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getChannelSampleRate() const { return m_channelSampleRate; } int getChannelSampleRate() const { return m_channelSampleRate; }
Real getBandwidth() const { return m_Bandwidth; } Real getBandwidth() const { return m_Bandwidth; }
Real getLoCutoff() const { return m_LowCutoff; } Real getLoCutoff() const { return m_LowCutoff; }
int getSpanLog2() const { return m_spanLog2; } int getSpanLog2() const { return m_spanLog2; }
bool getSSB() const { return m_ssb; } bool getSSB() const { return m_ssb; }
static MsgConfigureChannelAnalyzer* create( static MsgConfigureChannelAnalyzer* create(
int channelSampleRate, int channelSampleRate,
Real Bandwidth, Real Bandwidth,
Real LowCutoff, Real LowCutoff,
int spanLog2, int spanLog2,
bool ssb) bool ssb)
{ {
return new MsgConfigureChannelAnalyzer( return new MsgConfigureChannelAnalyzer(
channelSampleRate, channelSampleRate,
Bandwidth, Bandwidth,
LowCutoff, LowCutoff,
spanLog2, spanLog2,
ssb); ssb);
} }
private: private:
int m_channelSampleRate; int m_channelSampleRate;
Real m_Bandwidth; Real m_Bandwidth;
Real m_LowCutoff; Real m_LowCutoff;
int m_spanLog2; int m_spanLog2;
bool m_ssb; bool m_ssb;
MsgConfigureChannelAnalyzer( MsgConfigureChannelAnalyzer(
int channelSampleRate, int channelSampleRate,
Real Bandwidth, Real Bandwidth,
Real LowCutoff, Real LowCutoff,
int spanLog2, int spanLog2,
bool ssb) : bool ssb) :
Message(), Message(),
m_channelSampleRate(channelSampleRate), m_channelSampleRate(channelSampleRate),
m_Bandwidth(Bandwidth), m_Bandwidth(Bandwidth),
m_LowCutoff(LowCutoff), m_LowCutoff(LowCutoff),
m_spanLog2(spanLog2), m_spanLog2(spanLog2),
m_ssb(ssb) m_ssb(ssb)
{ } { }
}; };
class MsgConfigureChannelizer : public Message { class MsgConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getSampleRate() const { return m_sampleRate; } int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; } int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency) static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
{ {
return new MsgConfigureChannelizer(sampleRate, centerFrequency); return new MsgConfigureChannelizer(sampleRate, centerFrequency);
} }
private: private:
int m_sampleRate; int m_sampleRate;
int m_centerFrequency; int m_centerFrequency;
MsgConfigureChannelizer(int sampleRate, int centerFrequency) : MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
Message(), Message(),
m_sampleRate(sampleRate), m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency) m_centerFrequency(centerFrequency)
{ } { }
}; };
class MsgReportChannelSampleRateChanged : public Message { class MsgReportChannelSampleRateChanged : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
static MsgReportChannelSampleRateChanged* create() static MsgReportChannelSampleRateChanged* create()
{ {
return new MsgReportChannelSampleRateChanged(); return new MsgReportChannelSampleRateChanged();
} }
private: private:
MsgReportChannelSampleRateChanged() : MsgReportChannelSampleRateChanged() :
Message() Message()
{ } { }
}; };
ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI); ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI);
virtual ~ChannelAnalyzerNG(); virtual ~ChannelAnalyzerNG();
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
void configure(MessageQueue* messageQueue, void configure(MessageQueue* messageQueue,
int channelSampleRate, int channelSampleRate,
Real Bandwidth, Real Bandwidth,
Real LowCutoff, Real LowCutoff,
int spanLog2, int spanLog2,
bool ssb); bool ssb);
DownChannelizer *getChannelizer() { return m_channelizer; } DownChannelizer *getChannelizer() { return m_channelizer; }
int getInputSampleRate() const { return m_running.m_inputSampleRate; } int getInputSampleRate() const { return m_running.m_inputSampleRate; }
int getChannelSampleRate() const { return m_running.m_channelSampleRate; } int getChannelSampleRate() const { return m_running.m_channelSampleRate; }
double getMagSq() const { return m_magsq; } double getMagSq() const { return m_magsq; }
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
virtual void start(); virtual void start();
virtual void stop(); virtual void stop();
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
private slots: static const QString m_channelID;
void channelizerInputSampleRateChanged();
private slots:
private: void channelizerInputSampleRateChanged();
struct Config private:
{
int m_frequency; struct Config
int m_inputSampleRate; {
int m_channelSampleRate; int m_frequency;
Real m_Bandwidth; int m_inputSampleRate;
Real m_LowCutoff; int m_channelSampleRate;
int m_spanLog2; Real m_Bandwidth;
bool m_ssb; Real m_LowCutoff;
int m_spanLog2;
Config() : bool m_ssb;
m_frequency(0),
m_inputSampleRate(96000), Config() :
m_channelSampleRate(96000), m_frequency(0),
m_Bandwidth(5000), m_inputSampleRate(96000),
m_LowCutoff(300), m_channelSampleRate(96000),
m_spanLog2(3), m_Bandwidth(5000),
m_ssb(false) m_LowCutoff(300),
{} m_spanLog2(3),
}; m_ssb(false)
{}
Config m_config; };
Config m_running;
Config m_config;
DeviceSourceAPI *m_deviceAPI; Config m_running;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer; DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
int m_undersampleCount; DownChannelizer* m_channelizer;
fftfilt::cmplx m_sum;
bool m_usb; int m_undersampleCount;
double m_magsq; fftfilt::cmplx m_sum;
bool m_useInterpolator; bool m_usb;
double m_magsq;
NCOF m_nco; bool m_useInterpolator;
Interpolator m_interpolator;
Real m_interpolatorDistance; NCOF m_nco;
Real m_interpolatorDistanceRemain; Interpolator m_interpolator;
Real m_interpolatorDistance;
fftfilt* SSBFilter; Real m_interpolatorDistanceRemain;
fftfilt* DSBFilter;
fftfilt* SSBFilter;
BasebandSampleSink* m_sampleSink; fftfilt* DSBFilter;
SampleVector m_sampleBuffer;
QMutex m_settingsMutex; BasebandSampleSink* m_sampleSink;
SampleVector m_sampleBuffer;
void apply(bool force = false); QMutex m_settingsMutex;
void processOneSample(Complex& c, fftfilt::cmplx *sideband) void apply(bool force = false);
{
int n_out; void processOneSample(Complex& c, fftfilt::cmplx *sideband)
int decim = 1<<m_running.m_spanLog2; {
int n_out;
if (m_running.m_ssb) int decim = 1<<m_running.m_spanLog2;
{
n_out = SSBFilter->runSSB(c, &sideband, m_usb); if (m_running.m_ssb)
} {
else n_out = SSBFilter->runSSB(c, &sideband, m_usb);
{ }
n_out = DSBFilter->runDSB(c, &sideband); else
} {
n_out = DSBFilter->runDSB(c, &sideband);
for (int i = 0; i < n_out; i++) }
{
// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display for (int i = 0; i < n_out; i++)
// smart decimation with bit gain using float arithmetic (23 bits significand) {
// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
m_sum += sideband[i]; // smart decimation with bit gain using float arithmetic (23 bits significand)
if (!(m_undersampleCount++ & (decim - 1))) // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1) m_sum += sideband[i];
{
m_sum /= decim; if (!(m_undersampleCount++ & (decim - 1))) // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
m_magsq = (m_sum.real() * m_sum.real() + m_sum.imag() * m_sum.imag())/ (1<<30); {
m_sum /= decim;
if (m_running.m_ssb & !m_usb) m_magsq = (m_sum.real() * m_sum.real() + m_sum.imag() * m_sum.imag())/ (1<<30);
{ // invert spectrum for LSB
//m_sampleBuffer.push_back(Sample(m_sum.imag() * 32768.0, m_sum.real() * 32768.0)); if (m_running.m_ssb & !m_usb)
m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real())); { // invert spectrum for LSB
} //m_sampleBuffer.push_back(Sample(m_sum.imag() * 32768.0, m_sum.real() * 32768.0));
else m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real()));
{ }
//m_sampleBuffer.push_back(Sample(m_sum.real() * 32768.0, m_sum.imag() * 32768.0)); else
m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag())); {
} //m_sampleBuffer.push_back(Sample(m_sum.real() * 32768.0, m_sum.imag() * 32768.0));
m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag()));
m_sum = 0; }
}
} m_sum = 0;
} }
}; }
}
#endif // INCLUDE_CHANALYZERNG_H };
#endif // INCLUDE_CHANALYZERNG_H

View File

@ -38,8 +38,6 @@
#include "chanalyzerng.h" #include "chanalyzerng.h"
const QString ChannelAnalyzerNGGUI::m_channelID = "sdrangel.channel.chanalyzerng";
ChannelAnalyzerNGGUI* ChannelAnalyzerNGGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet) ChannelAnalyzerNGGUI* ChannelAnalyzerNGGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
{ {
ChannelAnalyzerNGGUI* gui = new ChannelAnalyzerNGGUI(pluginAPI, deviceUISet); ChannelAnalyzerNGGUI* gui = new ChannelAnalyzerNGGUI(pluginAPI, deviceUISet);
@ -407,7 +405,7 @@ ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceUISet *de
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
m_deviceUISet->registerRxChannelInstance(m_channelID, this); m_deviceUISet->registerRxChannelInstance(ChannelAnalyzerNG::m_channelID, this);
m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this); m_deviceUISet->addRollupWidget(this);

View File

@ -55,8 +55,6 @@ public:
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message); virtual bool handleMessage(const Message& message);
static const QString m_channelID;
private slots: private slots:
void viewChanged(); void viewChanged();
// void channelizerInputSampleRateChanged(); // void channelizerInputSampleRateChanged();

View File

@ -19,10 +19,11 @@
#include "plugin/pluginapi.h" #include "plugin/pluginapi.h"
#include "chanalyzerngplugin.h" #include "chanalyzerngplugin.h"
#include "chanalyzernggui.h" #include "chanalyzernggui.h"
#include "chanalyzerng.h"
const PluginDescriptor ChannelAnalyzerNGPlugin::m_pluginDescriptor = { const PluginDescriptor ChannelAnalyzerNGPlugin::m_pluginDescriptor = {
QString("Channel Analyzer NG"), QString("Channel Analyzer NG"),
QString("3.8.0"), QString("3.8.2"),
QString("(c) Edouard Griffiths, F4EXB"), QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"), QString("https://github.com/f4exb/sdrangel"),
true, true,
@ -45,16 +46,28 @@ void ChannelAnalyzerNGPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI = pluginAPI; m_pluginAPI = pluginAPI;
// register demodulator // register demodulator
m_pluginAPI->registerRxChannel(ChannelAnalyzerNGGUI::m_channelID, this); m_pluginAPI->registerRxChannel(ChannelAnalyzerNG::m_channelID, this);
} }
PluginInstanceGUI* ChannelAnalyzerNGPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet) PluginInstanceGUI* ChannelAnalyzerNGPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
{ {
if(channelName == ChannelAnalyzerNGGUI::m_channelID) if(channelName == ChannelAnalyzerNG::m_channelID)
{ {
ChannelAnalyzerNGGUI* gui = ChannelAnalyzerNGGUI::create(m_pluginAPI, deviceUISet); ChannelAnalyzerNGGUI* gui = ChannelAnalyzerNGGUI::create(m_pluginAPI, deviceUISet);
return gui; return gui;
} else { } else {
return NULL; return 0;
} }
} }
BasebandSampleSink* ChannelAnalyzerNGPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{
if(channelName == ChannelAnalyzerNG::m_channelID)
{
ChannelAnalyzerNG* sink = new ChannelAnalyzerNG(deviceAPI);
return sink;
} else {
return 0;
}
}

View File

@ -22,6 +22,7 @@
#include "plugin/plugininterface.h" #include "plugin/plugininterface.h"
class DeviceUISet; class DeviceUISet;
class BasebandSampleSink;
class ChannelAnalyzerNGPlugin : public QObject, PluginInterface { class ChannelAnalyzerNGPlugin : public QObject, PluginInterface {
Q_OBJECT Q_OBJECT
@ -35,6 +36,7 @@ public:
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet); PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -32,6 +32,7 @@
MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message) MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message)
MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureChannelizer, Message)
const QString AMDemod::m_channelID = "de.maintech.sdrangelove.channel.am";
const int AMDemod::m_udpBlockSize = 512; const int AMDemod::m_udpBlockSize = 512;
AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) : AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) :

View File

@ -1,227 +1,229 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Edouard Griffiths, F4EXB. // // Copyright (C) 2015 Edouard Griffiths, F4EXB. //
// // // //
// This program is free software; you can redistribute it and/or modify // // 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 // // it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or // // the Free Software Foundation as version 3 of the License, or //
// // // //
// This program is distributed in the hope that it will be useful, // // This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of // // but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. // // GNU General Public License V3 for more details. //
// // // //
// You should have received a copy of the GNU General Public License // // You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_AMDEMOD_H #ifndef INCLUDE_AMDEMOD_H
#define INCLUDE_AMDEMOD_H #define INCLUDE_AMDEMOD_H
#include <dsp/basebandsamplesink.h> #include <dsp/basebandsamplesink.h>
#include <QMutex> #include <QMutex>
#include <vector> #include <vector>
#include "dsp/nco.h" #include "dsp/nco.h"
#include "dsp/interpolator.h" #include "dsp/interpolator.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "dsp/agc.h" #include "dsp/agc.h"
#include "dsp/bandpass.h" #include "dsp/bandpass.h"
#include "audio/audiofifo.h" #include "audio/audiofifo.h"
#include "util/message.h" #include "util/message.h"
#include "amdemodsettings.h" #include "amdemodsettings.h"
class DeviceSourceAPI; class DeviceSourceAPI;
class DownChannelizer; class DownChannelizer;
class ThreadedBasebandSampleSink; class ThreadedBasebandSampleSink;
class AMDemod : public BasebandSampleSink { class AMDemod : public BasebandSampleSink {
Q_OBJECT Q_OBJECT
public: public:
class MsgConfigureAMDemod : public Message { class MsgConfigureAMDemod : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
const AMDemodSettings& getSettings() const { return m_settings; } const AMDemodSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; } bool getForce() const { return m_force; }
static MsgConfigureAMDemod* create(const AMDemodSettings& settings, bool force) static MsgConfigureAMDemod* create(const AMDemodSettings& settings, bool force)
{ {
return new MsgConfigureAMDemod(settings, force); return new MsgConfigureAMDemod(settings, force);
} }
private: private:
AMDemodSettings m_settings; AMDemodSettings m_settings;
bool m_force; bool m_force;
MsgConfigureAMDemod(const AMDemodSettings& settings, bool force) : MsgConfigureAMDemod(const AMDemodSettings& settings, bool force) :
Message(), Message(),
m_settings(settings), m_settings(settings),
m_force(force) m_force(force)
{ } { }
}; };
class MsgConfigureChannelizer : public Message { class MsgConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getSampleRate() const { return m_sampleRate; } int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; } int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency) static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
{ {
return new MsgConfigureChannelizer(sampleRate, centerFrequency); return new MsgConfigureChannelizer(sampleRate, centerFrequency);
} }
private: private:
int m_sampleRate; int m_sampleRate;
int m_centerFrequency; int m_centerFrequency;
MsgConfigureChannelizer(int sampleRate, int centerFrequency) : MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
Message(), Message(),
m_sampleRate(sampleRate), m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency) m_centerFrequency(centerFrequency)
{ } { }
}; };
AMDemod(DeviceSourceAPI *deviceAPI); AMDemod(DeviceSourceAPI *deviceAPI);
~AMDemod(); ~AMDemod();
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
virtual void start(); virtual void start();
virtual void stop(); virtual void stop();
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
double getMagSq() const { return m_magsq; } double getMagSq() const { return m_magsq; }
bool getSquelchOpen() const { return m_squelchOpen; } bool getSquelchOpen() const { return m_squelchOpen; }
void getMagSqLevels(double& avg, double& peak, int& nbSamples) void getMagSqLevels(double& avg, double& peak, int& nbSamples)
{ {
avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount; avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount;
peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak; peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak;
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount; nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
m_magsqSum = 0.0f; m_magsqSum = 0.0f;
m_magsqPeak = 0.0f; m_magsqPeak = 0.0f;
m_magsqCount = 0; m_magsqCount = 0;
} }
private: static const QString m_channelID;
enum RateState {
RSInitialFill, private:
RSRunning enum RateState {
}; RSInitialFill,
RSRunning
DeviceSourceAPI *m_deviceAPI; };
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer; DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
AMDemodSettings m_settings; DownChannelizer* m_channelizer;
NCO m_nco; AMDemodSettings m_settings;
Interpolator m_interpolator;
Real m_interpolatorDistance; NCO m_nco;
Real m_interpolatorDistanceRemain; Interpolator m_interpolator;
Real m_interpolatorDistance;
Real m_squelchLevel; Real m_interpolatorDistanceRemain;
uint32_t m_squelchCount;
bool m_squelchOpen; Real m_squelchLevel;
double m_magsq; uint32_t m_squelchCount;
double m_magsqSum; bool m_squelchOpen;
double m_magsqPeak; double m_magsq;
int m_magsqCount; double m_magsqSum;
double m_magsqPeak;
MovingAverage<double> m_movingAverage; int m_magsqCount;
SimpleAGC m_volumeAGC;
Bandpass<Real> m_bandpass; MovingAverage<double> m_movingAverage;
SimpleAGC m_volumeAGC;
AudioVector m_audioBuffer; Bandpass<Real> m_bandpass;
uint32_t m_audioBufferFill;
AudioFifo m_audioFifo; AudioVector m_audioBuffer;
UDPSink<qint16> *m_udpBufferAudio; uint32_t m_audioBufferFill;
AudioFifo m_audioFifo;
static const int m_udpBlockSize; UDPSink<qint16> *m_udpBufferAudio;
QMutex m_settingsMutex; static const int m_udpBlockSize;
// void apply(bool force = false); QMutex m_settingsMutex;
void applySettings(const AMDemodSettings& settings, bool force = false);
// void apply(bool force = false);
void processOneSample(Complex &ci) void applySettings(const AMDemodSettings& settings, bool force = false);
{
Real magsq = ci.real() * ci.real() + ci.imag() * ci.imag(); void processOneSample(Complex &ci)
magsq /= (1<<30); {
m_movingAverage.feed(magsq); Real magsq = ci.real() * ci.real() + ci.imag() * ci.imag();
m_magsq = m_movingAverage.average(); magsq /= (1<<30);
m_magsqSum += magsq; m_movingAverage.feed(magsq);
m_magsq = m_movingAverage.average();
if (magsq > m_magsqPeak) m_magsqSum += magsq;
{
m_magsqPeak = magsq; if (magsq > m_magsqPeak)
} {
m_magsqPeak = magsq;
m_magsqCount++; }
if (m_magsq >= m_squelchLevel) m_magsqCount++;
{
if (m_squelchCount <= m_settings.m_audioSampleRate / 10) if (m_magsq >= m_squelchLevel)
{ {
if (m_squelchCount == m_settings.m_audioSampleRate / 20) { if (m_squelchCount <= m_settings.m_audioSampleRate / 10)
m_volumeAGC.fill(1.0); {
} if (m_squelchCount == m_settings.m_audioSampleRate / 20) {
m_volumeAGC.fill(1.0);
m_squelchCount++; }
}
} m_squelchCount++;
else }
{ }
if (m_squelchCount > 1) else
{ {
m_squelchCount -= 2; if (m_squelchCount > 1)
} {
} m_squelchCount -= 2;
}
qint16 sample; }
if ((m_squelchCount >= m_settings.m_audioSampleRate / 20) && !m_settings.m_audioMute) qint16 sample;
{
Real demod = sqrt(magsq); if ((m_squelchCount >= m_settings.m_audioSampleRate / 20) && !m_settings.m_audioMute)
m_volumeAGC.feed(demod); {
demod = (demod - m_volumeAGC.getValue()) / m_volumeAGC.getValue(); Real demod = sqrt(magsq);
m_volumeAGC.feed(demod);
if (m_settings.m_bandpassEnable) demod = (demod - m_volumeAGC.getValue()) / m_volumeAGC.getValue();
{
demod = m_bandpass.filter(demod); if (m_settings.m_bandpassEnable)
demod /= 301.0f; {
} demod = m_bandpass.filter(demod);
demod /= 301.0f;
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); Real attack = (m_squelchCount - 0.05f * m_settings.m_audioSampleRate) / (0.05f * m_settings.m_audioSampleRate);
sample = demod * attack * 2048 * m_settings.m_volume;
m_squelchOpen = true; if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(demod * attack * 32768);
}
else m_squelchOpen = true;
{ }
sample = 0; else
if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(0); {
m_squelchOpen = false; sample = 0;
} if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(0);
m_squelchOpen = false;
m_audioBuffer[m_audioBufferFill].l = sample; }
m_audioBuffer[m_audioBufferFill].r = sample;
++m_audioBufferFill; m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample;
if (m_audioBufferFill >= m_audioBuffer.size()) ++m_audioBufferFill;
{
uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 10); if (m_audioBufferFill >= m_audioBuffer.size())
{
if (res != m_audioBufferFill) uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 10);
{
qDebug("AMDemod::feed: %u/%u audio samples written", res, m_audioBufferFill); if (res != m_audioBufferFill)
} {
qDebug("AMDemod::feed: %u/%u audio samples written", res, m_audioBufferFill);
m_audioBufferFill = 0; }
}
} m_audioBufferFill = 0;
}
}; }
#endif // INCLUDE_AMDEMOD_H };
#endif // INCLUDE_AMDEMOD_H

View File

@ -34,8 +34,6 @@
#include "amdemod.h" #include "amdemod.h"
const QString AMDemodGUI::m_channelID = "de.maintech.sdrangelove.channel.am";
AMDemodGUI* AMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet) AMDemodGUI* AMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
{ {
AMDemodGUI* gui = new AMDemodGUI(pluginAPI, deviceUISet); AMDemodGUI* gui = new AMDemodGUI(pluginAPI, deviceUISet);
@ -206,7 +204,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget*
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
m_deviceUISet->registerRxChannelInstance(m_channelID, this); m_deviceUISet->registerRxChannelInstance(AMDemod::m_channelID, this);
m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this); m_deviceUISet->addRollupWidget(this);

View File

@ -37,8 +37,6 @@ public:
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message); virtual bool handleMessage(const Message& message);
static const QString m_channelID;
private slots: private slots:
void channelMarkerChanged(); void channelMarkerChanged();
void on_deltaFrequency_changed(qint64 value); void on_deltaFrequency_changed(qint64 value);

View File

@ -31,12 +31,12 @@ void AMDemodPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI = pluginAPI; m_pluginAPI = pluginAPI;
// register AM demodulator // register AM demodulator
m_pluginAPI->registerRxChannel(AMDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(AMDemod::m_channelID, this);
} }
PluginInstanceGUI* AMDemodPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet) PluginInstanceGUI* AMDemodPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
{ {
if(channelName == AMDemodGUI::m_channelID) if(channelName == AMDemod::m_channelID)
{ {
AMDemodGUI* gui = AMDemodGUI::create(m_pluginAPI, deviceUISet); AMDemodGUI* gui = AMDemodGUI::create(m_pluginAPI, deviceUISet);
return gui; return gui;
@ -47,7 +47,7 @@ PluginInstanceGUI* AMDemodPlugin::createRxChannelGUI(const QString& channelName,
BasebandSampleSink* AMDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) BasebandSampleSink* AMDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{ {
if(channelName == AMDemodGUI::m_channelID) if(channelName == AMDemod::m_channelID)
{ {
AMDemod* sink = new AMDemod(deviceAPI); AMDemod* sink = new AMDemod(deviceAPI);
return sink; return sink;

View File

@ -35,6 +35,7 @@ MESSAGE_CLASS_DEFINITION(ATVDemod::MsgReportEffectiveSampleRate, Message)
MESSAGE_CLASS_DEFINITION(ATVDemod::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(ATVDemod::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(ATVDemod::MsgReportChannelSampleRateChanged, Message) MESSAGE_CLASS_DEFINITION(ATVDemod::MsgReportChannelSampleRateChanged, Message)
const QString ATVDemod::m_channelID = "sdrangel.channel.demodatv";
const int ATVDemod::m_ssbFftLen = 1024; const int ATVDemod::m_ssbFftLen = 1024;
ATVDemod::ATVDemod(DeviceSourceAPI *deviceAPI) : ATVDemod::ATVDemod(DeviceSourceAPI *deviceAPI) :

View File

@ -227,6 +227,8 @@ public:
double getMagSq() const { return m_objMagSqAverage.average(); } //!< Beware this is scaled to 2^30 double getMagSq() const { return m_objMagSqAverage.average(); } //!< Beware this is scaled to 2^30
bool getBFOLocked(); bool getBFOLocked();
static const QString m_channelID;
private slots: private slots:
void channelSampleRateChanged(); void channelSampleRateChanged();

View File

@ -36,8 +36,6 @@
#include "atvdemod.h" #include "atvdemod.h"
const QString ATVDemodGUI::m_strChannelID = "sdrangel.channel.demodatv";
ATVDemodGUI* ATVDemodGUI::create(PluginAPI* objPluginAPI, ATVDemodGUI* ATVDemodGUI::create(PluginAPI* objPluginAPI,
DeviceUISet *deviceUISet) DeviceUISet *deviceUISet)
{ {
@ -312,7 +310,7 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceUISet *deviceUISet,
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
m_deviceUISet->registerRxChannelInstance(m_strChannelID, this); m_deviceUISet->registerRxChannelInstance(ATVDemod::m_channelID, this);
m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this); m_deviceUISet->addRollupWidget(this);

View File

@ -54,8 +54,6 @@ public:
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& objMessage); virtual bool handleMessage(const Message& objMessage);
static const QString m_strChannelID;
private slots: private slots:
void viewChanged(); void viewChanged();
void handleSourceMessages(); void handleSourceMessages();

View File

@ -21,6 +21,7 @@
#include "plugin/pluginapi.h" #include "plugin/pluginapi.h"
#include "atvdemodgui.h" #include "atvdemodgui.h"
#include "atvdemod.h"
#include "atvdemodplugin.h" #include "atvdemodplugin.h"
const PluginDescriptor ATVDemodPlugin::m_ptrPluginDescriptor = const PluginDescriptor ATVDemodPlugin::m_ptrPluginDescriptor =
@ -50,18 +51,30 @@ void ATVDemodPlugin::initPlugin(PluginAPI* ptrPluginAPI)
m_ptrPluginAPI = ptrPluginAPI; m_ptrPluginAPI = ptrPluginAPI;
// register ATV demodulator // register ATV demodulator
m_ptrPluginAPI->registerRxChannel(ATVDemodGUI::m_strChannelID, this); m_ptrPluginAPI->registerRxChannel(ATVDemod::m_channelID, this);
} }
PluginInstanceGUI* ATVDemodPlugin::createRxChannelGUI(const QString& strChannelName, DeviceUISet *deviceUISet) PluginInstanceGUI* ATVDemodPlugin::createRxChannelGUI(const QString& strChannelName, DeviceUISet *deviceUISet)
{ {
if(strChannelName == ATVDemodGUI::m_strChannelID) if(strChannelName == ATVDemod::m_channelID)
{ {
ATVDemodGUI* ptrGui = ATVDemodGUI::create(m_ptrPluginAPI, deviceUISet); ATVDemodGUI* ptrGui = ATVDemodGUI::create(m_ptrPluginAPI, deviceUISet);
return ptrGui; return ptrGui;
} }
else else
{ {
return NULL; return 0;
} }
} }
BasebandSampleSink* ATVDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{
if(channelName == ATVDemod::m_channelID)
{
ATVDemod* sink = new ATVDemod(deviceAPI);
return sink;
} else {
return 0;
}
}

View File

@ -22,6 +22,7 @@
#include "plugin/plugininterface.h" #include "plugin/plugininterface.h"
class DeviceUISet; class DeviceUISet;
class BasebandSampleSink;
class ATVDemodPlugin : public QObject, PluginInterface class ATVDemodPlugin : public QObject, PluginInterface
{ {
@ -36,6 +37,7 @@ public:
void initPlugin(PluginAPI* ptrPluginAPI); void initPlugin(PluginAPI* ptrPluginAPI);
PluginInstanceGUI* createRxChannelGUI(const QString& strChannelName, DeviceUISet *deviceUISet); PluginInstanceGUI* createRxChannelGUI(const QString& strChannelName, DeviceUISet *deviceUISet);
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_ptrPluginDescriptor; static const PluginDescriptor m_ptrPluginDescriptor;

View File

@ -34,6 +34,7 @@ MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(BFMDemod::MsgReportChannelSampleRateChanged, Message) MESSAGE_CLASS_DEFINITION(BFMDemod::MsgReportChannelSampleRateChanged, Message)
MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureBFMDemod, Message) MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureBFMDemod, Message)
const QString BFMDemod::m_channelID = "sdrangel.channel.bfm";
const Real BFMDemod::default_deemphasis = 50.0; // 50 us const Real BFMDemod::default_deemphasis = 50.0; // 50 us
const int BFMDemod::m_udpBlockSize = 512; const int BFMDemod::m_udpBlockSize = 512;

View File

@ -1,219 +1,221 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 F4EXB // // Copyright (C) 2015 F4EXB //
// written by Edouard Griffiths // // written by Edouard Griffiths //
// // // //
// This program is free software; you can redistribute it and/or modify // // 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 // // it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or // // the Free Software Foundation as version 3 of the License, or //
// // // //
// This program is distributed in the hope that it will be useful, // // This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of // // but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. // // GNU General Public License V3 for more details. //
// // // //
// You should have received a copy of the GNU General Public License // // You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_BFMDEMOD_H #ifndef INCLUDE_BFMDEMOD_H
#define INCLUDE_BFMDEMOD_H #define INCLUDE_BFMDEMOD_H
#include <dsp/basebandsamplesink.h> #include <dsp/basebandsamplesink.h>
#include <QMutex> #include <QMutex>
#include <vector> #include <vector>
#include "dsp/nco.h" #include "dsp/nco.h"
#include "dsp/interpolator.h" #include "dsp/interpolator.h"
#include "dsp/lowpass.h" #include "dsp/lowpass.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "dsp/fftfilt.h" #include "dsp/fftfilt.h"
#include "dsp/phaselock.h" #include "dsp/phaselock.h"
#include "dsp/filterrc.h" #include "dsp/filterrc.h"
#include "dsp/phasediscri.h" #include "dsp/phasediscri.h"
#include "audio/audiofifo.h" #include "audio/audiofifo.h"
#include "util/message.h" #include "util/message.h"
#include "util/udpsink.h" #include "util/udpsink.h"
#include "rdsparser.h" #include "rdsparser.h"
#include "rdsdecoder.h" #include "rdsdecoder.h"
#include "rdsdemod.h" #include "rdsdemod.h"
#include "bfmdemodsettings.h" #include "bfmdemodsettings.h"
class DeviceSourceAPI; class DeviceSourceAPI;
class ThreadedBasebandSampleSink; class ThreadedBasebandSampleSink;
class DownChannelizer; class DownChannelizer;
class BFMDemod : public BasebandSampleSink { class BFMDemod : public BasebandSampleSink {
public: public:
class MsgConfigureBFMDemod : public Message { class MsgConfigureBFMDemod : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
const BFMDemodSettings& getSettings() const { return m_settings; } const BFMDemodSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; } bool getForce() const { return m_force; }
static MsgConfigureBFMDemod* create(const BFMDemodSettings& settings, bool force) static MsgConfigureBFMDemod* create(const BFMDemodSettings& settings, bool force)
{ {
return new MsgConfigureBFMDemod(settings, force); return new MsgConfigureBFMDemod(settings, force);
} }
private: private:
BFMDemodSettings m_settings; BFMDemodSettings m_settings;
bool m_force; bool m_force;
MsgConfigureBFMDemod(const BFMDemodSettings& settings, bool force) : MsgConfigureBFMDemod(const BFMDemodSettings& settings, bool force) :
Message(), Message(),
m_settings(settings), m_settings(settings),
m_force(force) m_force(force)
{ } { }
}; };
class MsgConfigureChannelizer : public Message { class MsgConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getSampleRate() const { return m_sampleRate; } int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; } int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency) static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
{ {
return new MsgConfigureChannelizer(sampleRate, centerFrequency); return new MsgConfigureChannelizer(sampleRate, centerFrequency);
} }
private: private:
int m_sampleRate; int m_sampleRate;
int m_centerFrequency; int m_centerFrequency;
MsgConfigureChannelizer(int sampleRate, int centerFrequency) : MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
Message(), Message(),
m_sampleRate(sampleRate), m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency) m_centerFrequency(centerFrequency)
{ } { }
}; };
class MsgReportChannelSampleRateChanged : public Message { class MsgReportChannelSampleRateChanged : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getSampleRate() const { return m_sampleRate; } int getSampleRate() const { return m_sampleRate; }
static MsgReportChannelSampleRateChanged* create(int sampleRate) static MsgReportChannelSampleRateChanged* create(int sampleRate)
{ {
return new MsgReportChannelSampleRateChanged(sampleRate); return new MsgReportChannelSampleRateChanged(sampleRate);
} }
private: private:
int m_sampleRate; int m_sampleRate;
MsgReportChannelSampleRateChanged(int sampleRate) : MsgReportChannelSampleRateChanged(int sampleRate) :
Message(), Message(),
m_sampleRate(sampleRate) m_sampleRate(sampleRate)
{ } { }
}; };
BFMDemod(DeviceSourceAPI *deviceAPI); BFMDemod(DeviceSourceAPI *deviceAPI);
virtual ~BFMDemod(); virtual ~BFMDemod();
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
int getSampleRate() const { return m_settings.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 feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
virtual void start(); virtual void start();
virtual void stop(); virtual void stop();
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
double getMagSq() const { return m_magsq; } double getMagSq() const { return m_magsq; }
bool getPilotLock() const { return m_pilotPLL.locked(); } bool getPilotLock() const { return m_pilotPLL.locked(); }
Real getPilotLevel() const { return m_pilotPLL.get_pilot_level(); } Real getPilotLevel() const { return m_pilotPLL.get_pilot_level(); }
Real getDecoderQua() const { return m_rdsDecoder.m_qua; } Real getDecoderQua() const { return m_rdsDecoder.m_qua; }
bool getDecoderSynced() const { return m_rdsDecoder.synced(); } bool getDecoderSynced() const { return m_rdsDecoder.synced(); }
Real getDemodAcc() const { return m_rdsDemod.m_report.acc; } Real getDemodAcc() const { return m_rdsDemod.m_report.acc; }
Real getDemodQua() const { return m_rdsDemod.m_report.qua; } Real getDemodQua() const { return m_rdsDemod.m_report.qua; }
Real getDemodFclk() const { return m_rdsDemod.m_report.fclk; } Real getDemodFclk() const { return m_rdsDemod.m_report.fclk; }
void getMagSqLevels(double& avg, double& peak, int& nbSamples) void getMagSqLevels(double& avg, double& peak, int& nbSamples)
{ {
avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount; avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount;
m_magsq = avg; m_magsq = avg;
peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak; peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak;
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount; nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
m_magsqSum = 0.0f; m_magsqSum = 0.0f;
m_magsqPeak = 0.0f; m_magsqPeak = 0.0f;
m_magsqCount = 0; m_magsqCount = 0;
} }
RDSParser& getRDSParser() { return m_rdsParser; } RDSParser& getRDSParser() { return m_rdsParser; }
private slots: static const QString m_channelID;
void channelSampleRateChanged();
private slots:
private: void channelSampleRateChanged();
enum RateState {
RSInitialFill, private:
RSRunning enum RateState {
}; RSInitialFill,
RSRunning
DeviceSourceAPI *m_deviceAPI; };
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer; DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
BFMDemodSettings m_settings; DownChannelizer* m_channelizer;
NCO m_nco; BFMDemodSettings m_settings;
Interpolator m_interpolator; //!< Interpolator between fixed demod bandwidth and audio bandwidth (rational)
Real m_interpolatorDistance; NCO m_nco;
Real m_interpolatorDistanceRemain; Interpolator m_interpolator; //!< Interpolator between fixed demod bandwidth and audio bandwidth (rational)
Real m_interpolatorDistance;
Interpolator m_interpolatorStereo; //!< Twin Interpolator for stereo subcarrier Real m_interpolatorDistanceRemain;
Real m_interpolatorStereoDistance;
Real m_interpolatorStereoDistanceRemain; Interpolator m_interpolatorStereo; //!< Twin Interpolator for stereo subcarrier
Real m_interpolatorStereoDistance;
Interpolator m_interpolatorRDS; //!< Twin Interpolator for stereo subcarrier Real m_interpolatorStereoDistanceRemain;
Real m_interpolatorRDSDistance;
Real m_interpolatorRDSDistanceRemain; Interpolator m_interpolatorRDS; //!< Twin Interpolator for stereo subcarrier
Real m_interpolatorRDSDistance;
Lowpass<Real> m_lowpass; Real m_interpolatorRDSDistanceRemain;
fftfilt* m_rfFilter;
static const int filtFftLen = 1024; Lowpass<Real> m_lowpass;
fftfilt* m_rfFilter;
Real m_squelchLevel; static const int filtFftLen = 1024;
int m_squelchState;
Real m_squelchLevel;
Real m_m1Arg; //!> x^-1 real sample int m_squelchState;
double m_magsq; Real m_m1Arg; //!> x^-1 real sample
double m_magsqSum;
double m_magsqPeak; double m_magsq;
int m_magsqCount; double m_magsqSum;
double m_magsqPeak;
AudioVector m_audioBuffer; int m_magsqCount;
uint m_audioBufferFill;
AudioVector m_audioBuffer;
BasebandSampleSink* m_sampleSink; uint m_audioBufferFill;
AudioFifo m_audioFifo;
SampleVector m_sampleBuffer; BasebandSampleSink* m_sampleSink;
QMutex m_settingsMutex; AudioFifo m_audioFifo;
SampleVector m_sampleBuffer;
RDSPhaseLock m_pilotPLL; QMutex m_settingsMutex;
Real m_pilotPLLSamples[4];
RDSPhaseLock m_pilotPLL;
RDSDemod m_rdsDemod; Real m_pilotPLLSamples[4];
RDSDecoder m_rdsDecoder;
RDSParser m_rdsParser; RDSDemod m_rdsDemod;
RDSDecoder m_rdsDecoder;
LowPassFilterRC m_deemphasisFilterX; RDSParser m_rdsParser;
LowPassFilterRC m_deemphasisFilterY;
static const Real default_deemphasis; LowPassFilterRC m_deemphasisFilterX;
LowPassFilterRC m_deemphasisFilterY;
Real m_fmExcursion; static const Real default_deemphasis;
static const int default_excursion = 750000; // +/- 75 kHz
Real m_fmExcursion;
PhaseDiscriminators m_phaseDiscri; static const int default_excursion = 750000; // +/- 75 kHz
UDPSink<AudioSample> *m_udpBufferAudio;
PhaseDiscriminators m_phaseDiscri;
static const int m_udpBlockSize; UDPSink<AudioSample> *m_udpBufferAudio;
void applySettings(const BFMDemodSettings& settings, bool force = false); static const int m_udpBlockSize;
};
void applySettings(const BFMDemodSettings& settings, bool force = false);
#endif // INCLUDE_BFMDEMOD_H };
#endif // INCLUDE_BFMDEMOD_H

View File

@ -43,8 +43,6 @@
#include "rdstmc.h" #include "rdstmc.h"
#include "ui_bfmdemodgui.h" #include "ui_bfmdemodgui.h"
const QString BFMDemodGUI::m_channelID = "sdrangel.channel.bfm";
BFMDemodGUI* BFMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUIset) BFMDemodGUI* BFMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUIset)
{ {
BFMDemodGUI* gui = new BFMDemodGUI(pluginAPI, deviceUIset); BFMDemodGUI* gui = new BFMDemodGUI(pluginAPI, deviceUIset);
@ -364,7 +362,7 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
m_deviceUISet->registerRxChannelInstance(m_channelID, this); m_deviceUISet->registerRxChannelInstance(BFMDemod::m_channelID, this);
m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this); m_deviceUISet->addRollupWidget(this);

View File

@ -56,8 +56,6 @@ public:
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message); virtual bool handleMessage(const Message& message);
static const QString m_channelID;
private slots: private slots:
void on_deltaFrequency_changed(qint64 value); void on_deltaFrequency_changed(qint64 value);
void on_rfBW_valueChanged(int value); void on_rfBW_valueChanged(int value);

View File

@ -21,6 +21,7 @@
#include "plugin/pluginapi.h" #include "plugin/pluginapi.h"
#include "bfmdemodgui.h" #include "bfmdemodgui.h"
#include "bfmdemod.h"
const PluginDescriptor BFMPlugin::m_pluginDescriptor = { const PluginDescriptor BFMPlugin::m_pluginDescriptor = {
QString("Broadcast FM Demodulator"), QString("Broadcast FM Demodulator"),
@ -47,12 +48,12 @@ void BFMPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI = pluginAPI; m_pluginAPI = pluginAPI;
// register BFM demodulator // register BFM demodulator
m_pluginAPI->registerRxChannel(BFMDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(BFMDemod::m_channelID, this);
} }
PluginInstanceGUI* BFMPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet) PluginInstanceGUI* BFMPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
{ {
if(channelName == BFMDemodGUI::m_channelID) if(channelName == BFMDemod::m_channelID)
{ {
BFMDemodGUI* gui = BFMDemodGUI::create(m_pluginAPI, deviceUISet); BFMDemodGUI* gui = BFMDemodGUI::create(m_pluginAPI, deviceUISet);
return gui; return gui;
@ -60,3 +61,15 @@ PluginInstanceGUI* BFMPlugin::createRxChannelGUI(const QString& channelName, Dev
return 0; return 0;
} }
} }
BasebandSampleSink* BFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{
if(channelName == BFMDemod::m_channelID)
{
BFMDemod* sink = new BFMDemod(deviceAPI);
return sink;
} else {
return 0;
}
}

View File

@ -35,6 +35,7 @@ public:
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet); PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -35,6 +35,7 @@ MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemod, Message) MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemod, Message)
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureMyPosition, Message) MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureMyPosition, Message)
const QString DSDDemod::m_channelID = "sdrangel.channel.dsddemod";
const int DSDDemod::m_udpBlockSize = 512; const int DSDDemod::m_udpBlockSize = 512;
DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) : DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) :

View File

@ -1,194 +1,195 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 F4EXB // // Copyright (C) 2016 F4EXB //
// written by Edouard Griffiths // // written by Edouard Griffiths //
// // // //
// This program is free software; you can redistribute it and/or modify // // 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 // // it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or // // the Free Software Foundation as version 3 of the License, or //
// // // //
// This program is distributed in the hope that it will be useful, // // This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of // // but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. // // GNU General Public License V3 for more details. //
// // // //
// You should have received a copy of the GNU General Public License // // You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_DSDDEMOD_H #ifndef INCLUDE_DSDDEMOD_H
#define INCLUDE_DSDDEMOD_H #define INCLUDE_DSDDEMOD_H
#include <dsp/basebandsamplesink.h> #include <dsp/basebandsamplesink.h>
#include <dsp/phasediscri.h> #include <dsp/phasediscri.h>
#include <QMutex> #include <QMutex>
#include <vector> #include <vector>
#include "dsp/nco.h" #include "dsp/nco.h"
#include "dsp/interpolator.h" #include "dsp/interpolator.h"
#include "dsp/lowpass.h" #include "dsp/lowpass.h"
#include "dsp/bandpass.h" #include "dsp/bandpass.h"
#include "dsp/afsquelch.h" #include "dsp/afsquelch.h"
#include "dsp/movingaverage.h" #include "dsp/movingaverage.h"
#include "dsp/afsquelch.h" #include "dsp/afsquelch.h"
#include "audio/audiofifo.h" #include "audio/audiofifo.h"
#include "util/message.h" #include "util/message.h"
#include "util/udpsink.h" #include "util/udpsink.h"
#include "dsddemodsettings.h" #include "dsddemodsettings.h"
#include "dsddecoder.h" #include "dsddecoder.h"
class DeviceSourceAPI; class DeviceSourceAPI;
class ThreadedBasebandSampleSink; class ThreadedBasebandSampleSink;
class DownChannelizer; class DownChannelizer;
class DSDDemod : public BasebandSampleSink { class DSDDemod : public BasebandSampleSink {
public: public:
class MsgConfigureDSDDemod : public Message { class MsgConfigureDSDDemod : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
const DSDDemodSettings& getSettings() const { return m_settings; } const DSDDemodSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; } bool getForce() const { return m_force; }
static MsgConfigureDSDDemod* create(const DSDDemodSettings& settings, bool force) static MsgConfigureDSDDemod* create(const DSDDemodSettings& settings, bool force)
{ {
return new MsgConfigureDSDDemod(settings, force); return new MsgConfigureDSDDemod(settings, force);
} }
private: private:
DSDDemodSettings m_settings; DSDDemodSettings m_settings;
bool m_force; bool m_force;
MsgConfigureDSDDemod(const DSDDemodSettings& settings, bool force) : MsgConfigureDSDDemod(const DSDDemodSettings& settings, bool force) :
Message(), Message(),
m_settings(settings), m_settings(settings),
m_force(force) m_force(force)
{ } { }
}; };
class MsgConfigureChannelizer : public Message { class MsgConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getSampleRate() const { return m_sampleRate; } int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; } int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency) static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
{ {
return new MsgConfigureChannelizer(sampleRate, centerFrequency); return new MsgConfigureChannelizer(sampleRate, centerFrequency);
} }
private: private:
int m_sampleRate; int m_sampleRate;
int m_centerFrequency; int m_centerFrequency;
MsgConfigureChannelizer(int sampleRate, int centerFrequency) : MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
Message(), Message(),
m_sampleRate(sampleRate), m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency) m_centerFrequency(centerFrequency)
{ } { }
}; };
DSDDemod(DeviceSourceAPI *deviceAPI); DSDDemod(DeviceSourceAPI *deviceAPI);
~DSDDemod(); ~DSDDemod();
void setScopeSink(BasebandSampleSink* sampleSink) { m_scope = sampleSink; } void setScopeSink(BasebandSampleSink* sampleSink) { m_scope = sampleSink; }
void configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude); void configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude);
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
virtual void start(); virtual void start();
virtual void stop(); virtual void stop();
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
double getMagSq() { return m_magsq; } double getMagSq() { return m_magsq; }
bool getSquelchOpen() const { return m_squelchOpen; } bool getSquelchOpen() const { return m_squelchOpen; }
const DSDDecoder& getDecoder() const { return m_dsdDecoder; } const DSDDecoder& getDecoder() const { return m_dsdDecoder; }
void getMagSqLevels(double& avg, double& peak, int& nbSamples) void getMagSqLevels(double& avg, double& peak, int& nbSamples)
{ {
avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount; avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount;
m_magsq = avg; m_magsq = avg;
peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak; peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak;
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount; nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
m_magsqSum = 0.0f; m_magsqSum = 0.0f;
m_magsqPeak = 0.0f; m_magsqPeak = 0.0f;
m_magsqCount = 0; m_magsqCount = 0;
} }
static const QString m_channelID;
private:
class MsgConfigureMyPosition : public Message { private:
MESSAGE_CLASS_DECLARATION class MsgConfigureMyPosition : public Message {
MESSAGE_CLASS_DECLARATION
public:
float getMyLatitude() const { return m_myLatitude; } public:
float getMyLongitude() const { return m_myLongitude; } float getMyLatitude() const { return m_myLatitude; }
float getMyLongitude() const { return m_myLongitude; }
static MsgConfigureMyPosition* create(float myLatitude, float myLongitude)
{ static MsgConfigureMyPosition* create(float myLatitude, float myLongitude)
return new MsgConfigureMyPosition(myLatitude, myLongitude); {
} return new MsgConfigureMyPosition(myLatitude, myLongitude);
}
private:
float m_myLatitude; private:
float m_myLongitude; float m_myLatitude;
float m_myLongitude;
MsgConfigureMyPosition(float myLatitude, float myLongitude) :
m_myLatitude(myLatitude), MsgConfigureMyPosition(float myLatitude, float myLongitude) :
m_myLongitude(myLongitude) m_myLatitude(myLatitude),
{} m_myLongitude(myLongitude)
}; {}
};
enum RateState {
RSInitialFill, enum RateState {
RSRunning RSInitialFill,
}; RSRunning
};
DSDDemodSettings m_settings;
DSDDemodSettings m_settings;
DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer; DeviceSourceAPI *m_deviceAPI;
DownChannelizer* m_channelizer; ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
NCO m_nco;
Interpolator m_interpolator; NCO m_nco;
Real m_interpolatorDistance; Interpolator m_interpolator;
Real m_interpolatorDistanceRemain; Real m_interpolatorDistance;
int m_sampleCount; Real m_interpolatorDistanceRemain;
int m_squelchCount; int m_sampleCount;
int m_squelchGate; int m_squelchCount;
int m_squelchGate;
double m_squelchLevel;
bool m_squelchOpen; double m_squelchLevel;
bool m_squelchOpen;
MovingAverage<double> m_movingAverage;
double m_magsq; MovingAverage<double> m_movingAverage;
double m_magsqSum; double m_magsq;
double m_magsqPeak; double m_magsqSum;
int m_magsqCount; double m_magsqPeak;
int m_magsqCount;
Real m_fmExcursion;
Real m_fmExcursion;
SampleVector m_scopeSampleBuffer;
AudioVector m_audioBuffer; SampleVector m_scopeSampleBuffer;
uint m_audioBufferFill; AudioVector m_audioBuffer;
qint16 *m_sampleBuffer; //!< samples ring buffer uint m_audioBufferFill;
int m_sampleBufferIndex; qint16 *m_sampleBuffer; //!< samples ring buffer
int m_sampleBufferIndex;
AudioFifo m_audioFifo1;
AudioFifo m_audioFifo2; AudioFifo m_audioFifo1;
BasebandSampleSink* m_scope; AudioFifo m_audioFifo2;
bool m_scopeEnabled; BasebandSampleSink* m_scope;
bool m_scopeEnabled;
DSDDecoder m_dsdDecoder;
QMutex m_settingsMutex; DSDDecoder m_dsdDecoder;
QMutex m_settingsMutex;
PhaseDiscriminators m_phaseDiscri;
UDPSink<AudioSample> *m_udpBufferAudio; PhaseDiscriminators m_phaseDiscri;
UDPSink<AudioSample> *m_udpBufferAudio;
static const int m_udpBlockSize;
static const int m_udpBlockSize;
void applySettings(DSDDemodSettings& settings, bool force = false);
}; void applySettings(DSDDemodSettings& settings, bool force = false);
};
#endif // INCLUDE_DSDDEMOD_H
#endif // INCLUDE_DSDDEMOD_H

View File

@ -38,8 +38,6 @@
#include "dsddemodbaudrates.h" #include "dsddemodbaudrates.h"
#include "dsddemod.h" #include "dsddemod.h"
const QString DSDDemodGUI::m_channelID = "sdrangel.channel.dsddemod";
DSDDemodGUI* DSDDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet) DSDDemodGUI* DSDDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
{ {
DSDDemodGUI* gui = new DSDDemodGUI(pluginAPI, deviceUISet); DSDDemodGUI* gui = new DSDDemodGUI(pluginAPI, deviceUISet);
@ -281,7 +279,7 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
m_deviceUISet->registerRxChannelInstance(m_channelID, this); m_deviceUISet->registerRxChannelInstance(DSDDemod::m_channelID, this);
m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this); m_deviceUISet->addRollupWidget(this);

View File

@ -57,8 +57,6 @@ public:
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message); virtual bool handleMessage(const Message& message);
static const QString m_channelID;
private slots: private slots:
void formatStatusText(); void formatStatusText();
void channelMarkerChanged(); void channelMarkerChanged();

View File

@ -21,6 +21,7 @@
#include <QtPlugin> #include <QtPlugin>
#include "plugin/pluginapi.h" #include "plugin/pluginapi.h"
#include "dsddemodgui.h" #include "dsddemodgui.h"
#include "dsddemod.h"
const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = { const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = {
QString("DSD Demodulator"), QString("DSD Demodulator"),
@ -47,16 +48,27 @@ void DSDDemodPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI = pluginAPI; m_pluginAPI = pluginAPI;
// register DSD demodulator // register DSD demodulator
m_pluginAPI->registerRxChannel(DSDDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(DSDDemod::m_channelID, this);
} }
PluginInstanceGUI* DSDDemodPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet) PluginInstanceGUI* DSDDemodPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
{ {
if(channelName == DSDDemodGUI::m_channelID) if(channelName == DSDDemod::m_channelID)
{ {
DSDDemodGUI* gui = DSDDemodGUI::create(m_pluginAPI, deviceUISet); DSDDemodGUI* gui = DSDDemodGUI::create(m_pluginAPI, deviceUISet);
return gui; return gui;
} else { } else {
return NULL; return 0;
} }
} }
BasebandSampleSink* DSDDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{
if(channelName == DSDDemod::m_channelID)
{
DSDDemod* sink = new DSDDemod(deviceAPI);
return sink;
} else {
return 0;
}
}

View File

@ -22,6 +22,7 @@
#include "plugin/plugininterface.h" #include "plugin/plugininterface.h"
class DeviceUISet; class DeviceUISet;
class BasebandSampleSink;
class DSDDemodPlugin : public QObject, PluginInterface { class DSDDemodPlugin : public QObject, PluginInterface {
Q_OBJECT Q_OBJECT
@ -35,6 +36,7 @@ public:
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet); PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -31,6 +31,8 @@
MESSAGE_CLASS_DEFINITION(LoRaDemod::MsgConfigureLoRaDemod, Message) MESSAGE_CLASS_DEFINITION(LoRaDemod::MsgConfigureLoRaDemod, Message)
MESSAGE_CLASS_DEFINITION(LoRaDemod::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(LoRaDemod::MsgConfigureChannelizer, Message)
const QString LoRaDemod::m_channelID = "de.maintech.sdrangelove.channel.lora";
LoRaDemod::LoRaDemod(DeviceSourceAPI* deviceAPI) : LoRaDemod::LoRaDemod(DeviceSourceAPI* deviceAPI) :
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
m_sampleSink(0), m_sampleSink(0),

View File

@ -96,6 +96,8 @@ public:
virtual void stop(); virtual void stop();
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
static const QString m_channelID;
private: private:
int detect(Complex sample, Complex angle); int detect(Complex sample, Complex angle);
void dumpRaw(void); void dumpRaw(void);

View File

@ -16,8 +16,6 @@
#include "lorademod.h" #include "lorademod.h"
#include "lorademodgui.h" #include "lorademodgui.h"
const QString LoRaDemodGUI::m_channelID = "de.maintech.sdrangelove.channel.lora";
LoRaDemodGUI* LoRaDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet) LoRaDemodGUI* LoRaDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
{ {
LoRaDemodGUI* gui = new LoRaDemodGUI(pluginAPI, deviceUISet); LoRaDemodGUI* gui = new LoRaDemodGUI(pluginAPI, deviceUISet);
@ -153,7 +151,7 @@ LoRaDemodGUI::LoRaDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidg
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
m_deviceUISet->registerRxChannelInstance(m_channelID, this); m_deviceUISet->registerRxChannelInstance(LoRaDemod::m_channelID, this);
m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this); m_deviceUISet->addRollupWidget(this);

View File

@ -35,8 +35,6 @@ public:
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message); virtual bool handleMessage(const Message& message);
static const QString m_channelID;
private slots: private slots:
void viewChanged(); void viewChanged();
void on_BW_valueChanged(int value); void on_BW_valueChanged(int value);

View File

@ -3,6 +3,7 @@
#include "loraplugin.h" #include "loraplugin.h"
#include "lorademodgui.h" #include "lorademodgui.h"
#include "lorademod.h"
const PluginDescriptor LoRaPlugin::m_pluginDescriptor = { const PluginDescriptor LoRaPlugin::m_pluginDescriptor = {
QString("LoRa Demodulator"), QString("LoRa Demodulator"),
@ -29,16 +30,27 @@ void LoRaPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI = pluginAPI; m_pluginAPI = pluginAPI;
// register demodulator // register demodulator
m_pluginAPI->registerRxChannel(LoRaDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(LoRaDemod::m_channelID, this);
} }
PluginInstanceGUI* LoRaPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet) PluginInstanceGUI* LoRaPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
{ {
if(channelName == LoRaDemodGUI::m_channelID) if(channelName == LoRaDemod::m_channelID)
{ {
LoRaDemodGUI* gui = LoRaDemodGUI::create(m_pluginAPI, deviceUISet); LoRaDemodGUI* gui = LoRaDemodGUI::create(m_pluginAPI, deviceUISet);
return gui; return gui;
} else { } else {
return NULL; return 0;
} }
} }
BasebandSampleSink* LoRaPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{
if(channelName == LoRaDemod::m_channelID)
{
LoRaDemod* sink = new LoRaDemod(deviceAPI);
return sink;
} else {
return 0;
}
}

View File

@ -5,6 +5,7 @@
#include "plugin/plugininterface.h" #include "plugin/plugininterface.h"
class DeviceUISet; class DeviceUISet;
class BasebandSampleSink;
class LoRaPlugin : public QObject, PluginInterface { class LoRaPlugin : public QObject, PluginInterface {
Q_OBJECT Q_OBJECT
@ -18,6 +19,7 @@ public:
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet); PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -35,6 +35,8 @@ MESSAGE_CLASS_DEFINITION(NFMDemod::MsgConfigureNFMDemod, Message)
MESSAGE_CLASS_DEFINITION(NFMDemod::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(NFMDemod::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(NFMDemod::MsgReportCTCSSFreq, Message) MESSAGE_CLASS_DEFINITION(NFMDemod::MsgReportCTCSSFreq, Message)
const QString NFMDemod::m_channelID = "de.maintech.sdrangelove.channel.nfm";
static const double afSqTones[2] = {1000.0, 6000.0}; // {1200.0, 8000.0}; static const double afSqTones[2] = {1000.0, 6000.0}; // {1200.0, 8000.0};
const int NFMDemod::m_udpBlockSize = 512; const int NFMDemod::m_udpBlockSize = 512;

View File

@ -138,6 +138,8 @@ public:
m_magsqCount = 0; m_magsqCount = 0;
} }
static const QString m_channelID;
private: private:
enum RateState { enum RateState {
RSInitialFill, RSInitialFill,

View File

@ -16,8 +16,6 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "nfmdemod.h" #include "nfmdemod.h"
const QString NFMDemodGUI::m_channelID = "de.maintech.sdrangelove.channel.nfm";
NFMDemodGUI* NFMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet) NFMDemodGUI* NFMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
{ {
NFMDemodGUI* gui = new NFMDemodGUI(pluginAPI, deviceUISet); NFMDemodGUI* gui = new NFMDemodGUI(pluginAPI, deviceUISet);
@ -277,7 +275,7 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
m_deviceUISet->registerRxChannelInstance(m_channelID, this); m_deviceUISet->registerRxChannelInstance(NFMDemod::m_channelID, this);
m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this); m_deviceUISet->addRollupWidget(this);

View File

@ -38,8 +38,6 @@ public:
virtual bool handleMessage(const Message& message); virtual bool handleMessage(const Message& message);
void setCtcssFreq(Real ctcssFreq); void setCtcssFreq(Real ctcssFreq);
static const QString m_channelID;
private slots: private slots:
void channelMarkerChanged(); void channelMarkerChanged();
void on_deltaFrequency_changed(qint64 value); void on_deltaFrequency_changed(qint64 value);

View File

@ -3,6 +3,7 @@
#include "nfmplugin.h" #include "nfmplugin.h"
#include "nfmdemodgui.h" #include "nfmdemodgui.h"
#include "nfmdemod.h"
const PluginDescriptor NFMPlugin::m_pluginDescriptor = { const PluginDescriptor NFMPlugin::m_pluginDescriptor = {
QString("NFM Demodulator"), QString("NFM Demodulator"),
@ -29,15 +30,26 @@ void NFMPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI = pluginAPI; m_pluginAPI = pluginAPI;
// register NFM demodulator // register NFM demodulator
m_pluginAPI->registerRxChannel(NFMDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(NFMDemod::m_channelID, this);
} }
PluginInstanceGUI* NFMPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet) PluginInstanceGUI* NFMPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
{ {
if(channelName == NFMDemodGUI::m_channelID) { if(channelName == NFMDemod::m_channelID) {
NFMDemodGUI* gui = NFMDemodGUI::create(m_pluginAPI, deviceUISet); NFMDemodGUI* gui = NFMDemodGUI::create(m_pluginAPI, deviceUISet);
return gui; return gui;
} else { } else {
return NULL; return 0;
} }
} }
BasebandSampleSink* NFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{
if(channelName == NFMDemod::m_channelID)
{
NFMDemod* sink = new NFMDemod(deviceAPI);
return sink;
} else {
return 0;
}
}

View File

@ -5,6 +5,7 @@
#include "plugin/plugininterface.h" #include "plugin/plugininterface.h"
class DeviceUISet; class DeviceUISet;
class BasebandSampleSink;
class NFMPlugin : public QObject, PluginInterface { class NFMPlugin : public QObject, PluginInterface {
Q_OBJECT Q_OBJECT
@ -18,6 +19,7 @@ public:
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet); PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -34,6 +34,8 @@ MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemod, Message)
MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemodPrivate, Message) MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemodPrivate, Message)
MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureChannelizer, Message)
const QString SSBDemod::m_channelID = "de.maintech.sdrangelove.channel.ssb";
SSBDemod::SSBDemod(DeviceSourceAPI *deviceAPI) : SSBDemod::SSBDemod(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
m_audioBinaual(false), m_audioBinaual(false),

View File

@ -1,270 +1,272 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel // // written by Christian Daniel //
// // // //
// This program is free software; you can redistribute it and/or modify // // 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 // // it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or // // the Free Software Foundation as version 3 of the License, or //
// // // //
// This program is distributed in the hope that it will be useful, // // This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of // // but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. // // GNU General Public License V3 for more details. //
// // // //
// You should have received a copy of the GNU General Public License // // You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_SSBDEMOD_H #ifndef INCLUDE_SSBDEMOD_H
#define INCLUDE_SSBDEMOD_H #define INCLUDE_SSBDEMOD_H
#include <QMutex> #include <QMutex>
#include <vector> #include <vector>
#include <dsp/basebandsamplesink.h> #include <dsp/basebandsamplesink.h>
#include "dsp/ncof.h" #include "dsp/ncof.h"
#include "dsp/interpolator.h" #include "dsp/interpolator.h"
#include "dsp/fftfilt.h" #include "dsp/fftfilt.h"
#include "dsp/agc.h" #include "dsp/agc.h"
#include "audio/audiofifo.h" #include "audio/audiofifo.h"
#include "util/message.h" #include "util/message.h"
#include "ssbdemodsettings.h" #include "ssbdemodsettings.h"
#define ssbFftLen 1024 #define ssbFftLen 1024
#define agcTarget 3276.8 // -10 dB amplitude => -20 dB power: center of normal signal #define agcTarget 3276.8 // -10 dB amplitude => -20 dB power: center of normal signal
class DeviceSourceAPI; class DeviceSourceAPI;
class ThreadedBasebandSampleSink; class ThreadedBasebandSampleSink;
class DownChannelizer; class DownChannelizer;
class SSBDemod : public BasebandSampleSink { class SSBDemod : public BasebandSampleSink {
public: public:
class MsgConfigureSSBDemod : public Message { class MsgConfigureSSBDemod : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
const SSBDemodSettings& getSettings() const { return m_settings; } const SSBDemodSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; } bool getForce() const { return m_force; }
static MsgConfigureSSBDemod* create(const SSBDemodSettings& settings, bool force) static MsgConfigureSSBDemod* create(const SSBDemodSettings& settings, bool force)
{ {
return new MsgConfigureSSBDemod(settings, force); return new MsgConfigureSSBDemod(settings, force);
} }
private: private:
SSBDemodSettings m_settings; SSBDemodSettings m_settings;
bool m_force; bool m_force;
MsgConfigureSSBDemod(const SSBDemodSettings& settings, bool force) : MsgConfigureSSBDemod(const SSBDemodSettings& settings, bool force) :
Message(), Message(),
m_settings(settings), m_settings(settings),
m_force(force) m_force(force)
{ } { }
}; };
class MsgConfigureChannelizer : public Message { class MsgConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getSampleRate() const { return m_sampleRate; } int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; } int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency) static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
{ {
return new MsgConfigureChannelizer(sampleRate, centerFrequency); return new MsgConfigureChannelizer(sampleRate, centerFrequency);
} }
private: private:
int m_sampleRate; int m_sampleRate;
int m_centerFrequency; int m_centerFrequency;
MsgConfigureChannelizer(int sampleRate, int centerFrequency) : MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
Message(), Message(),
m_sampleRate(sampleRate), m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency) m_centerFrequency(centerFrequency)
{ } { }
}; };
SSBDemod(DeviceSourceAPI *deviceAPI); SSBDemod(DeviceSourceAPI *deviceAPI);
virtual ~SSBDemod(); virtual ~SSBDemod();
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
void configure(MessageQueue* messageQueue, void configure(MessageQueue* messageQueue,
Real Bandwidth, Real Bandwidth,
Real LowCutoff, Real LowCutoff,
Real volume, Real volume,
int spanLog2, int spanLog2,
bool audioBinaural, bool audioBinaural,
bool audioFlipChannels, bool audioFlipChannels,
bool dsb, bool dsb,
bool audioMute, bool audioMute,
bool agc, bool agc,
bool agcClamping, bool agcClamping,
int agcTimeLog2, int agcTimeLog2,
int agcPowerThreshold, int agcPowerThreshold,
int agcThresholdGate); int agcThresholdGate);
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
virtual void start(); virtual void start();
virtual void stop(); virtual void stop();
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
double getMagSq() const { return m_magsq; } double getMagSq() const { return m_magsq; }
bool getAudioActive() const { return m_audioActive; } bool getAudioActive() const { return m_audioActive; }
void getMagSqLevels(double& avg, double& peak, int& nbSamples) void getMagSqLevels(double& avg, double& peak, int& nbSamples)
{ {
avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount; avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount;
m_magsq = avg; m_magsq = avg;
peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak; peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak;
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount; nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
m_magsqSum = 0.0f; m_magsqSum = 0.0f;
m_magsqPeak = 0.0f; m_magsqPeak = 0.0f;
m_magsqCount = 0; m_magsqCount = 0;
} }
private: static const QString m_channelID;
class MsgConfigureSSBDemodPrivate : public Message {
MESSAGE_CLASS_DECLARATION private:
class MsgConfigureSSBDemodPrivate : public Message {
public: MESSAGE_CLASS_DECLARATION
Real getBandwidth() const { return m_Bandwidth; }
Real getLoCutoff() const { return m_LowCutoff; } public:
Real getVolume() const { return m_volume; } Real getBandwidth() const { return m_Bandwidth; }
int getSpanLog2() const { return m_spanLog2; } Real getLoCutoff() const { return m_LowCutoff; }
bool getAudioBinaural() const { return m_audioBinaural; } Real getVolume() const { return m_volume; }
bool getAudioFlipChannels() const { return m_audioFlipChannels; } int getSpanLog2() const { return m_spanLog2; }
bool getDSB() const { return m_dsb; } bool getAudioBinaural() const { return m_audioBinaural; }
bool getAudioMute() const { return m_audioMute; } bool getAudioFlipChannels() const { return m_audioFlipChannels; }
bool getAGC() const { return m_agc; } bool getDSB() const { return m_dsb; }
bool getAGCClamping() const { return m_agcClamping; } bool getAudioMute() const { return m_audioMute; }
int getAGCTimeLog2() const { return m_agcTimeLog2; } bool getAGC() const { return m_agc; }
int getAGCPowerThershold() const { return m_agcPowerThreshold; } bool getAGCClamping() const { return m_agcClamping; }
int getAGCThersholdGate() const { return m_agcThresholdGate; } int getAGCTimeLog2() const { return m_agcTimeLog2; }
int getAGCPowerThershold() const { return m_agcPowerThreshold; }
static MsgConfigureSSBDemodPrivate* create(Real Bandwidth, int getAGCThersholdGate() const { return m_agcThresholdGate; }
Real LowCutoff,
Real volume, static MsgConfigureSSBDemodPrivate* create(Real Bandwidth,
int spanLog2, Real LowCutoff,
bool audioBinaural, Real volume,
bool audioFlipChannels, int spanLog2,
bool dsb, bool audioBinaural,
bool audioMute, bool audioFlipChannels,
bool agc, bool dsb,
bool agcClamping, bool audioMute,
int agcTimeLog2, bool agc,
int agcPowerThreshold, bool agcClamping,
int agcThresholdGate) int agcTimeLog2,
{ int agcPowerThreshold,
return new MsgConfigureSSBDemodPrivate( int agcThresholdGate)
Bandwidth, {
LowCutoff, return new MsgConfigureSSBDemodPrivate(
volume, Bandwidth,
spanLog2, LowCutoff,
audioBinaural, volume,
audioFlipChannels, spanLog2,
dsb, audioBinaural,
audioMute, audioFlipChannels,
agc, dsb,
agcClamping, audioMute,
agcTimeLog2, agc,
agcPowerThreshold, agcClamping,
agcThresholdGate); agcTimeLog2,
} agcPowerThreshold,
agcThresholdGate);
private: }
Real m_Bandwidth;
Real m_LowCutoff; private:
Real m_volume; Real m_Bandwidth;
int m_spanLog2; Real m_LowCutoff;
bool m_audioBinaural; Real m_volume;
bool m_audioFlipChannels; int m_spanLog2;
bool m_dsb; bool m_audioBinaural;
bool m_audioMute; bool m_audioFlipChannels;
bool m_agc; bool m_dsb;
bool m_agcClamping; bool m_audioMute;
int m_agcTimeLog2; bool m_agc;
int m_agcPowerThreshold; bool m_agcClamping;
int m_agcThresholdGate; int m_agcTimeLog2;
int m_agcPowerThreshold;
MsgConfigureSSBDemodPrivate(Real Bandwidth, int m_agcThresholdGate;
Real LowCutoff,
Real volume, MsgConfigureSSBDemodPrivate(Real Bandwidth,
int spanLog2, Real LowCutoff,
bool audioBinaural, Real volume,
bool audioFlipChannels, int spanLog2,
bool dsb, bool audioBinaural,
bool audioMute, bool audioFlipChannels,
bool agc, bool dsb,
bool agcClamping, bool audioMute,
int agcTimeLog2, bool agc,
int agcPowerThreshold, bool agcClamping,
int agcThresholdGate) : int agcTimeLog2,
Message(), int agcPowerThreshold,
m_Bandwidth(Bandwidth), int agcThresholdGate) :
m_LowCutoff(LowCutoff), Message(),
m_volume(volume), m_Bandwidth(Bandwidth),
m_spanLog2(spanLog2), m_LowCutoff(LowCutoff),
m_audioBinaural(audioBinaural), m_volume(volume),
m_audioFlipChannels(audioFlipChannels), m_spanLog2(spanLog2),
m_dsb(dsb), m_audioBinaural(audioBinaural),
m_audioMute(audioMute), m_audioFlipChannels(audioFlipChannels),
m_agc(agc), m_dsb(dsb),
m_agcClamping(agcClamping), m_audioMute(audioMute),
m_agcTimeLog2(agcTimeLog2), m_agc(agc),
m_agcPowerThreshold(agcPowerThreshold), m_agcClamping(agcClamping),
m_agcThresholdGate(agcThresholdGate) m_agcTimeLog2(agcTimeLog2),
{ } m_agcPowerThreshold(agcPowerThreshold),
}; m_agcThresholdGate(agcThresholdGate)
{ }
DeviceSourceAPI *m_deviceAPI; };
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer; DeviceSourceAPI *m_deviceAPI;
SSBDemodSettings m_settings; ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
Real m_Bandwidth; SSBDemodSettings m_settings;
Real m_LowCutoff;
Real m_volume; Real m_Bandwidth;
int m_spanLog2; Real m_LowCutoff;
fftfilt::cmplx m_sum; Real m_volume;
int m_undersampleCount; int m_spanLog2;
int m_sampleRate; fftfilt::cmplx m_sum;
int m_frequency; int m_undersampleCount;
bool m_audioBinaual; int m_sampleRate;
bool m_audioFlipChannels; int m_frequency;
bool m_usb; bool m_audioBinaual;
bool m_dsb; bool m_audioFlipChannels;
bool m_audioMute; bool m_usb;
double m_magsq; bool m_dsb;
double m_magsqSum; bool m_audioMute;
double m_magsqPeak; double m_magsq;
int m_magsqCount; double m_magsqSum;
MagAGC m_agc; double m_magsqPeak;
bool m_agcActive; int m_magsqCount;
bool m_agcClamping; MagAGC m_agc;
int m_agcNbSamples; //!< number of audio (48 kHz) samples for AGC averaging bool m_agcActive;
double m_agcPowerThreshold; //!< AGC power threshold (linear) bool m_agcClamping;
int m_agcThresholdGate; //!< Gate length in number of samples befor threshold triggers int m_agcNbSamples; //!< number of audio (48 kHz) samples for AGC averaging
bool m_audioActive; //!< True if an audio signal is produced (no AGC or AGC and above threshold) double m_agcPowerThreshold; //!< AGC power threshold (linear)
int m_agcThresholdGate; //!< Gate length in number of samples befor threshold triggers
NCOF m_nco; bool m_audioActive; //!< True if an audio signal is produced (no AGC or AGC and above threshold)
Interpolator m_interpolator;
Real m_sampleDistanceRemain; NCOF m_nco;
fftfilt* SSBFilter; Interpolator m_interpolator;
fftfilt* DSBFilter; Real m_sampleDistanceRemain;
fftfilt* SSBFilter;
BasebandSampleSink* m_sampleSink; fftfilt* DSBFilter;
SampleVector m_sampleBuffer;
BasebandSampleSink* m_sampleSink;
AudioVector m_audioBuffer; SampleVector m_sampleBuffer;
uint m_audioBufferFill;
AudioFifo m_audioFifo; AudioVector m_audioBuffer;
quint32 m_audioSampleRate; uint m_audioBufferFill;
AudioFifo m_audioFifo;
QMutex m_settingsMutex; quint32 m_audioSampleRate;
void applySettings(const SSBDemodSettings& settings, bool force = false); QMutex m_settingsMutex;
};
void applySettings(const SSBDemodSettings& settings, bool force = false);
#endif // INCLUDE_SSBDEMOD_H };
#endif // INCLUDE_SSBDEMOD_H

View File

@ -17,8 +17,6 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "ssbdemod.h" #include "ssbdemod.h"
const QString SSBDemodGUI::m_channelID = "de.maintech.sdrangelove.channel.ssb";
SSBDemodGUI* SSBDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet) SSBDemodGUI* SSBDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
{ {
SSBDemodGUI* gui = new SSBDemodGUI(pluginAPI, deviceUISet); SSBDemodGUI* gui = new SSBDemodGUI(pluginAPI, deviceUISet);
@ -253,7 +251,7 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
m_deviceUISet->registerRxChannelInstance(m_channelID, this); m_deviceUISet->registerRxChannelInstance(SSBDemod::m_channelID, this);
m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this); m_deviceUISet->addRollupWidget(this);

View File

@ -37,8 +37,6 @@ public:
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message); virtual bool handleMessage(const Message& message);
static const QString m_channelID;
private slots: private slots:
void viewChanged(); void viewChanged();
void on_deltaFrequency_changed(qint64 value); void on_deltaFrequency_changed(qint64 value);

View File

@ -4,6 +4,7 @@
#include <QtPlugin> #include <QtPlugin>
#include "plugin/pluginapi.h" #include "plugin/pluginapi.h"
#include "ssbdemodgui.h" #include "ssbdemodgui.h"
#include "ssbdemod.h"
const PluginDescriptor SSBPlugin::m_pluginDescriptor = { const PluginDescriptor SSBPlugin::m_pluginDescriptor = {
QString("SSB Demodulator"), QString("SSB Demodulator"),
@ -30,16 +31,27 @@ void SSBPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI = pluginAPI; m_pluginAPI = pluginAPI;
// register demodulator // register demodulator
m_pluginAPI->registerRxChannel(SSBDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(SSBDemod::m_channelID, this);
} }
PluginInstanceGUI* SSBPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet) PluginInstanceGUI* SSBPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
{ {
if(channelName == SSBDemodGUI::m_channelID) if(channelName == SSBDemod::m_channelID)
{ {
SSBDemodGUI* gui = SSBDemodGUI::create(m_pluginAPI, deviceUISet); SSBDemodGUI* gui = SSBDemodGUI::create(m_pluginAPI, deviceUISet);
return gui; return gui;
} else { } else {
return NULL; return 0;
} }
} }
BasebandSampleSink* SSBPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{
if(channelName == SSBDemod::m_channelID)
{
SSBDemod* sink = new SSBDemod(deviceAPI);
return sink;
} else {
return 0;
}
}

View File

@ -5,6 +5,7 @@
#include "plugin/plugininterface.h" #include "plugin/plugininterface.h"
class DeviceUISet; class DeviceUISet;
class BasebandSampleSink;
class SSBPlugin : public QObject, PluginInterface { class SSBPlugin : public QObject, PluginInterface {
Q_OBJECT Q_OBJECT
@ -18,6 +19,7 @@ public:
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet); PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -33,6 +33,8 @@
MESSAGE_CLASS_DEFINITION(WFMDemod::MsgConfigureWFMDemod, Message) MESSAGE_CLASS_DEFINITION(WFMDemod::MsgConfigureWFMDemod, Message)
MESSAGE_CLASS_DEFINITION(WFMDemod::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(WFMDemod::MsgConfigureChannelizer, Message)
const QString WFMDemod::m_channelID = "de.maintech.sdrangelove.channel.wfm";
WFMDemod::WFMDemod(DeviceSourceAPI* deviceAPI) : WFMDemod::WFMDemod(DeviceSourceAPI* deviceAPI) :
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
m_squelchOpen(false), m_squelchOpen(false),

View File

@ -109,6 +109,8 @@ public:
m_magsqCount = 0; m_magsqCount = 0;
} }
static const QString m_channelID;
private: private:
enum RateState { enum RateState {
RSInitialFill, RSInitialFill,

View File

@ -18,8 +18,6 @@
#include "wfmdemod.h" #include "wfmdemod.h"
const QString WFMDemodGUI::m_channelID = "de.maintech.sdrangelove.channel.wfm";
WFMDemodGUI* WFMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet) WFMDemodGUI* WFMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
{ {
WFMDemodGUI* gui = new WFMDemodGUI(pluginAPI, deviceUISet); WFMDemodGUI* gui = new WFMDemodGUI(pluginAPI, deviceUISet);
@ -187,7 +185,7 @@ WFMDemodGUI::WFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
m_deviceUISet->registerRxChannelInstance(m_channelID, this); m_deviceUISet->registerRxChannelInstance(WFMDemod::m_channelID, this);
m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this); m_deviceUISet->addRollupWidget(this);

View File

@ -36,8 +36,6 @@ public:
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message); virtual bool handleMessage(const Message& message);
static const QString m_channelID;
private slots: private slots:
void channelMarkerChanged(); void channelMarkerChanged();
void on_deltaFrequency_changed(qint64 value); void on_deltaFrequency_changed(qint64 value);

View File

@ -4,6 +4,7 @@
#include "plugin/pluginapi.h" #include "plugin/pluginapi.h"
#include "wfmdemodgui.h" #include "wfmdemodgui.h"
#include "wfmdemod.h"
const PluginDescriptor WFMPlugin::m_pluginDescriptor = { const PluginDescriptor WFMPlugin::m_pluginDescriptor = {
QString("WFM Demodulator"), QString("WFM Demodulator"),
@ -30,16 +31,27 @@ void WFMPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI = pluginAPI; m_pluginAPI = pluginAPI;
// register WFM demodulator // register WFM demodulator
m_pluginAPI->registerRxChannel(WFMDemodGUI::m_channelID, this); m_pluginAPI->registerRxChannel(WFMDemod::m_channelID, this);
} }
PluginInstanceGUI* WFMPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet) PluginInstanceGUI* WFMPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
{ {
if(channelName == WFMDemodGUI::m_channelID) if(channelName == WFMDemod::m_channelID)
{ {
WFMDemodGUI* gui = WFMDemodGUI::create(m_pluginAPI, deviceUISet); WFMDemodGUI* gui = WFMDemodGUI::create(m_pluginAPI, deviceUISet);
return gui; return gui;
} else { } else {
return NULL; return 0;
} }
} }
BasebandSampleSink* WFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{
if(channelName == WFMDemod::m_channelID)
{
WFMDemod* sink = new WFMDemod(deviceAPI);
return sink;
} else {
return 0;
}
}

View File

@ -5,6 +5,7 @@
#include "plugin/plugininterface.h" #include "plugin/plugininterface.h"
class DeviceUISet; class DeviceUISet;
class BasebandSampleSink;
class WFMPlugin : public QObject, PluginInterface { class WFMPlugin : public QObject, PluginInterface {
Q_OBJECT Q_OBJECT
@ -18,6 +19,7 @@ public:
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet); PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -30,6 +30,8 @@ MESSAGE_CLASS_DEFINITION(TCPSrc::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(TCPSrc::MsgTCPSrcConnection, Message) MESSAGE_CLASS_DEFINITION(TCPSrc::MsgTCPSrcConnection, Message)
MESSAGE_CLASS_DEFINITION(TCPSrc::MsgTCPSrcSpectrum, Message) MESSAGE_CLASS_DEFINITION(TCPSrc::MsgTCPSrcSpectrum, Message)
const QString TCPSrc::m_channelID = "sdrangel.channel.tcpsrc";
TCPSrc::TCPSrc(DeviceSourceAPI* deviceAPI) : TCPSrc::TCPSrc(DeviceSourceAPI* deviceAPI) :
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
m_settingsMutex(QMutex::Recursive) m_settingsMutex(QMutex::Recursive)

View File

@ -113,6 +113,8 @@ public:
virtual void stop(); virtual void stop();
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
static const QString m_channelID;
protected: protected:
class MsgTCPSrcSpectrum : public Message { class MsgTCPSrcSpectrum : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION

View File

@ -12,8 +12,6 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "tcpsrc.h" #include "tcpsrc.h"
const QString TCPSrcGUI::m_channelID = "sdrangel.channel.tcpsrc";
TCPSrcGUI* TCPSrcGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet) TCPSrcGUI* TCPSrcGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
{ {
TCPSrcGUI* gui = new TCPSrcGUI(pluginAPI, deviceUISet); TCPSrcGUI* gui = new TCPSrcGUI(pluginAPI, deviceUISet);
@ -165,7 +163,7 @@ TCPSrcGUI::TCPSrcGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget* pa
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
m_deviceUISet->registerRxChannelInstance(m_channelID, this); m_deviceUISet->registerRxChannelInstance(TCPSrc::m_channelID, this);
m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this); m_deviceUISet->addRollupWidget(this);

View File

@ -39,8 +39,6 @@ public:
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message); virtual bool handleMessage(const Message& message);
static const QString m_channelID;
private slots: private slots:
void channelMarkerChanged(); void channelMarkerChanged();
void on_deltaFrequency_changed(qint64 value); void on_deltaFrequency_changed(qint64 value);

View File

@ -4,6 +4,7 @@
#include "plugin/pluginapi.h" #include "plugin/pluginapi.h"
#include "tcpsrcgui.h" #include "tcpsrcgui.h"
#include "tcpsrc.h"
const PluginDescriptor TCPSrcPlugin::m_pluginDescriptor = { const PluginDescriptor TCPSrcPlugin::m_pluginDescriptor = {
QString("TCP Channel Source"), QString("TCP Channel Source"),
@ -30,18 +31,29 @@ void TCPSrcPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI = pluginAPI; m_pluginAPI = pluginAPI;
// register TCP Channel Source // register TCP Channel Source
m_pluginAPI->registerRxChannel(TCPSrcGUI::m_channelID, this); m_pluginAPI->registerRxChannel(TCPSrc::m_channelID, this);
} }
PluginInstanceGUI* TCPSrcPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet) PluginInstanceGUI* TCPSrcPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
{ {
if(channelName == TCPSrcGUI::m_channelID) if(channelName == TCPSrc::m_channelID)
{ {
TCPSrcGUI* gui = TCPSrcGUI::create(m_pluginAPI, deviceUISet); TCPSrcGUI* gui = TCPSrcGUI::create(m_pluginAPI, deviceUISet);
// deviceAPI->registerChannelInstance("sdrangel.channel.tcpsrc", gui); // deviceAPI->registerChannelInstance("sdrangel.channel.tcpsrc", gui);
// m_pluginAPI->addChannelRollup(gui); // m_pluginAPI->addChannelRollup(gui);
return gui; return gui;
} else { } else {
return NULL; return 0;
} }
} }
BasebandSampleSink* TCPSrcPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{
if(channelName == TCPSrc::m_channelID)
{
TCPSrc* sink = new TCPSrc(deviceAPI);
return sink;
} else {
return 0;
}
}

View File

@ -5,6 +5,7 @@
#include "plugin/plugininterface.h" #include "plugin/plugininterface.h"
class DeviceUISet; class DeviceUISet;
class BasebandSampleSink;
class TCPSrcPlugin : public QObject, PluginInterface { class TCPSrcPlugin : public QObject, PluginInterface {
Q_OBJECT Q_OBJECT
@ -18,6 +19,7 @@ public:
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet); PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;

View File

@ -33,6 +33,8 @@ MESSAGE_CLASS_DEFINITION(UDPSrc::MsgConfigureUDPSrc, Message)
MESSAGE_CLASS_DEFINITION(UDPSrc::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(UDPSrc::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(UDPSrc::MsgUDPSrcSpectrum, Message) MESSAGE_CLASS_DEFINITION(UDPSrc::MsgUDPSrcSpectrum, Message)
const QString UDPSrc::m_channelID = "sdrangel.channel.udpsrc";
UDPSrc::UDPSrc(DeviceSourceAPI *deviceAPI) : UDPSrc::UDPSrc(DeviceSourceAPI *deviceAPI) :
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
m_outMovingAverage(480, 1e-10), m_outMovingAverage(480, 1e-10),

View File

@ -104,6 +104,7 @@ public:
virtual void stop(); virtual void stop();
virtual bool handleMessage(const Message& cmd); virtual bool handleMessage(const Message& cmd);
static const QString m_channelID;
static const int udpBlockSize = 512; // UDP block size in number of bytes static const int udpBlockSize = 512; // UDP block size in number of bytes
public slots: public slots:

View File

@ -30,8 +30,6 @@
#include "udpsrc.h" #include "udpsrc.h"
const QString UDPSrcGUI::m_channelID = "sdrangel.channel.udpsrc";
UDPSrcGUI* UDPSrcGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet) UDPSrcGUI* UDPSrcGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
{ {
UDPSrcGUI* gui = new UDPSrcGUI(pluginAPI, deviceUISet); UDPSrcGUI* gui = new UDPSrcGUI(pluginAPI, deviceUISet);
@ -185,7 +183,7 @@ UDPSrcGUI::UDPSrcGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget* pa
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged())); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
m_deviceUISet->registerRxChannelInstance(m_channelID, this); m_deviceUISet->registerRxChannelInstance(UDPSrc::m_channelID, this);
m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this); m_deviceUISet->addRollupWidget(this);

View File

@ -55,8 +55,6 @@ public:
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message); virtual bool handleMessage(const Message& message);
static const QString m_channelID;
private slots: private slots:
void channelMarkerChanged(); void channelMarkerChanged();
void on_deltaFrequency_changed(qint64 value); void on_deltaFrequency_changed(qint64 value);

View File

@ -21,6 +21,7 @@
#include "plugin/pluginapi.h" #include "plugin/pluginapi.h"
#include "udpsrcgui.h" #include "udpsrcgui.h"
#include "udpsrc.h"
const PluginDescriptor UDPSrcPlugin::m_pluginDescriptor = { const PluginDescriptor UDPSrcPlugin::m_pluginDescriptor = {
QString("UDP Channel Source"), QString("UDP Channel Source"),
@ -47,12 +48,12 @@ void UDPSrcPlugin::initPlugin(PluginAPI* pluginAPI)
m_pluginAPI = pluginAPI; m_pluginAPI = pluginAPI;
// register TCP Channel Source // register TCP Channel Source
m_pluginAPI->registerRxChannel(UDPSrcGUI::m_channelID, this); m_pluginAPI->registerRxChannel(UDPSrc::m_channelID, this);
} }
PluginInstanceGUI* UDPSrcPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet) PluginInstanceGUI* UDPSrcPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
{ {
if(channelName == UDPSrcGUI::m_channelID) if(channelName == UDPSrc::m_channelID)
{ {
UDPSrcGUI* gui = UDPSrcGUI::create(m_pluginAPI, deviceUISet); UDPSrcGUI* gui = UDPSrcGUI::create(m_pluginAPI, deviceUISet);
// deviceAPI->registerChannelInstance("sdrangel.channel.udpsrc", gui); // deviceAPI->registerChannelInstance("sdrangel.channel.udpsrc", gui);
@ -62,3 +63,14 @@ PluginInstanceGUI* UDPSrcPlugin::createRxChannelGUI(const QString& channelName,
return 0; return 0;
} }
} }
BasebandSampleSink* UDPSrcPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
{
if(channelName == UDPSrc::m_channelID)
{
UDPSrc* sink = new UDPSrc(deviceAPI);
return sink;
} else {
return 0;
}
}

View File

@ -22,6 +22,7 @@
#include "plugin/plugininterface.h" #include "plugin/plugininterface.h"
class DeviceUISet; class DeviceUISet;
class BasebandSampleSink;
class UDPSrcPlugin : public QObject, PluginInterface { class UDPSrcPlugin : public QObject, PluginInterface {
Q_OBJECT Q_OBJECT
@ -35,6 +36,7 @@ public:
void initPlugin(PluginAPI* pluginAPI); void initPlugin(PluginAPI* pluginAPI);
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet); PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
private: private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;