1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-08-31 20:27:52 -04:00

WFM modulator: use settings in modulator (1)

This commit is contained in:
f4exb 2017-10-13 13:44:07 +02:00
parent 024814e997
commit e76c95f7a2
2 changed files with 921 additions and 835 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,355 +1,382 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB // // Copyright (C) 2016 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 PLUGINS_CHANNELTX_MODWFM_WFMMOD_H_ #ifndef PLUGINS_CHANNELTX_MODWFM_WFMMOD_H_
#define PLUGINS_CHANNELTX_MODWFM_WFMMOD_H_ #define PLUGINS_CHANNELTX_MODWFM_WFMMOD_H_
#include <QMutex> #include <QMutex>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include "dsp/basebandsamplesource.h" #include "dsp/basebandsamplesource.h"
#include "dsp/nco.h" #include "dsp/nco.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/movingaverage.h" #include "dsp/movingaverage.h"
#include "dsp/agc.h" #include "dsp/agc.h"
#include "dsp/cwkeyer.h" #include "dsp/cwkeyer.h"
#include "audio/audiofifo.h" #include "audio/audiofifo.h"
#include "util/message.h" #include "util/message.h"
class WFMMod : public BasebandSampleSource { #include "wfmmodsettings.h"
Q_OBJECT
class WFMMod : public BasebandSampleSource {
public: Q_OBJECT
typedef enum
{ public:
WFMModInputNone, typedef enum
WFMModInputTone, {
WFMModInputFile, WFMModInputNone,
WFMModInputAudio, WFMModInputTone,
WFMModInputCWTone WFMModInputFile,
} WFMModInputAF; WFMModInputAudio,
WFMModInputCWTone
class MsgConfigureFileSourceName : public Message } WFMModInputAF;
{
MESSAGE_CLASS_DECLARATION class MsgConfigureWFMMod : public Message {
MESSAGE_CLASS_DECLARATION
public:
const QString& getFileName() const { return m_fileName; } public:
const WFMModSettings& getSettings() const { return m_settings; }
static MsgConfigureFileSourceName* create(const QString& fileName) bool getForce() const { return m_force; }
{
return new MsgConfigureFileSourceName(fileName); static MsgConfigureWFMMod* create(const WFMModSettings& settings, bool force)
} {
return new MsgConfigureWFMMod(settings, force);
private: }
QString m_fileName;
private:
MsgConfigureFileSourceName(const QString& fileName) : WFMModSettings m_settings;
Message(), bool m_force;
m_fileName(fileName)
{ } MsgConfigureWFMMod(const WFMModSettings& settings, bool force) :
}; Message(),
m_settings(settings),
class MsgConfigureFileSourceSeek : public Message m_force(force)
{ { }
MESSAGE_CLASS_DECLARATION };
public: class MsgConfigureFileSourceName : public Message
int getPercentage() const { return m_seekPercentage; } {
MESSAGE_CLASS_DECLARATION
static MsgConfigureFileSourceSeek* create(int seekPercentage)
{ public:
return new MsgConfigureFileSourceSeek(seekPercentage); const QString& getFileName() const { return m_fileName; }
}
static MsgConfigureFileSourceName* create(const QString& fileName)
protected: {
int m_seekPercentage; //!< percentage of seek position from the beginning 0..100 return new MsgConfigureFileSourceName(fileName);
}
MsgConfigureFileSourceSeek(int seekPercentage) :
Message(), private:
m_seekPercentage(seekPercentage) QString m_fileName;
{ }
}; MsgConfigureFileSourceName(const QString& fileName) :
Message(),
class MsgConfigureFileSourceStreamTiming : public Message { m_fileName(fileName)
MESSAGE_CLASS_DECLARATION { }
};
public:
class MsgConfigureFileSourceSeek : public Message
static MsgConfigureFileSourceStreamTiming* create() {
{ MESSAGE_CLASS_DECLARATION
return new MsgConfigureFileSourceStreamTiming();
} public:
int getPercentage() const { return m_seekPercentage; }
private:
static MsgConfigureFileSourceSeek* create(int seekPercentage)
MsgConfigureFileSourceStreamTiming() : {
Message() return new MsgConfigureFileSourceSeek(seekPercentage);
{ } }
};
protected:
class MsgConfigureAFInput : public Message int m_seekPercentage; //!< percentage of seek position from the beginning 0..100
{
MESSAGE_CLASS_DECLARATION MsgConfigureFileSourceSeek(int seekPercentage) :
Message(),
public: m_seekPercentage(seekPercentage)
WFMModInputAF getAFInput() const { return m_afInput; } { }
};
static MsgConfigureAFInput* create(WFMModInputAF afInput)
{ class MsgConfigureFileSourceStreamTiming : public Message {
return new MsgConfigureAFInput(afInput); MESSAGE_CLASS_DECLARATION
}
public:
private:
WFMModInputAF m_afInput; static MsgConfigureFileSourceStreamTiming* create()
{
MsgConfigureAFInput(WFMModInputAF afInput) : return new MsgConfigureFileSourceStreamTiming();
Message(), }
m_afInput(afInput)
{ } private:
};
MsgConfigureFileSourceStreamTiming() :
class MsgReportFileSourceStreamTiming : public Message Message()
{ { }
MESSAGE_CLASS_DECLARATION };
public: class MsgConfigureAFInput : public Message
std::size_t getSamplesCount() const { return m_samplesCount; } {
MESSAGE_CLASS_DECLARATION
static MsgReportFileSourceStreamTiming* create(std::size_t samplesCount)
{ public:
return new MsgReportFileSourceStreamTiming(samplesCount); WFMModInputAF getAFInput() const { return m_afInput; }
}
static MsgConfigureAFInput* create(WFMModInputAF afInput)
protected: {
std::size_t m_samplesCount; return new MsgConfigureAFInput(afInput);
}
MsgReportFileSourceStreamTiming(std::size_t samplesCount) :
Message(), private:
m_samplesCount(samplesCount) WFMModInputAF m_afInput;
{ }
}; MsgConfigureAFInput(WFMModInputAF afInput) :
Message(),
class MsgReportFileSourceStreamData : public Message { m_afInput(afInput)
MESSAGE_CLASS_DECLARATION { }
};
public:
int getSampleRate() const { return m_sampleRate; } class MsgReportFileSourceStreamTiming : public Message
quint32 getRecordLength() const { return m_recordLength; } {
MESSAGE_CLASS_DECLARATION
static MsgReportFileSourceStreamData* create(int sampleRate,
quint32 recordLength) public:
{ std::size_t getSamplesCount() const { return m_samplesCount; }
return new MsgReportFileSourceStreamData(sampleRate, recordLength);
} static MsgReportFileSourceStreamTiming* create(std::size_t samplesCount)
{
protected: return new MsgReportFileSourceStreamTiming(samplesCount);
int m_sampleRate; }
quint32 m_recordLength;
protected:
MsgReportFileSourceStreamData(int sampleRate, std::size_t m_samplesCount;
quint32 recordLength) :
Message(), MsgReportFileSourceStreamTiming(std::size_t samplesCount) :
m_sampleRate(sampleRate), Message(),
m_recordLength(recordLength) m_samplesCount(samplesCount)
{ } { }
}; };
//================================================================= class MsgReportFileSourceStreamData : public Message {
MESSAGE_CLASS_DECLARATION
WFMMod();
~WFMMod(); public:
int getSampleRate() const { return m_sampleRate; }
void configure(MessageQueue* messageQueue, quint32 getRecordLength() const { return m_recordLength; }
Real rfBandwidth,
Real afBandwidth, static MsgReportFileSourceStreamData* create(int sampleRate,
float fmDeviation, quint32 recordLength)
float toneFrequency, {
float volumeFactor, return new MsgReportFileSourceStreamData(sampleRate, recordLength);
bool audioMute, }
bool playLoop);
protected:
virtual void pull(Sample& sample); int m_sampleRate;
virtual void pullAudio(int nbSamples); quint32 m_recordLength;
virtual void start();
virtual void stop(); MsgReportFileSourceStreamData(int sampleRate,
virtual bool handleMessage(const Message& cmd); quint32 recordLength) :
Message(),
double getMagSq() const { return m_magsq; } m_sampleRate(sampleRate),
m_recordLength(recordLength)
CWKeyer *getCWKeyer() { return &m_cwKeyer; } { }
};
signals:
/** //=================================================================
* Level changed
* \param rmsLevel RMS level in range 0.0 - 1.0 WFMMod();
* \param peakLevel Peak level in range 0.0 - 1.0 ~WFMMod();
* \param numSamples Number of audio samples analyzed
*/ void configure(MessageQueue* messageQueue,
void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples); Real rfBandwidth,
Real afBandwidth,
float fmDeviation,
private: float toneFrequency,
class MsgConfigureWFMMod : public Message float volumeFactor,
{ bool audioMute,
MESSAGE_CLASS_DECLARATION bool playLoop);
public: virtual void pull(Sample& sample);
Real getRFBandwidth() const { return m_rfBandwidth; } virtual void pullAudio(int nbSamples);
Real getAFBandwidth() const { return m_afBandwidth; } virtual void start();
float getFMDeviation() const { return m_fmDeviation; } virtual void stop();
float getToneFrequency() const { return m_toneFrequency; } virtual bool handleMessage(const Message& cmd);
float getVolumeFactor() const { return m_volumeFactor; }
bool getChannelMute() const { return m_channelMute; } double getMagSq() const { return m_magsq; }
bool getPlayLoop() const { return m_playLoop; }
CWKeyer *getCWKeyer() { return &m_cwKeyer; }
static MsgConfigureWFMMod* create(Real rfBandwidth,
Real afBandwidth, signals:
float fmDeviation, /**
float toneFrequency, * Level changed
float volumeFactor, * \param rmsLevel RMS level in range 0.0 - 1.0
bool channelMute, * \param peakLevel Peak level in range 0.0 - 1.0
bool playLoop) * \param numSamples Number of audio samples analyzed
{ */
return new MsgConfigureWFMMod(rfBandwidth, void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples);
afBandwidth,
fmDeviation,
toneFrequency, private:
volumeFactor, class MsgConfigureWFMModPrivate : public Message
channelMute, {
playLoop); MESSAGE_CLASS_DECLARATION
}
public:
private: Real getRFBandwidth() const { return m_rfBandwidth; }
Real m_rfBandwidth; Real getAFBandwidth() const { return m_afBandwidth; }
Real m_afBandwidth; float getFMDeviation() const { return m_fmDeviation; }
float m_fmDeviation; float getToneFrequency() const { return m_toneFrequency; }
float m_toneFrequency; float getVolumeFactor() const { return m_volumeFactor; }
float m_volumeFactor; bool getChannelMute() const { return m_channelMute; }
bool m_channelMute; bool getPlayLoop() const { return m_playLoop; }
bool m_playLoop;
static MsgConfigureWFMModPrivate* create(Real rfBandwidth,
MsgConfigureWFMMod(Real rfBandwidth, Real afBandwidth,
Real afBandwidth, float fmDeviation,
float fmDeviation, float toneFrequency,
float toneFrequency, float volumeFactor,
float volumeFactor, bool channelMute,
bool channelMute, bool playLoop)
bool playLoop) : {
Message(), return new MsgConfigureWFMModPrivate(rfBandwidth,
m_rfBandwidth(rfBandwidth), afBandwidth,
m_afBandwidth(afBandwidth), fmDeviation,
m_fmDeviation(fmDeviation), toneFrequency,
m_toneFrequency(toneFrequency), volumeFactor,
m_volumeFactor(volumeFactor), channelMute,
m_channelMute(channelMute), playLoop);
m_playLoop(playLoop) }
{ }
}; private:
Real m_rfBandwidth;
//================================================================= Real m_afBandwidth;
float m_fmDeviation;
enum RateState { float m_toneFrequency;
RSInitialFill, float m_volumeFactor;
RSRunning bool m_channelMute;
}; bool m_playLoop;
struct Config { MsgConfigureWFMModPrivate(Real rfBandwidth,
int m_basebandSampleRate; Real afBandwidth,
int m_outputSampleRate; float fmDeviation,
qint64 m_inputFrequencyOffset; float toneFrequency,
Real m_rfBandwidth; float volumeFactor,
Real m_afBandwidth; bool channelMute,
float m_fmDeviation; bool playLoop) :
float m_toneFrequency; Message(),
float m_volumeFactor; m_rfBandwidth(rfBandwidth),
quint32 m_audioSampleRate; m_afBandwidth(afBandwidth),
bool m_channelMute; m_fmDeviation(fmDeviation),
bool m_playLoop; m_toneFrequency(toneFrequency),
m_volumeFactor(volumeFactor),
Config() : m_channelMute(channelMute),
m_basebandSampleRate(0), m_playLoop(playLoop)
m_outputSampleRate(-1), { }
m_inputFrequencyOffset(0), };
m_rfBandwidth(-1),
m_afBandwidth(-1), //=================================================================
m_fmDeviation(5000.0f),
m_toneFrequency(1000.0f), enum RateState {
m_volumeFactor(1.0f), RSInitialFill,
m_audioSampleRate(0), RSRunning
m_channelMute(false), };
m_playLoop(false)
{ } struct Config {
}; int m_basebandSampleRate;
int m_outputSampleRate;
//================================================================= qint64 m_inputFrequencyOffset;
Real m_rfBandwidth;
Config m_config; Real m_afBandwidth;
Config m_running; float m_fmDeviation;
float m_toneFrequency;
NCO m_carrierNco; float m_volumeFactor;
NCOF m_toneNco; quint32 m_audioSampleRate;
NCOF m_toneNcoRF; bool m_channelMute;
float m_modPhasor; //!< baseband modulator phasor bool m_playLoop;
Complex m_modSample;
Interpolator m_interpolator; Config() :
Real m_interpolatorDistance; m_basebandSampleRate(0),
Real m_interpolatorDistanceRemain; m_outputSampleRate(-1),
bool m_interpolatorConsumed; m_inputFrequencyOffset(0),
m_rfBandwidth(-1),
fftfilt* m_rfFilter; m_afBandwidth(-1),
static const int m_rfFilterFFTLength; m_fmDeviation(5000.0f),
fftfilt::cmplx *m_rfFilterBuffer; m_toneFrequency(1000.0f),
int m_rfFilterBufferIndex; m_volumeFactor(1.0f),
m_audioSampleRate(0),
double m_magsq; m_channelMute(false),
MovingAverage<double> m_movingAverage; m_playLoop(false)
SimpleAGC m_volumeAGC; { }
};
AudioVector m_audioBuffer;
uint m_audioBufferFill; //=================================================================
AudioFifo m_audioFifo; Config m_config;
SampleVector m_sampleBuffer; Config m_running;
QMutex m_settingsMutex; WFMModSettings m_settings;
std::ifstream m_ifstream; NCO m_carrierNco;
QString m_fileName; NCOF m_toneNco;
quint64 m_fileSize; //!< raw file size (bytes) NCOF m_toneNcoRF;
quint32 m_recordLength; //!< record length in seconds computed from file size float m_modPhasor; //!< baseband modulator phasor
int m_sampleRate; Complex m_modSample;
Interpolator m_interpolator;
WFMModInputAF m_afInput; Real m_interpolatorDistance;
quint32 m_levelCalcCount; Real m_interpolatorDistanceRemain;
Real m_peakLevel; bool m_interpolatorConsumed;
Real m_levelSum;
CWKeyer m_cwKeyer; fftfilt* m_rfFilter;
CWSmoother m_cwSmoother; static const int m_rfFilterFFTLength;
static const int m_levelNbSamples; fftfilt::cmplx *m_rfFilterBuffer;
int m_rfFilterBufferIndex;
void apply();
void pullAF(Complex& sample); double m_magsq;
void calculateLevel(const Real& sample); MovingAverage<double> m_movingAverage;
void openFileStream(); SimpleAGC m_volumeAGC;
void seekFileStream(int seekPercentage);
}; AudioVector m_audioBuffer;
uint m_audioBufferFill;
#endif /* PLUGINS_CHANNELTX_MODWFM_WFMMOD_H_ */ AudioFifo m_audioFifo;
SampleVector m_sampleBuffer;
QMutex m_settingsMutex;
std::ifstream m_ifstream;
QString m_fileName;
quint64 m_fileSize; //!< raw file size (bytes)
quint32 m_recordLength; //!< record length in seconds computed from file size
int m_sampleRate;
WFMModInputAF m_afInput;
quint32 m_levelCalcCount;
Real m_peakLevel;
Real m_levelSum;
CWKeyer m_cwKeyer;
CWSmoother m_cwSmoother;
static const int m_levelNbSamples;
void apply();
void applySettings(const WFMModSettings& settings, bool force = false);
void pullAF(Complex& sample);
void calculateLevel(const Real& sample);
void openFileStream();
void seekFileStream(int seekPercentage);
};
#endif /* PLUGINS_CHANNELTX_MODWFM_WFMMOD_H_ */