1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-07-08 03:45:26 -04:00

Demod Analyzer: implementation for the rest of planned plugins

This commit is contained in:
f4exb 2020-12-21 02:30:29 +01:00
parent e8ea0665fe
commit 793d8b9f49
41 changed files with 363 additions and 27 deletions

@ -30,7 +30,7 @@
const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = { const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = {
DSDDemod::m_channelId, DSDDemod::m_channelId,
QStringLiteral("DSD Demodulator"), QStringLiteral("DSD Demodulator"),
QStringLiteral("6.3.3"), QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,

@ -12,7 +12,7 @@
const PluginDescriptor NFMPlugin::m_pluginDescriptor = { const PluginDescriptor NFMPlugin::m_pluginDescriptor = {
NFMDemod::m_channelId, NFMDemod::m_channelId,
QStringLiteral("NFM Demodulator"), QStringLiteral("NFM Demodulator"),
QStringLiteral("6.3.3"), QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,

@ -58,6 +58,7 @@ SSBDemod::SSBDemod(DeviceAPI *deviceAPI) :
m_thread = new QThread(this); m_thread = new QThread(this);
m_basebandSink = new SSBDemodBaseband(); m_basebandSink = new SSBDemodBaseband();
m_basebandSink->setSpectrumSink(&m_spectrumVis); m_basebandSink->setSpectrumSink(&m_spectrumVis);
m_basebandSink->setChannel(this);
m_basebandSink->moveToThread(m_thread); m_basebandSink->moveToThread(m_thread);
applySettings(m_settings, true); applySettings(m_settings, true);

@ -63,6 +63,11 @@ void SSBDemodBaseband::reset()
m_sampleFifo.reset(); m_sampleFifo.reset();
} }
void SSBDemodBaseband::setChannel(ChannelAPI *channel)
{
m_sink.setChannel(channel);
}
void SSBDemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) void SSBDemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
{ {
m_sampleFifo.write(begin, end); m_sampleFifo.write(begin, end);
@ -198,4 +203,4 @@ void SSBDemodBaseband::setBasebandSampleRate(int sampleRate)
{ {
m_channelizer->setBasebandSampleRate(sampleRate); m_channelizer->setBasebandSampleRate(sampleRate);
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset()); m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
} }

@ -28,6 +28,7 @@
#include "ssbdemodsink.h" #include "ssbdemodsink.h"
class DownChannelizer; class DownChannelizer;
class ChannelAPI;
class SSBDemodBaseband : public QObject class SSBDemodBaseband : public QObject
{ {
@ -69,6 +70,7 @@ public:
bool getAudioActive() const { return m_sink.getAudioActive(); } bool getAudioActive() const { return m_sink.getAudioActive(); }
void setBasebandSampleRate(int sampleRate); void setBasebandSampleRate(int sampleRate);
void setMessageQueueToGUI(MessageQueue *messageQueue) { m_messageQueueToGUI = messageQueue; } void setMessageQueueToGUI(MessageQueue *messageQueue) { m_messageQueueToGUI = messageQueue; }
void setChannel(ChannelAPI *channel);
private: private:
SampleSinkFifo m_sampleFifo; SampleSinkFifo m_sampleFifo;
@ -90,4 +92,4 @@ private slots:
void handleData(); //!< Handle data when samples have to be processed void handleData(); //!< Handle data when samples have to be processed
}; };
#endif // INCLUDE_SSBDEMODBASEBAND_H #endif // INCLUDE_SSBDEMODBASEBAND_H

@ -25,8 +25,11 @@
#include "dsp/dspcommands.h" #include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h" #include "dsp/devicesamplemimo.h"
#include "dsp/basebandsamplesink.h" #include "dsp/basebandsamplesink.h"
#include "dsp/datafifo.h"
#include "device/deviceapi.h" #include "device/deviceapi.h"
#include "util/db.h" #include "util/db.h"
#include "util/messagequeue.h"
#include "maincore.h"
#include "ssbdemodsink.h" #include "ssbdemodsink.h"
@ -62,6 +65,9 @@ SSBDemodSink::SSBDemodSink() :
m_undersampleCount = 0; m_undersampleCount = 0;
m_sum = 0; m_sum = 0;
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
m_usb = true; m_usb = true;
m_magsq = 0.0f; m_magsq = 0.0f;
m_magsqSum = 0.0f; m_magsqSum = 0.0f;
@ -194,6 +200,25 @@ void SSBDemodSink::processOneSample(Complex &ci)
m_audioBuffer[m_audioBufferFill].l = sample; m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample; m_audioBuffer[m_audioBufferFill].r = sample;
} }
m_demodBuffer[m_demodBufferFill] = (z.real() + z.imag()) * 0.7;
++m_demodBufferFill;
if (m_demodBufferFill >= m_demodBuffer.size())
{
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::iterator it = dataFifos->begin();
for (; it != dataFifos->end(); ++it) {
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
}
}
m_demodBufferFill = 0;
}
} }
++m_audioBufferFill; ++m_audioBufferFill;
@ -279,6 +304,19 @@ void SSBDemodSink::applyAudioSampleRate(int sampleRate)
m_audioFifo.setSize(sampleRate); m_audioFifo.setSize(sampleRate);
m_audioSampleRate = sampleRate; m_audioSampleRate = sampleRate;
QList<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate);
(*it)->push(msg);
}
}
} }
void SSBDemodSink::applySettings(const SSBDemodSettings& settings, bool force) void SSBDemodSink::applySettings(const SSBDemodSettings& settings, bool force)

@ -18,7 +18,7 @@
#ifndef INCLUDE_SSBDEMODSINK_H #ifndef INCLUDE_SSBDEMODSINK_H
#define INCLUDE_SSBDEMODSINK_H #define INCLUDE_SSBDEMODSINK_H
#include <vector> #include <QVector>
#include "dsp/channelsamplesink.h" #include "dsp/channelsamplesink.h"
#include "dsp/ncof.h" #include "dsp/ncof.h"
@ -31,6 +31,7 @@
#include "ssbdemodsettings.h" #include "ssbdemodsettings.h"
class BasebandSampleSink; class BasebandSampleSink;
class ChannelAPI;
class SSBDemodSink : public ChannelSampleSink { class SSBDemodSink : public ChannelSampleSink {
public: public:
@ -47,6 +48,7 @@ public:
AudioFifo *getAudioFifo() { return &m_audioFifo; } AudioFifo *getAudioFifo() { return &m_audioFifo; }
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 setChannel(ChannelAPI *channel) { m_channel = channel; }
void getMagSqLevels(double& avg, double& peak, int& nbSamples) void getMagSqLevels(double& avg, double& peak, int& nbSamples)
{ {
@ -78,6 +80,7 @@ private:
}; };
SSBDemodSettings m_settings; SSBDemodSettings m_settings;
ChannelAPI *m_channel;
Real m_Bandwidth; Real m_Bandwidth;
Real m_LowCutoff; Real m_LowCutoff;
@ -121,10 +124,13 @@ private:
AudioFifo m_audioFifo; AudioFifo m_audioFifo;
quint32 m_audioSampleRate; quint32 m_audioSampleRate;
QVector<qint16> m_demodBuffer;
int m_demodBufferFill;
static const int m_ssbFftLen; static const int m_ssbFftLen;
static const int m_agcTarget; static const int m_agcTarget;
void processOneSample(Complex &ci); void processOneSample(Complex &ci);
}; };
#endif // INCLUDE_SSBDEMODSINK_H #endif // INCLUDE_SSBDEMODSINK_H

@ -12,7 +12,7 @@
const PluginDescriptor SSBPlugin::m_pluginDescriptor = { const PluginDescriptor SSBPlugin::m_pluginDescriptor = {
SSBDemod::m_channelId, SSBDemod::m_channelId,
QStringLiteral("SSB Demodulator"), QStringLiteral("SSB Demodulator"),
QStringLiteral("6.3.3"), QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,

@ -59,6 +59,7 @@ WFMDemod::WFMDemod(DeviceAPI* deviceAPI) :
m_thread = new QThread(this); m_thread = new QThread(this);
m_basebandSink = new WFMDemodBaseband(); m_basebandSink = new WFMDemodBaseband();
m_basebandSink->setChannel(this);
m_basebandSink->moveToThread(m_thread); m_basebandSink->moveToThread(m_thread);
applySettings(m_settings, true); applySettings(m_settings, true);

@ -58,6 +58,11 @@ void WFMDemodBaseband::reset()
m_sampleFifo.reset(); m_sampleFifo.reset();
} }
void WFMDemodBaseband::setChannel(ChannelAPI *channel)
{
m_sink.setChannel(channel);
}
void WFMDemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) void WFMDemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
{ {
m_sampleFifo.write(begin, end); m_sampleFifo.write(begin, end);

@ -28,6 +28,7 @@
#include "wfmdemodsink.h" #include "wfmdemodsink.h"
class DownChannelizer; class DownChannelizer;
class ChannelAPI;
class WFMDemodBaseband : public QObject class WFMDemodBaseband : public QObject
{ {
@ -69,6 +70,7 @@ public:
bool getSquelchOpen() const { return m_sink.getSquelchOpen(); } bool getSquelchOpen() const { return m_sink.getSquelchOpen(); }
int getSquelchState() const { return m_sink.getSquelchState(); } int getSquelchState() const { return m_sink.getSquelchState(); }
void getMagSqLevels(double& avg, double& peak, int& nbSamples) { m_sink.getMagSqLevels(avg, peak, nbSamples); } void getMagSqLevels(double& avg, double& peak, int& nbSamples) { m_sink.getMagSqLevels(avg, peak, nbSamples); }
void setChannel(ChannelAPI *channel);
private: private:
SampleSinkFifo m_sampleFifo; SampleSinkFifo m_sampleFifo;

@ -25,7 +25,10 @@
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "dsp/dspcommands.h" #include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h" #include "dsp/devicesamplemimo.h"
#include "dsp/datafifo.h"
#include "util/db.h" #include "util/db.h"
#include "util/messagequeue.h"
#include "maincore.h"
#include "wfmdemodsink.h" #include "wfmdemodsink.h"
@ -35,6 +38,7 @@ WFMDemodSink::WFMDemodSink() :
m_channelSampleRate(384000), m_channelSampleRate(384000),
m_channelFrequencyOffset(0), m_channelFrequencyOffset(0),
m_audioSampleRate(48000), m_audioSampleRate(48000),
m_squelchState(0),
m_squelchOpen(false), m_squelchOpen(false),
m_magsq(0.0f), m_magsq(0.0f),
m_magsqSum(0.0f), m_magsqSum(0.0f),
@ -48,6 +52,9 @@ WFMDemodSink::WFMDemodSink() :
m_audioBuffer.resize(16384); m_audioBuffer.resize(16384);
m_audioBufferFill = 0; m_audioBufferFill = 0;
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
applySettings(m_settings, true); applySettings(m_settings, true);
applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true);
} }
@ -130,6 +137,24 @@ void WFMDemodSink::feed(const SampleVector::const_iterator& begin, const SampleV
} }
m_interpolatorDistanceRemain += m_interpolatorDistance; m_interpolatorDistanceRemain += m_interpolatorDistance;
m_demodBuffer[m_demodBufferFill] = sample;
++m_demodBufferFill;
if (m_demodBufferFill >= m_demodBuffer.size())
{
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::iterator it = dataFifos->begin();
for (; it != dataFifos->end(); ++it) {
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
}
}
m_demodBufferFill = 0;
}
} }
} }
} }
@ -162,6 +187,19 @@ void WFMDemodSink::applyAudioSampleRate(int sampleRate)
m_interpolatorDistanceRemain = (Real) m_channelSampleRate / sampleRate; m_interpolatorDistanceRemain = (Real) m_channelSampleRate / sampleRate;
m_interpolatorDistance = (Real) m_channelSampleRate / (Real) sampleRate; m_interpolatorDistance = (Real) m_channelSampleRate / (Real) sampleRate;
m_audioSampleRate = sampleRate; m_audioSampleRate = sampleRate;
QList<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate);
(*it)->push(msg);
}
}
} }
void WFMDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force) void WFMDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
@ -186,8 +224,8 @@ void WFMDemodSink::applyChannelSettings(int channelSampleRate, int channelFreque
Real lowCut = -(m_settings.m_rfBandwidth / 2.0) / channelSampleRate; Real lowCut = -(m_settings.m_rfBandwidth / 2.0) / channelSampleRate;
Real hiCut = (m_settings.m_rfBandwidth / 2.0) / channelSampleRate; Real hiCut = (m_settings.m_rfBandwidth / 2.0) / channelSampleRate;
m_rfFilter->create_filter(lowCut, hiCut); m_rfFilter->create_filter(lowCut, hiCut);
m_fmExcursion = m_settings.m_rfBandwidth / (Real) channelSampleRate; //m_fmExcursion = m_settings.m_rfBandwidth / (Real) channelSampleRate;
m_phaseDiscri.setFMScaling(1.0f/m_fmExcursion); m_phaseDiscri.setFMScaling((float) channelSampleRate / ((float) 2*m_fmExcursion));
qDebug("WFMDemod::applySettings: m_fmExcursion: %f", m_fmExcursion); qDebug("WFMDemod::applySettings: m_fmExcursion: %f", m_fmExcursion);
} }
@ -224,8 +262,10 @@ void WFMDemodSink::applySettings(const WFMDemodSettings& settings, bool force)
Real lowCut = -(settings.m_rfBandwidth / 2.0) / m_channelSampleRate; Real lowCut = -(settings.m_rfBandwidth / 2.0) / m_channelSampleRate;
Real hiCut = (settings.m_rfBandwidth / 2.0) / m_channelSampleRate; Real hiCut = (settings.m_rfBandwidth / 2.0) / m_channelSampleRate;
m_rfFilter->create_filter(lowCut, hiCut); m_rfFilter->create_filter(lowCut, hiCut);
m_fmExcursion = settings.m_rfBandwidth / (Real) m_channelSampleRate; m_fmExcursion = (settings.m_rfBandwidth / 2) - m_settings.m_afBandwidth;
m_phaseDiscri.setFMScaling(1.0f/m_fmExcursion); m_fmExcursion = m_fmExcursion < 2500 ? 2500 : m_fmExcursion;
//m_fmExcursion = settings.m_rfBandwidth / (Real) m_channelSampleRate;
m_phaseDiscri.setFMScaling((float) m_channelSampleRate / ((float) 2*m_fmExcursion));
qDebug("WFMDemodSink::applySettings: m_fmExcursion: %f", m_fmExcursion); qDebug("WFMDemodSink::applySettings: m_fmExcursion: %f", m_fmExcursion);
} }

@ -18,7 +18,7 @@
#ifndef INCLUDE_WFMDEMODSINK_H #ifndef INCLUDE_WFMDEMODSINK_H
#define INCLUDE_WFMDEMODSINK_H #define INCLUDE_WFMDEMODSINK_H
#include <vector> #include <QVector>
#include "dsp/channelsamplesink.h" #include "dsp/channelsamplesink.h"
#include "dsp/nco.h" #include "dsp/nco.h"
@ -32,6 +32,8 @@
#include "wfmdemodsettings.h" #include "wfmdemodsettings.h"
class ChannelAPI;
class WFMDemodSink : public ChannelSampleSink { class WFMDemodSink : public ChannelSampleSink {
public: public:
WFMDemodSink(); WFMDemodSink();
@ -67,6 +69,7 @@ public:
AudioFifo *getAudioFifo() { return &m_audioFifo; } AudioFifo *getAudioFifo() { return &m_audioFifo; }
void applyAudioSampleRate(int sampleRate); void applyAudioSampleRate(int sampleRate);
int getAudioSampleRate() const { return m_audioSampleRate; } int getAudioSampleRate() const { return m_audioSampleRate; }
void setChannel(ChannelAPI *channel) { m_channel = channel; }
private: private:
struct MagSqLevelsStore struct MagSqLevelsStore
@ -87,6 +90,7 @@ private:
int m_channelSampleRate; int m_channelSampleRate;
int m_channelFrequencyOffset; int m_channelFrequencyOffset;
WFMDemodSettings m_settings; WFMDemodSettings m_settings;
ChannelAPI *m_channel;
int m_audioSampleRate; int m_audioSampleRate;
@ -115,6 +119,9 @@ private:
SampleVector m_sampleBuffer; SampleVector m_sampleBuffer;
PhaseDiscriminators m_phaseDiscri; PhaseDiscriminators m_phaseDiscri;
QVector<qint16> m_demodBuffer;
int m_demodBufferFill;
static const unsigned int m_rfFilterFftLength; static const unsigned int m_rfFilterFftLength;
}; };

@ -13,7 +13,7 @@
const PluginDescriptor WFMPlugin::m_pluginDescriptor = { const PluginDescriptor WFMPlugin::m_pluginDescriptor = {
WFMDemod::m_channelId, WFMDemod::m_channelId,
QStringLiteral("WFM Demodulator"), QStringLiteral("WFM Demodulator"),
QStringLiteral("6.3.3"), QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,

@ -343,7 +343,6 @@ void AMModSource::applyFeedbackAudioSampleRate(int sampleRate)
qDebug("AMModSource::applyFeedbackAudioSampleRate: %u", sampleRate); qDebug("AMModSource::applyFeedbackAudioSampleRate: %u", sampleRate);
m_feedbackInterpolatorDistanceRemain = 0; m_feedbackInterpolatorDistanceRemain = 0;
m_feedbackInterpolatorConsumed = false;
m_feedbackInterpolatorDistance = (Real) sampleRate / (Real) m_audioSampleRate; m_feedbackInterpolatorDistance = (Real) sampleRate / (Real) m_audioSampleRate;
Real cutoff = std::min(sampleRate, m_audioSampleRate) / 2.2f; Real cutoff = std::min(sampleRate, m_audioSampleRate) / 2.2f;
m_feedbackInterpolator.create(48, sampleRate, cutoff, 3.0); m_feedbackInterpolator.create(48, sampleRate, cutoff, 3.0);

@ -85,7 +85,6 @@ private:
Interpolator m_feedbackInterpolator; Interpolator m_feedbackInterpolator;
Real m_feedbackInterpolatorDistance; Real m_feedbackInterpolatorDistance;
Real m_feedbackInterpolatorDistanceRemain; Real m_feedbackInterpolatorDistanceRemain;
bool m_feedbackInterpolatorConsumed;
double m_magsq; double m_magsq;
MovingAverageUtil<double, double, 16> m_movingAverage; MovingAverageUtil<double, double, 16> m_movingAverage;

@ -66,6 +66,7 @@ NFMMod::NFMMod(DeviceAPI *deviceAPI) :
m_thread = new QThread(this); m_thread = new QThread(this);
m_basebandSource = new NFMModBaseband(); m_basebandSource = new NFMModBaseband();
m_basebandSource->setInputFileStream(&m_ifstream); m_basebandSource->setInputFileStream(&m_ifstream);
m_basebandSource->setChannel(this);
m_basebandSource->moveToThread(m_thread); m_basebandSource->moveToThread(m_thread);
applySettings(m_settings, true); applySettings(m_settings, true);

@ -62,6 +62,11 @@ void NFMModBaseband::reset()
m_sampleFifo.reset(); m_sampleFifo.reset();
} }
void NFMModBaseband::setChannel(ChannelAPI *channel)
{
m_source.setChannel(channel);
}
void NFMModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples) void NFMModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples)
{ {
unsigned int part1Begin, part1End, part2Begin, part2End; unsigned int part1Begin, part1End, part2Begin, part2End;
@ -226,4 +231,4 @@ void NFMModBaseband::applySettings(const NFMModSettings& settings, bool force)
int NFMModBaseband::getChannelSampleRate() const int NFMModBaseband::getChannelSampleRate() const
{ {
return m_channelizer->getChannelSampleRate(); return m_channelizer->getChannelSampleRate();
} }

@ -28,6 +28,7 @@
#include "nfmmodsource.h" #include "nfmmodsource.h"
class UpChannelizer; class UpChannelizer;
class ChannelAPI;
class NFMModBaseband : public QObject class NFMModBaseband : public QObject
{ {
@ -69,6 +70,7 @@ public:
void setInputFileStream(std::ifstream *ifstream) { m_source.setInputFileStream(ifstream); } void setInputFileStream(std::ifstream *ifstream) { m_source.setInputFileStream(ifstream); }
AudioFifo *getAudioFifo() { return m_source.getAudioFifo(); } AudioFifo *getAudioFifo() { return m_source.getAudioFifo(); }
AudioFifo *getFeedbackAudioFifo() { return m_source.getFeedbackAudioFifo(); } AudioFifo *getFeedbackAudioFifo() { return m_source.getFeedbackAudioFifo(); }
void setChannel(ChannelAPI *channel);
signals: signals:
/** /**

@ -28,7 +28,7 @@
const PluginDescriptor NFMModPlugin::m_pluginDescriptor = { const PluginDescriptor NFMModPlugin::m_pluginDescriptor = {
NFMMod::m_channelId, NFMMod::m_channelId,
QStringLiteral("NFM Modulator"), QStringLiteral("NFM Modulator"),
QStringLiteral("6.3.3"), QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,

@ -17,6 +17,10 @@
#include <QDebug> #include <QDebug>
#include "dsp/datafifo.h"
#include "util/messagequeue.h"
#include "maincore.h"
#include "nfmmodsource.h" #include "nfmmodsource.h"
const int NFMModSource::m_levelNbSamples = 480; // every 10ms const int NFMModSource::m_levelNbSamples = 480; // every 10ms
@ -44,6 +48,9 @@ NFMModSource::NFMModSource() :
m_feedbackAudioBuffer.resize(1<<14); m_feedbackAudioBuffer.resize(1<<14);
m_feedbackAudioBufferFill = 0; m_feedbackAudioBufferFill = 0;
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
m_magsq = 0.0; m_magsq = 0.0;
applySettings(m_settings, true); applySettings(m_settings, true);
@ -132,7 +139,7 @@ void NFMModSource::pullAudio(unsigned int nbSamplesAudio)
void NFMModSource::modulateSample() void NFMModSource::modulateSample()
{ {
Real t0, t; Real t0, t1, t;
pullAF(t0); pullAF(t0);
m_preemphasisFilter.process(t0, t); m_preemphasisFilter.process(t0, t);
@ -144,11 +151,13 @@ void NFMModSource::modulateSample()
calculateLevel(t); calculateLevel(t);
if (m_settings.m_ctcssOn) { if (m_settings.m_ctcssOn) {
m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * (0.85f * m_bandpass.filter(t) + 0.15f * 0.625f * m_ctcssNco.next()) * 1.33f; t1 = (0.85f * m_bandpass.filter(t) + 0.15f * 0.625f * m_ctcssNco.next()) * 1.2f;
} else { } else {
m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * m_bandpass.filter(t) * 1.33f; t1 = m_bandpass.filter(t) * 1.2f;
} }
m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * t1;
// limit phasor range to ]-pi,pi] // limit phasor range to ]-pi,pi]
if (m_modPhasor > M_PI) { if (m_modPhasor > M_PI) {
m_modPhasor -= (2.0f * M_PI); m_modPhasor -= (2.0f * M_PI);
@ -156,6 +165,25 @@ void NFMModSource::modulateSample()
m_modSample.real(cos(m_modPhasor) * 0.891235351562f * SDR_TX_SCALEF); // -1 dB m_modSample.real(cos(m_modPhasor) * 0.891235351562f * SDR_TX_SCALEF); // -1 dB
m_modSample.imag(sin(m_modPhasor) * 0.891235351562f * SDR_TX_SCALEF); m_modSample.imag(sin(m_modPhasor) * 0.891235351562f * SDR_TX_SCALEF);
m_demodBuffer[m_demodBufferFill] = t1 * std::numeric_limits<int16_t>::max();
++m_demodBufferFill;
if (m_demodBufferFill >= m_demodBuffer.size())
{
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::iterator it = dataFifos->begin();
for (; it != dataFifos->end(); ++it) {
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
}
}
m_demodBufferFill = 0;
}
} }
void NFMModSource::pullAF(Real& sample) void NFMModSource::pullAF(Real& sample)
@ -321,6 +349,19 @@ void NFMModSource::applyAudioSampleRate(int sampleRate)
m_preemphasisFilter.configure(m_preemphasis*sampleRate); m_preemphasisFilter.configure(m_preemphasis*sampleRate);
m_audioSampleRate = sampleRate; m_audioSampleRate = sampleRate;
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate); applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
QList<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate);
(*it)->push(msg);
}
}
} }
void NFMModSource::applyFeedbackAudioSampleRate(int sampleRate) void NFMModSource::applyFeedbackAudioSampleRate(int sampleRate)

@ -20,6 +20,7 @@
#include <QObject> #include <QObject>
#include <QMutex> #include <QMutex>
#include <QVector>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@ -36,6 +37,8 @@
#include "nfmmodsettings.h" #include "nfmmodsettings.h"
class ChannelAPI;
class NFMModSource : public QObject, public ChannelSampleSource class NFMModSource : public QObject, public ChannelSampleSource
{ {
Q_OBJECT Q_OBJECT
@ -54,6 +57,7 @@ public:
void applyFeedbackAudioSampleRate(int sampleRate); void applyFeedbackAudioSampleRate(int sampleRate);
int getAudioSampleRate() const { return m_audioSampleRate; } int getAudioSampleRate() const { return m_audioSampleRate; }
int getFeedbackAudioSampleRate() const { return m_feedbackAudioSampleRate; } int getFeedbackAudioSampleRate() const { return m_feedbackAudioSampleRate; }
void setChannel(ChannelAPI *channel) { m_channel = channel; }
CWKeyer& getCWKeyer() { return m_cwKeyer; } CWKeyer& getCWKeyer() { return m_cwKeyer; }
double getMagSq() const { return m_magsq; } double getMagSq() const { return m_magsq; }
void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const
@ -69,6 +73,7 @@ private:
int m_channelSampleRate; int m_channelSampleRate;
int m_channelFrequencyOffset; int m_channelFrequencyOffset;
NFMModSettings m_settings; NFMModSettings m_settings;
ChannelAPI *m_channel;
NCO m_carrierNco; NCO m_carrierNco;
NCOF m_toneNco; NCOF m_toneNco;
@ -86,6 +91,9 @@ private:
Real m_feedbackInterpolatorDistanceRemain; Real m_feedbackInterpolatorDistanceRemain;
bool m_feedbackInterpolatorConsumed; bool m_feedbackInterpolatorConsumed;
QVector<qint16> m_demodBuffer;
int m_demodBufferFill;
Lowpass<Real> m_lowpass; Lowpass<Real> m_lowpass;
Bandpass<Real> m_bandpass; Bandpass<Real> m_bandpass;
HighPassFilterRC m_preemphasisFilter; HighPassFilterRC m_preemphasisFilter;

@ -64,6 +64,7 @@ PacketMod::PacketMod(DeviceAPI *deviceAPI) :
m_thread = new QThread(this); m_thread = new QThread(this);
m_basebandSource = new PacketModBaseband(); m_basebandSource = new PacketModBaseband();
m_basebandSource->setSpectrumSampleSink(&m_spectrumVis); m_basebandSource->setSpectrumSampleSink(&m_spectrumVis);
m_basebandSource->setChannel(this);
m_basebandSource->moveToThread(m_thread); m_basebandSource->moveToThread(m_thread);
applySettings(m_settings, true); applySettings(m_settings, true);

@ -56,6 +56,11 @@ void PacketModBaseband::reset()
m_sampleFifo.reset(); m_sampleFifo.reset();
} }
void PacketModBaseband::setChannel(ChannelAPI *channel)
{
m_source.setChannel(channel);
}
void PacketModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples) void PacketModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples)
{ {
unsigned int part1Begin, part1End, part2Begin, part2End; unsigned int part1Begin, part1End, part2Begin, part2End;

@ -29,6 +29,7 @@
#include "packetmodsource.h" #include "packetmodsource.h"
class UpChannelizer; class UpChannelizer;
class ChannelAPI;
class PacketModBaseband : public QObject class PacketModBaseband : public QObject
{ {
@ -65,7 +66,7 @@ public:
double getMagSq() const { return m_source.getMagSq(); } double getMagSq() const { return m_source.getMagSq(); }
int getChannelSampleRate() const; int getChannelSampleRate() const;
void setSpectrumSampleSink(BasebandSampleSink* sampleSink) { m_source.setSpectrumSink(sampleSink); } void setSpectrumSampleSink(BasebandSampleSink* sampleSink) { m_source.setSpectrumSink(sampleSink); }
void setChannel(ChannelAPI *channel);
signals: signals:
/** /**

@ -29,7 +29,7 @@
const PluginDescriptor PacketModPlugin::m_pluginDescriptor = { const PluginDescriptor PacketModPlugin::m_pluginDescriptor = {
PacketMod::m_channelId, PacketMod::m_channelId,
QStringLiteral("Packet Modulator"), QStringLiteral("Packet Modulator"),
QStringLiteral("6.3.3"), QStringLiteral("6.4.0"),
QStringLiteral("(c) Jon Beniston, M7RCE"), QStringLiteral("(c) Jon Beniston, M7RCE"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,

@ -20,8 +20,11 @@
#include <QDebug> #include <QDebug>
#include "dsp/basebandsamplesink.h" #include "dsp/basebandsamplesink.h"
#include "dsp/datafifo.h"
#include "packetmodsource.h" #include "packetmodsource.h"
#include "util/crc.h" #include "util/crc.h"
#include "util/messagequeue.h"
#include "maincore.h"
PacketModSource::PacketModSource() : PacketModSource::PacketModSource() :
m_channelSampleRate(48000), m_channelSampleRate(48000),
@ -46,6 +49,10 @@ PacketModSource::PacketModSource() :
qDebug() << "PacketModSource::PacketModSource creating BPF : " << m_channelSampleRate; qDebug() << "PacketModSource::PacketModSource creating BPF : " << m_channelSampleRate;
m_bandpass.create(301, m_channelSampleRate, 800.0, 2600.0); m_bandpass.create(301, m_channelSampleRate, 800.0, 2600.0);
m_pulseShape.create(0.5, 6, m_channelSampleRate/9600); m_pulseShape.create(0.5, 6, m_channelSampleRate/9600);
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
applySettings(m_settings, true); applySettings(m_settings, true);
applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true);
} }
@ -266,6 +273,25 @@ void PacketModSource::modulateSample()
Real s = std::real(m_modSample); Real s = std::real(m_modSample);
calculateLevel(s); calculateLevel(s);
} }
m_demodBuffer[m_demodBufferFill] = audioMod * std::numeric_limits<int16_t>::max();
++m_demodBufferFill;
if (m_demodBufferFill >= m_demodBuffer.size())
{
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::iterator it = dataFifos->begin();
for (; it != dataFifos->end(); ++it) {
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
}
}
m_demodBufferFill = 0;
}
} }
void PacketModSource::calculateLevel(Real& sample) void PacketModSource::calculateLevel(Real& sample)
@ -383,6 +409,19 @@ void PacketModSource::applyChannelSettings(int channelSampleRate, int channelFre
qDebug() << "m_samplesPerSymbol: " << m_samplesPerSymbol << " (" << m_channelSampleRate << "/" << m_settings.m_baud << ")"; qDebug() << "m_samplesPerSymbol: " << m_samplesPerSymbol << " (" << m_channelSampleRate << "/" << m_settings.m_baud << ")";
// Precalculate FM sensensity to save doing it in the loop // Precalculate FM sensensity to save doing it in the loop
m_phaseSensitivity = 2.0f * M_PI * m_settings.m_fmDeviation / (double)m_channelSampleRate; m_phaseSensitivity = 2.0f * M_PI * m_settings.m_fmDeviation / (double)m_channelSampleRate;
QList<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, m_channelSampleRate);
(*it)->push(msg);
}
}
} }
static uint8_t *ax25_address(uint8_t *p, QString address, uint8_t crrl) static uint8_t *ax25_address(uint8_t *p, QString address, uint8_t crrl)

@ -21,6 +21,7 @@
#include <QMutex> #include <QMutex>
#include <QDebug> #include <QDebug>
#include <QVector>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@ -44,6 +45,7 @@
#define AX25_NO_L3 0xf0 #define AX25_NO_L3 0xf0
class BasebandSampleSink; class BasebandSampleSink;
class ChannelAPI;
class PacketModSource : public ChannelSampleSource class PacketModSource : public ChannelSampleSource
{ {
@ -66,12 +68,14 @@ public:
void applySettings(const PacketModSettings& settings, bool force = false); void applySettings(const PacketModSettings& settings, bool force = false);
void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false); void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false);
void addTXPacket(QString callsign, QString to, QString via, QString data); void addTXPacket(QString callsign, QString to, QString via, QString data);
void setChannel(ChannelAPI *channel) { m_channel = channel; }
private: private:
int m_channelSampleRate; int m_channelSampleRate;
int m_channelFrequencyOffset; int m_channelFrequencyOffset;
int m_spectrumRate; int m_spectrumRate;
PacketModSettings m_settings; PacketModSettings m_settings;
ChannelAPI *m_channel;
NCO m_carrierNco; NCO m_carrierNco;
Real m_audioPhase; Real m_audioPhase;
@ -126,6 +130,9 @@ private:
std::ofstream m_audioFile; // For debug output of baseband waveform std::ofstream m_audioFile; // For debug output of baseband waveform
QVector<qint16> m_demodBuffer;
int m_demodBufferFill;
bool bitsValid(); // Are there and bits to transmit bool bitsValid(); // Are there and bits to transmit
int getBit(); // Get bit from m_bits int getBit(); // Get bit from m_bits
void addBit(int bit); // Add bit to m_bits, with zero stuffing void addBit(int bit); // Add bit to m_bits, with zero stuffing

@ -67,6 +67,7 @@ SSBMod::SSBMod(DeviceAPI *deviceAPI) :
m_basebandSource = new SSBModBaseband(); m_basebandSource = new SSBModBaseband();
m_basebandSource->setSpectrumSink(&m_spectrumVis); m_basebandSource->setSpectrumSink(&m_spectrumVis);
m_basebandSource->setInputFileStream(&m_ifstream); m_basebandSource->setInputFileStream(&m_ifstream);
m_basebandSource->setChannel(this);
m_basebandSource->moveToThread(m_thread); m_basebandSource->moveToThread(m_thread);
applySettings(m_settings, true); applySettings(m_settings, true);

@ -63,6 +63,11 @@ void SSBModBaseband::reset()
m_sampleFifo.reset(); m_sampleFifo.reset();
} }
void SSBModBaseband::setChannel(ChannelAPI *channel)
{
m_source.setChannel(channel);
}
void SSBModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples) void SSBModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples)
{ {
unsigned int part1Begin, part1End, part2Begin, part2End; unsigned int part1Begin, part1End, part2Begin, part2End;

@ -30,6 +30,7 @@
class UpChannelizer; class UpChannelizer;
class BasebandSampleSink; class BasebandSampleSink;
class SpectrumVis; class SpectrumVis;
class ChannelAPI;
class SSBModBaseband : public QObject class SSBModBaseband : public QObject
{ {
@ -72,6 +73,7 @@ public:
AudioFifo *getAudioFifo() { return m_source.getAudioFifo(); } AudioFifo *getAudioFifo() { return m_source.getAudioFifo(); }
AudioFifo *getFeedbackAudioFifo() { return m_source.getFeedbackAudioFifo(); } AudioFifo *getFeedbackAudioFifo() { return m_source.getFeedbackAudioFifo(); }
void setSpectrumSink(SpectrumVis *sampleSink) { m_spectrumVis = sampleSink; m_source.setSpectrumSink((BasebandSampleSink *) sampleSink); } void setSpectrumSink(SpectrumVis *sampleSink) { m_spectrumVis = sampleSink; m_source.setSpectrumSink((BasebandSampleSink *) sampleSink); }
void setChannel(ChannelAPI *channel);
signals: signals:
/** /**

@ -28,7 +28,7 @@
const PluginDescriptor SSBModPlugin::m_pluginDescriptor = { const PluginDescriptor SSBModPlugin::m_pluginDescriptor = {
SSBMod::m_channelId, SSBMod::m_channelId,
QStringLiteral("SSB Modulator"), QStringLiteral("SSB Modulator"),
QStringLiteral("6.3.3"), QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,

@ -19,6 +19,10 @@
#include "dsp/basebandsamplesink.h" #include "dsp/basebandsamplesink.h"
#include "dsp/misc.h" #include "dsp/misc.h"
#include "dsp/datafifo.h"
#include "util/messagequeue.h"
#include "maincore.h"
#include "ssbmodsource.h" #include "ssbmodsource.h"
const int SSBModSource::m_ssbFftLen = 1024; const int SSBModSource::m_ssbFftLen = 1024;
@ -51,6 +55,9 @@ SSBModSource::SSBModSource() :
m_feedbackAudioBuffer.resize(1<<14); m_feedbackAudioBuffer.resize(1<<14);
m_feedbackAudioBufferFill = 0; m_feedbackAudioBufferFill = 0;
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
m_sum.real(0.0f); m_sum.real(0.0f);
m_sum.imag(0.0f); m_sum.imag(0.0f);
m_undersampleCount = 0; m_undersampleCount = 0;
@ -163,6 +170,26 @@ void SSBModSource::modulateSample()
} }
calculateLevel(m_modSample); calculateLevel(m_modSample);
// take projection on real axis
m_demodBuffer[m_demodBufferFill] = m_modSample.real() * std::numeric_limits<int16_t>::max();
++m_demodBufferFill;
if (m_demodBufferFill >= m_demodBuffer.size())
{
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::iterator it = dataFifos->begin();
for (; it != dataFifos->end(); ++it) {
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
}
}
m_demodBufferFill = 0;
}
} }
void SSBModSource::pullAF(Complex& sample) void SSBModSource::pullAF(Complex& sample)
@ -574,6 +601,19 @@ void SSBModSource::applyAudioSampleRate(int sampleRate)
m_audioSampleRate = sampleRate; m_audioSampleRate = sampleRate;
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate); applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
QList<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate);
(*it)->push(msg);
}
}
} }
void SSBModSource::applyFeedbackAudioSampleRate(int sampleRate) void SSBModSource::applyFeedbackAudioSampleRate(int sampleRate)

@ -20,6 +20,7 @@
#include <QObject> #include <QObject>
#include <QMutex> #include <QMutex>
#include <QVector>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@ -36,6 +37,7 @@
#include "ssbmodsettings.h" #include "ssbmodsettings.h"
class BasebandSampleSink; class BasebandSampleSink;
class ChannelAPI;
class SSBModSource : public QObject, public ChannelSampleSource class SSBModSource : public QObject, public ChannelSampleSource
{ {
@ -55,6 +57,7 @@ public:
void applyFeedbackAudioSampleRate(int sampleRate); void applyFeedbackAudioSampleRate(int sampleRate);
int getAudioSampleRate() const { return m_audioSampleRate; } int getAudioSampleRate() const { return m_audioSampleRate; }
int getFeedbackAudioSampleRate() const { return m_feedbackAudioSampleRate; } int getFeedbackAudioSampleRate() const { return m_feedbackAudioSampleRate; }
void setChannel(ChannelAPI *channel) { m_channel = channel; }
CWKeyer& getCWKeyer() { return m_cwKeyer; } CWKeyer& getCWKeyer() { return m_cwKeyer; }
double getMagSq() const { return m_magsq; } double getMagSq() const { return m_magsq; }
void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const
@ -71,6 +74,7 @@ private:
int m_channelSampleRate; int m_channelSampleRate;
int m_channelFrequencyOffset; int m_channelFrequencyOffset;
SSBModSettings m_settings; SSBModSettings m_settings;
ChannelAPI *m_channel;
NCOF m_carrierNco; NCOF m_carrierNco;
NCOF m_toneNco; NCOF m_toneNco;
@ -86,6 +90,9 @@ private:
Real m_feedbackInterpolatorDistanceRemain; Real m_feedbackInterpolatorDistanceRemain;
bool m_feedbackInterpolatorConsumed; bool m_feedbackInterpolatorConsumed;
QVector<qint16> m_demodBuffer;
int m_demodBufferFill;
fftfilt* m_SSBFilter; fftfilt* m_SSBFilter;
fftfilt* m_DSBFilter; fftfilt* m_DSBFilter;
Complex* m_SSBFilterBuffer; Complex* m_SSBFilterBuffer;

@ -64,6 +64,7 @@ WFMMod::WFMMod(DeviceAPI *deviceAPI) :
m_thread = new QThread(this); m_thread = new QThread(this);
m_basebandSource = new WFMModBaseband(); m_basebandSource = new WFMModBaseband();
m_basebandSource->setInputFileStream(&m_ifstream); m_basebandSource->setInputFileStream(&m_ifstream);
m_basebandSource->setChannel(this);
m_basebandSource->moveToThread(m_thread); m_basebandSource->moveToThread(m_thread);
applySettings(m_settings, true); applySettings(m_settings, true);

@ -61,6 +61,11 @@ void WFMModBaseband::reset()
m_sampleFifo.reset(); m_sampleFifo.reset();
} }
void WFMModBaseband::setChannel(ChannelAPI *channel)
{
m_source.setChannel(channel);
}
void WFMModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples) void WFMModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples)
{ {
unsigned int part1Begin, part1End, part2Begin, part2End; unsigned int part1Begin, part1End, part2Begin, part2End;
@ -209,4 +214,4 @@ void WFMModBaseband::applySettings(const WFMModSettings& settings, bool force)
int WFMModBaseband::getChannelSampleRate() const int WFMModBaseband::getChannelSampleRate() const
{ {
return m_channelizer->getChannelSampleRate(); return m_channelizer->getChannelSampleRate();
} }

@ -28,6 +28,7 @@
#include "wfmmodsource.h" #include "wfmmodsource.h"
class UpChannelizer; class UpChannelizer;
class ChannelAPI;
class WFMModBaseband : public QObject class WFMModBaseband : public QObject
{ {
@ -68,6 +69,7 @@ public:
int getChannelSampleRate() const; int getChannelSampleRate() const;
void setInputFileStream(std::ifstream *ifstream) { m_source.setInputFileStream(ifstream); } void setInputFileStream(std::ifstream *ifstream) { m_source.setInputFileStream(ifstream); }
AudioFifo *getAudioFifo() { return m_source.getAudioFifo(); } AudioFifo *getAudioFifo() { return m_source.getAudioFifo(); }
void setChannel(ChannelAPI *channel);
signals: signals:
/** /**

@ -28,7 +28,7 @@
const PluginDescriptor WFMModPlugin::m_pluginDescriptor = { const PluginDescriptor WFMModPlugin::m_pluginDescriptor = {
WFMMod::m_channelId, WFMMod::m_channelId,
QStringLiteral("WFM Modulator"), QStringLiteral("WFM Modulator"),
QStringLiteral("6.3.3"), QStringLiteral("6.4.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,

@ -16,6 +16,10 @@
#include <QDebug> #include <QDebug>
#include "dsp/datafifo.h"
#include "util/messagequeue.h"
#include "maincore.h"
#include "wfmmodsource.h" #include "wfmmodsource.h"
const int WFMModSource::m_rfFilterFFTLength = 1024; const int WFMModSource::m_rfFilterFFTLength = 1024;
@ -46,6 +50,8 @@ WFMModSource::WFMModSource() :
m_magsq = 0.0; m_magsq = 0.0;
m_feedbackAudioBuffer.resize(1<<14); m_feedbackAudioBuffer.resize(1<<14);
m_feedbackAudioBufferFill = 0; m_feedbackAudioBufferFill = 0;
m_demodBuffer.resize(1<<12);
m_demodBufferFill = 0;
applySettings(m_settings, true); applySettings(m_settings, true);
applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true);
@ -140,6 +146,25 @@ void WFMModSource::pullOne(Sample& sample)
sample.m_real = (FixReal) ci.real(); sample.m_real = (FixReal) ci.real();
sample.m_imag = (FixReal) ci.imag(); sample.m_imag = (FixReal) ci.imag();
m_demodBuffer[m_demodBufferFill] = t * std::numeric_limits<int16_t>::max();
++m_demodBufferFill;
if (m_demodBufferFill >= m_demodBuffer.size())
{
QList<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::iterator it = dataFifos->begin();
for (; it != dataFifos->end(); ++it) {
(*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16));
}
}
m_demodBufferFill = 0;
}
} }
void WFMModSource::modulateAudio() void WFMModSource::modulateAudio()
@ -237,13 +262,13 @@ void WFMModSource::pullAF(Real& sample)
if (m_cwKeyer.getSample()) if (m_cwKeyer.getSample())
{ {
m_cwKeyer.getCWSmoother().getFadeSample(true, fadeFactor); m_cwKeyer.getCWSmoother().getFadeSample(true, fadeFactor);
sample = m_cwToneNco.next() * m_settings.m_volumeFactor * fadeFactor; sample = m_cwToneNco.next() * m_settings.m_volumeFactor * fadeFactor * 0.99f;
} }
else else
{ {
if (m_cwKeyer.getCWSmoother().getFadeSample(false, fadeFactor)) if (m_cwKeyer.getCWSmoother().getFadeSample(false, fadeFactor))
{ {
sample = m_cwToneNco.next() * m_settings.m_volumeFactor * fadeFactor; sample = m_cwToneNco.next() * m_settings.m_volumeFactor * fadeFactor * 0.99f;
} }
else else
{ {
@ -339,6 +364,19 @@ void WFMModSource::applyAudioSampleRate(int sampleRate)
m_cwKeyer.reset(); m_cwKeyer.reset();
m_audioSampleRate = sampleRate; m_audioSampleRate = sampleRate;
applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate); applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate);
QList<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate);
(*it)->push(msg);
}
}
} }
void WFMModSource::applyFeedbackAudioSampleRate(int sampleRate) void WFMModSource::applyFeedbackAudioSampleRate(int sampleRate)

@ -20,6 +20,7 @@
#include <QObject> #include <QObject>
#include <QMutex> #include <QMutex>
#include <QVector>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@ -35,6 +36,8 @@
#include "wfmmodsettings.h" #include "wfmmodsettings.h"
class ChannelAPI;
class WFMModSource : public QObject, public ChannelSampleSource class WFMModSource : public QObject, public ChannelSampleSource
{ {
Q_OBJECT Q_OBJECT
@ -53,6 +56,7 @@ public:
void applyFeedbackAudioSampleRate(int sampleRate); void applyFeedbackAudioSampleRate(int sampleRate);
int getAudioSampleRate() const { return m_audioSampleRate; } int getAudioSampleRate() const { return m_audioSampleRate; }
int getFeedbackAudioSampleRate() const { return m_feedbackAudioSampleRate; } int getFeedbackAudioSampleRate() const { return m_feedbackAudioSampleRate; }
void setChannel(ChannelAPI *channel) { m_channel = channel; }
CWKeyer& getCWKeyer() { return m_cwKeyer; } CWKeyer& getCWKeyer() { return m_cwKeyer; }
double getMagSq() const { return m_magsq; } double getMagSq() const { return m_magsq; }
void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const
@ -68,6 +72,7 @@ private:
int m_channelSampleRate; int m_channelSampleRate;
int m_channelFrequencyOffset; int m_channelFrequencyOffset;
WFMModSettings m_settings; WFMModSettings m_settings;
ChannelAPI *m_channel;
NCO m_carrierNco; NCO m_carrierNco;
NCOF m_toneNco; NCOF m_toneNco;
@ -85,6 +90,9 @@ private:
Real m_feedbackInterpolatorDistanceRemain; Real m_feedbackInterpolatorDistanceRemain;
bool m_feedbackInterpolatorConsumed; bool m_feedbackInterpolatorConsumed;
QVector<qint16> m_demodBuffer;
int m_demodBufferFill;
fftfilt* m_rfFilter; fftfilt* m_rfFilter;
static const int m_rfFilterFFTLength; static const int m_rfFilterFFTLength;
fftfilt::cmplx *m_rfFilterBuffer; fftfilt::cmplx *m_rfFilterBuffer;

@ -27,6 +27,12 @@ const QStringList DemodAnalyzerSettings::m_channelTypes = {
QStringLiteral("AMMod"), QStringLiteral("AMMod"),
QStringLiteral("DSDDemod"), QStringLiteral("DSDDemod"),
QStringLiteral("NFMDemod"), QStringLiteral("NFMDemod"),
QStringLiteral("NFMMod"),
QStringLiteral("PacketMod"),
QStringLiteral("SSBDemod"),
QStringLiteral("SSBMod"),
QStringLiteral("WFMDemod"),
QStringLiteral("WFMMod"),
}; };
const QStringList DemodAnalyzerSettings::m_channelURIs = { const QStringList DemodAnalyzerSettings::m_channelURIs = {
@ -34,6 +40,12 @@ const QStringList DemodAnalyzerSettings::m_channelURIs = {
QStringLiteral("sdrangel.channeltx.modam"), QStringLiteral("sdrangel.channeltx.modam"),
QStringLiteral("sdrangel.channel.dsddemod"), QStringLiteral("sdrangel.channel.dsddemod"),
QStringLiteral("sdrangel.channel.nfmdemod"), QStringLiteral("sdrangel.channel.nfmdemod"),
QStringLiteral("sdrangel.channeltx.modnfm"),
QStringLiteral("sdrangel.channeltx.modpacket"),
QStringLiteral("sdrangel.channel.ssbdemod"),
QStringLiteral("sdrangel.channeltx.modssb"),
QStringLiteral("sdrangel.channel.wfmdemod"),
QStringLiteral("sdrangel.channeltx.modwfm"),
}; };
DemodAnalyzerSettings::DemodAnalyzerSettings() : DemodAnalyzerSettings::DemodAnalyzerSettings() :