mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-06-25 20:07:51 +02:00
new modole system
This commit is contained in:
55
radio/CMakeLists.txt
Normal file
55
radio/CMakeLists.txt
Normal file
@ -0,0 +1,55 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(radio)
|
||||
|
||||
if (MSVC)
|
||||
set(CMAKE_CXX_FLAGS "-O2 /std:c++17")
|
||||
link_directories(radio "C:/Program Files/PothosSDR/lib/")
|
||||
include_directories(radio "C:/Program Files/PothosSDR/include/volk/")
|
||||
include_directories(radio "C:/Program Files/PothosSDR/include/")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fsanitize=address -g")
|
||||
include_directories(radio "/usr/include/volk")
|
||||
link_libraries(pthread)
|
||||
link_libraries(GL)
|
||||
link_libraries(GLEW)
|
||||
link_libraries(glfw)
|
||||
link_libraries(fftw3)
|
||||
link_libraries(fftw3f)
|
||||
link_libraries(portaudio)
|
||||
link_libraries(X11)
|
||||
link_libraries(Xxf86vm)
|
||||
endif (MSVC)
|
||||
|
||||
link_libraries(volk)
|
||||
link_libraries(SoapySDR)
|
||||
|
||||
# Main code
|
||||
include_directories(radio "src/")
|
||||
include_directories(radio "../core/src/")
|
||||
include_directories(radio "../core/src/imgui")
|
||||
file(GLOB SRC "src/*.cpp")
|
||||
file(GLOB IMGUI "../core/src/imgui/*.cpp")
|
||||
add_library(radio SHARED ${SRC} ${IMGUI})
|
||||
set_target_properties(radio PROPERTIES PREFIX "")
|
||||
|
||||
if (MSVC)
|
||||
# Glew
|
||||
find_package(GLEW REQUIRED)
|
||||
target_link_libraries(radio PRIVATE GLEW::GLEW)
|
||||
|
||||
# GLFW3
|
||||
find_package(glfw3 CONFIG REQUIRED)
|
||||
target_link_libraries(radio PRIVATE glfw)
|
||||
|
||||
# FFTW3
|
||||
find_package(FFTW3 CONFIG REQUIRED)
|
||||
target_link_libraries(radio PRIVATE FFTW3::fftw3)
|
||||
find_package(FFTW3f CONFIG REQUIRED)
|
||||
target_link_libraries(radio PRIVATE FFTW3::fftw3f)
|
||||
|
||||
# PortAudio
|
||||
find_package(portaudio CONFIG REQUIRED)
|
||||
target_link_libraries(radio PRIVATE portaudio portaudio_static)
|
||||
endif (MSVC)
|
||||
|
||||
# cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/Users/Alex/vcpkg/scripts/buildsystems/vcpkg.cmake" -G "Visual Studio 15 2017 Win64"
|
135
radio/src/main.cpp
Normal file
135
radio/src/main.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
#include <imgui.h>
|
||||
#include <module.h>
|
||||
#include <path.h>
|
||||
#include <watcher.h>
|
||||
|
||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||
#define DEEMP_LIST "50µS\00075µS\000none\000"
|
||||
|
||||
mod::API_t* API;
|
||||
|
||||
struct RadioContext_t {
|
||||
std::string name;
|
||||
int demod = 1;
|
||||
int deemp = 0;
|
||||
int bandWidth;
|
||||
int bandWidthMin;
|
||||
int bandWidthMax;
|
||||
SigPath sigPath;
|
||||
};
|
||||
|
||||
MOD_EXPORT void* _INIT_(mod::API_t* _API, ImGuiContext* imctx, std::string _name) {
|
||||
API = _API;
|
||||
RadioContext_t* ctx = new RadioContext_t;
|
||||
ctx->name = _name;
|
||||
ctx->bandWidth = 200000;
|
||||
ctx->bandWidthMin = 100000;
|
||||
ctx->bandWidthMax = 200000;
|
||||
ctx->sigPath.init(_name, 200000, 1000, API->registerVFO(_name, mod::API_t::REF_CENTER, 0, 200000, 200000, 1000));
|
||||
ctx->sigPath.start();
|
||||
ImGui::SetCurrentContext(imctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
MOD_EXPORT void _NEW_FRAME_(RadioContext_t* ctx) {
|
||||
|
||||
}
|
||||
|
||||
MOD_EXPORT void _DRAW_MENU_(RadioContext_t* ctx) {
|
||||
float menuColumnWidth = ImGui::GetContentRegionAvailWidth();
|
||||
|
||||
ImGui::BeginGroup();
|
||||
|
||||
// TODO: Change VFO ref in signal path
|
||||
|
||||
ImGui::Columns(4, CONCAT("RadioModeColumns##_", ctx->name), false);
|
||||
if (ImGui::RadioButton(CONCAT("NFM##_", ctx->name), ctx->demod == 0) && ctx->demod != 0) {
|
||||
ctx->demod = 0;
|
||||
ctx->bandWidth = 16000;
|
||||
ctx->bandWidthMin = 8000;
|
||||
ctx->bandWidthMax = 16000;
|
||||
ctx->sigPath.setDemodulator(SigPath::DEMOD_NFM, ctx->bandWidth);
|
||||
API->setVFOReference(ctx->name, mod::API_t::REF_CENTER);
|
||||
}
|
||||
if (ImGui::RadioButton(CONCAT("WFM##_", ctx->name), ctx->demod == 1) && ctx->demod != 1) {
|
||||
ctx->demod = 1;
|
||||
ctx->bandWidth = 200000;
|
||||
ctx->bandWidthMin = 100000;
|
||||
ctx->bandWidthMax = 200000;
|
||||
ctx->sigPath.setDemodulator(SigPath::DEMOD_FM, ctx->bandWidth);
|
||||
API->setVFOReference(ctx->name, mod::API_t::REF_CENTER);
|
||||
}
|
||||
ImGui::NextColumn();
|
||||
if (ImGui::RadioButton(CONCAT("AM##_", ctx->name), ctx->demod == 2) && ctx->demod != 2) {
|
||||
ctx->demod = 2;
|
||||
ctx->bandWidth = 12500;
|
||||
ctx->bandWidthMin = 6250;
|
||||
ctx->bandWidthMax = 12500;
|
||||
ctx->sigPath.setDemodulator(SigPath::DEMOD_AM, ctx->bandWidth);
|
||||
API->setVFOReference(ctx->name, mod::API_t::REF_CENTER);
|
||||
}
|
||||
if (ImGui::RadioButton(CONCAT("DSB##_", ctx->name), ctx->demod == 3) && ctx->demod != 3) {
|
||||
ctx->demod = 3;
|
||||
ctx->bandWidth = 6000;
|
||||
ctx->bandWidthMin = 3000;
|
||||
ctx->bandWidthMax = 6000;
|
||||
ctx->sigPath.setDemodulator(SigPath::DEMOD_DSB, ctx->bandWidth);
|
||||
API->setVFOReference(ctx->name, mod::API_t::REF_CENTER);
|
||||
}
|
||||
ImGui::NextColumn();
|
||||
if (ImGui::RadioButton(CONCAT("USB##_", ctx->name), ctx->demod == 4) && ctx->demod != 4) {
|
||||
ctx->demod = 4;
|
||||
ctx->bandWidth = 3000;
|
||||
ctx->bandWidthMin = 1500;
|
||||
ctx->bandWidthMax = 3000;
|
||||
ctx->sigPath.setDemodulator(SigPath::DEMOD_USB, ctx->bandWidth);
|
||||
API->setVFOReference(ctx->name, mod::API_t::REF_LOWER);
|
||||
}
|
||||
if (ImGui::RadioButton(CONCAT("CW##_", ctx->name), ctx->demod == 5) && ctx->demod != 5) { ctx->demod = 5; };
|
||||
ImGui::NextColumn();
|
||||
if (ImGui::RadioButton(CONCAT("LSB##_", ctx->name), ctx->demod == 6) && ctx->demod != 6) {
|
||||
ctx->demod = 6;
|
||||
ctx->bandWidth = 3000;
|
||||
ctx->bandWidthMin = 1500;
|
||||
ctx->bandWidthMax = 3000;
|
||||
ctx->sigPath.setDemodulator(SigPath::DEMOD_LSB, ctx->bandWidth);
|
||||
API->setVFOReference(ctx->name, mod::API_t::REF_UPPER);
|
||||
}
|
||||
if (ImGui::RadioButton(CONCAT("RAW##_", ctx->name), ctx->demod == 7) && ctx->demod != 7) {
|
||||
ctx->demod = 7;
|
||||
ctx->bandWidth = 10000;
|
||||
ctx->bandWidthMin = 3000;
|
||||
ctx->bandWidthMax = 10000;
|
||||
ctx->sigPath.setDemodulator(SigPath::DEMOD_RAW, ctx->bandWidth);
|
||||
API->setVFOReference(ctx->name, mod::API_t::REF_CENTER);
|
||||
};
|
||||
ImGui::Columns(1, CONCAT("EndRadioModeColumns##_", ctx->name), false);
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
ImGui::Text("WFM Deemphasis");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(menuColumnWidth - ImGui::GetCursorPosX());
|
||||
if (ImGui::Combo(CONCAT("##_deemp_select_", ctx->name), &ctx->deemp, DEEMP_LIST)) {
|
||||
ctx->sigPath.setDeemphasis(ctx->deemp);
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::Text("Bandwidth");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(menuColumnWidth - ImGui::GetCursorPosX());
|
||||
if (ImGui::InputInt(CONCAT("##_bw_select_", ctx->name), &ctx->bandWidth, 100, 1000)) {
|
||||
ctx->bandWidth = std::clamp<int>(ctx->bandWidth, ctx->bandWidthMin, ctx->bandWidthMax);
|
||||
ctx->sigPath.setBandwidth(ctx->bandWidth);
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
MOD_EXPORT void _HANDLE_EVENT_(RadioContext_t* ctx, int eventId) {
|
||||
|
||||
}
|
||||
|
||||
MOD_EXPORT void _STOP_(RadioContext_t* ctx) {
|
||||
API->removeVFO(ctx->name);
|
||||
delete ctx;
|
||||
}
|
244
radio/src/path.cpp
Normal file
244
radio/src/path.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
#include <path.h>
|
||||
|
||||
SigPath::SigPath() {
|
||||
|
||||
}
|
||||
|
||||
int SigPath::sampleRateChangeHandler(void* ctx, float sampleRate) {
|
||||
SigPath* _this = (SigPath*)ctx;
|
||||
_this->outputSampleRate = sampleRate;
|
||||
_this->audioResamp.stop();
|
||||
_this->deemp.stop();
|
||||
float bw = std::min<float>(_this->bandwidth, sampleRate / 2.0f);
|
||||
_this->audioResamp.setOutputSampleRate(sampleRate, bw, bw);
|
||||
_this->deemp.setBlockSize(_this->audioResamp.getOutputBlockSize());
|
||||
_this->deemp.setSamplerate(sampleRate);
|
||||
_this->audioResamp.start();
|
||||
_this->deemp.start();
|
||||
return _this->audioResamp.getOutputBlockSize();
|
||||
}
|
||||
|
||||
void SigPath::init(std::string vfoName, uint64_t sampleRate, int blockSize, dsp::stream<dsp::complex_t>* input) {
|
||||
this->sampleRate = sampleRate;
|
||||
this->blockSize = blockSize;
|
||||
this->vfoName = vfoName;
|
||||
|
||||
_demod = DEMOD_FM;
|
||||
_deemp = DEEMP_50US;
|
||||
bandwidth = 200000;
|
||||
|
||||
// TODO: Set default VFO options
|
||||
// TODO: ajust deemphasis for different output sample rates
|
||||
// TODO: Add a mono to stereo for different modes
|
||||
|
||||
demod.init(input, 100000, 200000, 800);
|
||||
amDemod.init(input, 50);
|
||||
ssbDemod.init(input, 6000, 3000, 22);
|
||||
cpx2stereo.init(input, 22);
|
||||
|
||||
audioResamp.init(&demod.output, 200000, 48000, 800);
|
||||
deemp.init(&audioResamp.output, 800, 50e-6, 48000);
|
||||
outputSampleRate = API->registerMonoStream(&deemp.output, vfoName, vfoName, sampleRateChangeHandler, this);
|
||||
API->setBlockSize(vfoName, audioResamp.getOutputBlockSize());
|
||||
|
||||
setDemodulator(_demod, bandwidth);
|
||||
}
|
||||
|
||||
void SigPath::setSampleRate(float sampleRate) {
|
||||
this->sampleRate = sampleRate;
|
||||
|
||||
// Reset the demodulator and audio systems
|
||||
setDemodulator(_demod, bandwidth);
|
||||
}
|
||||
|
||||
void SigPath::setDemodulator(int demId, float bandWidth) {
|
||||
if (demId < 0 || demId >= _DEMOD_COUNT) {
|
||||
return;
|
||||
}
|
||||
|
||||
audioResamp.stop();
|
||||
deemp.stop();
|
||||
|
||||
bandwidth = bandWidth;
|
||||
|
||||
// Stop current demodulator
|
||||
if (_demod == DEMOD_FM) {
|
||||
demod.stop();
|
||||
}
|
||||
else if (_demod == DEMOD_NFM) {
|
||||
demod.stop();
|
||||
}
|
||||
else if (_demod == DEMOD_AM) {
|
||||
amDemod.stop();
|
||||
}
|
||||
else if (_demod == DEMOD_USB) {
|
||||
ssbDemod.stop();
|
||||
}
|
||||
else if (_demod == DEMOD_LSB) {
|
||||
ssbDemod.stop();
|
||||
}
|
||||
else if (_demod == DEMOD_DSB) {
|
||||
ssbDemod.stop();
|
||||
}
|
||||
else if (_demod == DEMOD_RAW) {
|
||||
cpx2stereo.stop();
|
||||
}
|
||||
else {
|
||||
spdlog::error("UNIMPLEMENTED DEMODULATOR IN SigPath::setDemodulator (stop)");
|
||||
}
|
||||
_demod = demId;
|
||||
|
||||
// Set input of the audio resampler
|
||||
// TODO: Set bandwidth from argument
|
||||
if (demId == DEMOD_FM) {
|
||||
API->setVFOSampleRate(vfoName, 200000, bandwidth);
|
||||
demod.setBlockSize(API->getVFOOutputBlockSize(vfoName));
|
||||
demod.setSampleRate(200000);
|
||||
demod.setDeviation(bandwidth / 2.0f);
|
||||
audioResamp.setInput(&demod.output);
|
||||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(200000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw);
|
||||
deemp.bypass = (_deemp == DEEMP_NONE);
|
||||
demod.start();
|
||||
}
|
||||
else if (demId == DEMOD_NFM) {
|
||||
API->setVFOSampleRate(vfoName, 16000, bandwidth);
|
||||
demod.setBlockSize(API->getVFOOutputBlockSize(vfoName));
|
||||
demod.setSampleRate(16000);
|
||||
demod.setDeviation(bandwidth / 2.0f);
|
||||
audioResamp.setInput(&demod.output);
|
||||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(16000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw);
|
||||
deemp.bypass = true;
|
||||
demod.start();
|
||||
}
|
||||
else if (demId == DEMOD_AM) {
|
||||
API->setVFOSampleRate(vfoName, 12500, bandwidth);
|
||||
amDemod.setBlockSize(API->getVFOOutputBlockSize(vfoName));
|
||||
audioResamp.setInput(&amDemod.output);
|
||||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(12500, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw);
|
||||
deemp.bypass = true;
|
||||
amDemod.start();
|
||||
}
|
||||
else if (demId == DEMOD_USB) {
|
||||
API->setVFOSampleRate(vfoName, 6000, bandwidth);
|
||||
ssbDemod.setBlockSize(API->getVFOOutputBlockSize(vfoName));
|
||||
ssbDemod.setMode(dsp::SSBDemod::MODE_USB);
|
||||
audioResamp.setInput(&ssbDemod.output);
|
||||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(6000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw);
|
||||
deemp.bypass = true;
|
||||
ssbDemod.start();
|
||||
}
|
||||
else if (demId == DEMOD_LSB) {
|
||||
API->setVFOSampleRate(vfoName, 6000, bandwidth);
|
||||
ssbDemod.setBlockSize(API->getVFOOutputBlockSize(vfoName));
|
||||
ssbDemod.setMode(dsp::SSBDemod::MODE_LSB);
|
||||
audioResamp.setInput(&ssbDemod.output);
|
||||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(6000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw);
|
||||
deemp.bypass = true;
|
||||
ssbDemod.start();
|
||||
}
|
||||
else if (demId == DEMOD_DSB) {
|
||||
API->setVFOSampleRate(vfoName, 6000, bandwidth);
|
||||
ssbDemod.setBlockSize(API->getVFOOutputBlockSize(vfoName));
|
||||
ssbDemod.setMode(dsp::SSBDemod::MODE_DSB);
|
||||
audioResamp.setInput(&ssbDemod.output);
|
||||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(6000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw);
|
||||
deemp.bypass = true;
|
||||
ssbDemod.start();
|
||||
}
|
||||
else if (demId == DEMOD_RAW) {
|
||||
API->setVFOSampleRate(vfoName, 10000, bandwidth);
|
||||
cpx2stereo.setBlockSize(API->getVFOOutputBlockSize(vfoName));
|
||||
//audioResamp.setInput(&cpx2stereo.output);
|
||||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(10000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw);
|
||||
cpx2stereo.start();
|
||||
}
|
||||
else {
|
||||
spdlog::error("UNIMPLEMENTED DEMODULATOR IN SigPath::setDemodulator (start): {0}", demId);
|
||||
}
|
||||
|
||||
deemp.setBlockSize(audioResamp.getOutputBlockSize());
|
||||
|
||||
audioResamp.start();
|
||||
deemp.start();
|
||||
}
|
||||
|
||||
void SigPath::updateBlockSize() {
|
||||
setDemodulator(_demod, bandwidth);
|
||||
}
|
||||
|
||||
void SigPath::setDeemphasis(int deemph) {
|
||||
_deemp = deemph;
|
||||
deemp.stop();
|
||||
if (_deemp == DEEMP_NONE) {
|
||||
deemp.bypass = true;
|
||||
}
|
||||
else if (_deemp == DEEMP_50US) {
|
||||
deemp.bypass = false;
|
||||
deemp.setTau(50e-6);
|
||||
}
|
||||
else if (_deemp == DEEMP_75US) {
|
||||
deemp.bypass = false;
|
||||
deemp.setTau(75e-6);
|
||||
}
|
||||
deemp.start();
|
||||
}
|
||||
|
||||
void SigPath::setBandwidth(float bandWidth) {
|
||||
bandwidth = bandWidth;
|
||||
API->setVFOBandwidth(vfoName, bandwidth);
|
||||
if (_demod == DEMOD_FM) {
|
||||
demod.stop();
|
||||
demod.setDeviation(bandwidth / 2.0f);
|
||||
demod.start();
|
||||
}
|
||||
else if (_demod == DEMOD_NFM) {
|
||||
demod.stop();
|
||||
demod.setDeviation(bandwidth / 2.0f);
|
||||
demod.start();
|
||||
}
|
||||
else if (_demod == DEMOD_AM) {
|
||||
// Notbing to change
|
||||
}
|
||||
else if (_demod == DEMOD_USB) {
|
||||
ssbDemod.stop();
|
||||
ssbDemod.setBandwidth(bandwidth);
|
||||
ssbDemod.start();
|
||||
}
|
||||
else if (_demod == DEMOD_LSB) {
|
||||
ssbDemod.stop();
|
||||
ssbDemod.setBandwidth(bandwidth);
|
||||
ssbDemod.start();
|
||||
}
|
||||
else if (_demod == DEMOD_DSB) {
|
||||
ssbDemod.stop();
|
||||
ssbDemod.setBandwidth(bandwidth);
|
||||
ssbDemod.start();
|
||||
}
|
||||
else if (_demod == DEMOD_RAW) {
|
||||
// Notbing to change
|
||||
}
|
||||
else {
|
||||
spdlog::error("UNIMPLEMENTED DEMODULATOR IN SigPath::setBandwidth");
|
||||
}
|
||||
float _audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
if (audioBw != _audioBw) {
|
||||
audioBw = _audioBw;
|
||||
audioResamp.stop();
|
||||
audioResamp.setInputSampleRate(6000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw);
|
||||
audioResamp.start();
|
||||
}
|
||||
}
|
||||
|
||||
void SigPath::start() {
|
||||
demod.start();
|
||||
audioResamp.start();
|
||||
deemp.start();
|
||||
API->startStream(vfoName);
|
||||
}
|
71
radio/src/path.h
Normal file
71
radio/src/path.h
Normal file
@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
#include <dsp/filter.h>
|
||||
#include <dsp/resampling.h>
|
||||
#include <dsp/source.h>
|
||||
#include <dsp/math.h>
|
||||
#include <dsp/demodulator.h>
|
||||
#include <dsp/routing.h>
|
||||
#include <dsp/sink.h>
|
||||
#include <dsp/correction.h>
|
||||
#include <dsp/vfo.h>
|
||||
#include <io/audio.h>
|
||||
#include <module.h>
|
||||
|
||||
class SigPath {
|
||||
public:
|
||||
SigPath();
|
||||
void init(std::string vfoName, uint64_t sampleRate, int blockSize, dsp::stream<dsp::complex_t>* input);
|
||||
void start();
|
||||
void setSampleRate(float sampleRate);
|
||||
void setVFOFrequency(uint64_t frequency);
|
||||
void updateBlockSize();
|
||||
void setDemodulator(int demod, float bandWidth);
|
||||
void setDeemphasis(int deemph);
|
||||
void setBandwidth(float bandWidth);
|
||||
|
||||
enum {
|
||||
DEMOD_FM,
|
||||
DEMOD_NFM,
|
||||
DEMOD_AM,
|
||||
DEMOD_USB,
|
||||
DEMOD_LSB,
|
||||
DEMOD_DSB,
|
||||
DEMOD_RAW,
|
||||
_DEMOD_COUNT
|
||||
};
|
||||
|
||||
enum {
|
||||
DEEMP_50US,
|
||||
DEEMP_75US,
|
||||
DEEMP_NONE,
|
||||
_DEEMP_COUNT
|
||||
};
|
||||
|
||||
|
||||
dsp::FMDeemphasis deemp;
|
||||
|
||||
private:
|
||||
static int sampleRateChangeHandler(void* ctx, float sampleRate);
|
||||
|
||||
dsp::stream<dsp::complex_t> input;
|
||||
|
||||
// Demodulators
|
||||
dsp::FMDemodulator demod;
|
||||
dsp::AMDemodulator amDemod;
|
||||
dsp::SSBDemod ssbDemod;
|
||||
dsp::ComplexToStereo cpx2stereo;
|
||||
|
||||
// Audio output
|
||||
dsp::MonoToStereo m2s;
|
||||
dsp::FIRResampler<float> audioResamp;
|
||||
|
||||
std::string vfoName;
|
||||
|
||||
float sampleRate;
|
||||
float bandwidth;
|
||||
float outputSampleRate;
|
||||
int blockSize;
|
||||
int _demod;
|
||||
int _deemp;
|
||||
float audioBw;
|
||||
};
|
Reference in New Issue
Block a user