kopia lustrzana https://github.com/AlexandreRouma/SDRPlusPlus
Save before changes
rodzic
2c4d7cbf09
commit
524f20bc2f
|
@ -3,7 +3,8 @@ project(sdrpp_core)
|
|||
|
||||
add_subdirectory("core")
|
||||
add_subdirectory("radio")
|
||||
add_subdirectory("recorder")
|
||||
# Add back recorder when module new system is ready
|
||||
#add_subdirectory("recorder")
|
||||
add_subdirectory("demo")
|
||||
|
||||
add_executable(sdrpp "src/main.cpp" "win32/resources.rc")
|
||||
|
|
|
@ -52,6 +52,13 @@ namespace dsp {
|
|||
output.setMaxLatency(blockSize * 2);
|
||||
}
|
||||
|
||||
void setInput(stream<complex_t>* input) {
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
_in = input;
|
||||
}
|
||||
|
||||
stream<complex_t> output;
|
||||
bool bypass;
|
||||
|
||||
|
|
|
@ -6,12 +6,10 @@ std::mutex fft_mtx;
|
|||
fftwf_complex *fft_in, *fft_out;
|
||||
fftwf_plan p;
|
||||
float* tempData;
|
||||
float* uiGains;
|
||||
char buf[1024];
|
||||
|
||||
int fftSize = 8192 * 8;
|
||||
|
||||
io::SoapyWrapper soapy;
|
||||
std::vector<float> _data;
|
||||
std::vector<float> fftTaps;
|
||||
void fftHandler(dsp::complex_t* samples) {
|
||||
|
@ -34,10 +32,7 @@ void fftHandler(dsp::complex_t* samples) {
|
|||
}
|
||||
|
||||
dsp::NullSink sink;
|
||||
int devId = 0;
|
||||
int srId = 0;
|
||||
watcher<uint64_t> freq((uint64_t)90500000);
|
||||
int demod = 1;
|
||||
watcher<float> vfoFreq(92000000.0f);
|
||||
float dummyVolume = 1.0f;
|
||||
float* volume = &dummyVolume;
|
||||
|
@ -45,7 +40,6 @@ float fftMin = -70.0f;
|
|||
float fftMax = 0.0f;
|
||||
watcher<float> offset(0.0f, true);
|
||||
watcher<float> bw(8000000.0f, true);
|
||||
int sampleRate = 8000000;
|
||||
bool playing = false;
|
||||
watcher<bool> dcbias(false, false);
|
||||
bool showCredits = false;
|
||||
|
@ -56,175 +50,14 @@ bool grabbingMenu = false;
|
|||
int newWidth = 300;
|
||||
int fftHeight = 300;
|
||||
bool showMenu = true;
|
||||
|
||||
void saveCurrentSource() {
|
||||
int i = 0;
|
||||
for (std::string gainName : soapy.gainList) {
|
||||
core::configManager.conf["sourceSettings"][sourceName]["gains"][gainName] = uiGains[i];
|
||||
i++;
|
||||
}
|
||||
core::configManager.conf["sourceSettings"][sourceName]["sampleRate"] = soapy.sampleRates[srId];
|
||||
}
|
||||
|
||||
void loadSourceConfig(std::string name) {
|
||||
json sourceSettings = core::configManager.conf["sourceSettings"][name];
|
||||
|
||||
sampleRate = sourceSettings["sampleRate"];
|
||||
|
||||
auto _srIt = std::find(soapy.sampleRates.begin(), soapy.sampleRates.end(), sampleRate);
|
||||
// If the sample rate isn't valid, set to minimum
|
||||
if (_srIt == soapy.sampleRates.end()) {
|
||||
srId = 0;
|
||||
sampleRate = soapy.sampleRates[0];
|
||||
}
|
||||
else {
|
||||
srId = std::distance(soapy.sampleRates.begin(), _srIt);
|
||||
}
|
||||
sigpath::signalPath.setSampleRate(sampleRate);
|
||||
soapy.setSampleRate(sampleRate);
|
||||
|
||||
// Set gains
|
||||
delete[] uiGains;
|
||||
uiGains = new float[soapy.gainList.size()];
|
||||
int i = 0;
|
||||
for (std::string gainName : soapy.gainList) {
|
||||
// If gain doesn't exist in config, set it to the minimum value
|
||||
if (!sourceSettings["gains"].contains(gainName)) {
|
||||
uiGains[i] = soapy.gainRanges[i].minimum();
|
||||
soapy.setGain(i, uiGains[i]);
|
||||
continue;
|
||||
}
|
||||
uiGains[i] = sourceSettings["gains"][gainName];
|
||||
soapy.setGain(i, uiGains[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
// Update GUI
|
||||
gui::waterfall.setBandwidth(sampleRate);
|
||||
gui::waterfall.setViewBandwidth(sampleRate);
|
||||
bw.val = sampleRate;
|
||||
}
|
||||
|
||||
void setVFO(float freq);
|
||||
|
||||
// =======================================================
|
||||
|
||||
void sourceMenu(void* ctx) {
|
||||
float menuColumnWidth = ImGui::GetContentRegionAvailWidth();
|
||||
if (playing) { style::beginDisabled(); };
|
||||
|
||||
ImGui::PushItemWidth(menuColumnWidth);
|
||||
if (ImGui::Combo("##_0_", &devId, soapy.txtDevList.c_str())) {
|
||||
spdlog::info("Changed input device: {0}", devId);
|
||||
sourceName = soapy.devNameList[devId];
|
||||
soapy.setDevice(soapy.devList[devId]);
|
||||
|
||||
core::configManager.aquire();
|
||||
if (core::configManager.conf["sourceSettings"].contains(sourceName)) {
|
||||
loadSourceConfig(sourceName);
|
||||
}
|
||||
else {
|
||||
srId = 0;
|
||||
sampleRate = soapy.getSampleRate();
|
||||
bw.val = sampleRate;
|
||||
gui::waterfall.setBandwidth(sampleRate);
|
||||
gui::waterfall.setViewBandwidth(sampleRate);
|
||||
sigpath::signalPath.setSampleRate(sampleRate);
|
||||
|
||||
if (soapy.gainList.size() >= 0) {
|
||||
delete[] uiGains;
|
||||
uiGains = new float[soapy.gainList.size()];
|
||||
for (int i = 0; i < soapy.gainList.size(); i++) {
|
||||
uiGains[i] = soapy.currentGains[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
setVFO(gui::freqSelect.frequency);
|
||||
core::configManager.conf["source"] = sourceName;
|
||||
core::configManager.release(true);
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
if (ImGui::Combo("##_1_", &srId, soapy.txtSampleRateList.c_str())) {
|
||||
spdlog::info("Changed sample rate: {0}", srId);
|
||||
sampleRate = soapy.sampleRates[srId];
|
||||
soapy.setSampleRate(sampleRate);
|
||||
gui::waterfall.setBandwidth(sampleRate);
|
||||
gui::waterfall.setViewBandwidth(sampleRate);
|
||||
sigpath::signalPath.setSampleRate(sampleRate);
|
||||
bw.val = sampleRate;
|
||||
|
||||
core::configManager.aquire();
|
||||
if (!core::configManager.conf["sourceSettings"].contains(sourceName)) {
|
||||
saveCurrentSource();
|
||||
}
|
||||
core::configManager.conf["sourceSettings"][sourceName]["sampleRate"] = sampleRate;
|
||||
core::configManager.release(true);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
bool noDevice = (soapy.devList.size() == 0);
|
||||
if (ImGui::Button("Refresh", ImVec2(menuColumnWidth - ImGui::GetCursorPosX(), 0.0f))) {
|
||||
soapy.refresh();
|
||||
if (noDevice && soapy.devList.size() > 0) {
|
||||
sourceName = soapy.devNameList[0];
|
||||
soapy.setDevice(soapy.devList[0]);
|
||||
if (core::configManager.conf["sourceSettings"][sourceName]) {
|
||||
loadSourceConfig(sourceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (playing) { style::endDisabled(); };
|
||||
|
||||
float maxTextLength = 0;
|
||||
float txtLen = 0;
|
||||
char buf[100];
|
||||
|
||||
// Calculate the spacing
|
||||
for (int i = 0; i < soapy.gainList.size(); i++) {
|
||||
sprintf(buf, "%s gain", soapy.gainList[i].c_str());
|
||||
txtLen = ImGui::CalcTextSize(buf).x;
|
||||
if (txtLen > maxTextLength) {
|
||||
maxTextLength = txtLen;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < soapy.gainList.size(); i++) {
|
||||
ImGui::Text("%s gain", soapy.gainList[i].c_str());
|
||||
ImGui::SameLine();
|
||||
sprintf(buf, "##_gain_slide_%d_", i);
|
||||
|
||||
ImGui::SetCursorPosX(maxTextLength + 5);
|
||||
ImGui::PushItemWidth(menuColumnWidth - (maxTextLength + 5));
|
||||
if (ImGui::SliderFloat(buf, &uiGains[i], soapy.gainRanges[i].minimum(), soapy.gainRanges[i].maximum())) {
|
||||
soapy.setGain(i, uiGains[i]);
|
||||
core::configManager.aquire();
|
||||
if (!core::configManager.conf["sourceSettings"].contains(sourceName)) {
|
||||
saveCurrentSource();
|
||||
}
|
||||
core::configManager.conf["sourceSettings"][sourceName]["gains"][soapy.gainList[i]] = uiGains[i];
|
||||
core::configManager.release(true);
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
}
|
||||
|
||||
// =======================================================
|
||||
dsp::stream<dsp::complex_t> dummyStream;
|
||||
|
||||
void windowInit() {
|
||||
spdlog::info("Initializing SoapySDR");
|
||||
soapy.init();
|
||||
|
||||
credits::init();
|
||||
|
||||
audiomenu::init();
|
||||
bandplanmenu::init();
|
||||
displaymenu::init();
|
||||
|
||||
gui::menu.registerEntry("Source", sourceMenu, NULL);
|
||||
gui::menu.registerEntry("Source", sourecmenu::draw, NULL);
|
||||
gui::menu.registerEntry("Audio", audiomenu::draw, NULL);
|
||||
gui::menu.registerEntry("Band Plan", bandplanmenu::draw, NULL);
|
||||
gui::menu.registerEntry("Display", displaymenu::draw, NULL);
|
||||
|
@ -235,50 +68,19 @@ void windowInit() {
|
|||
fft_out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
||||
p = fftwf_plan_dft_1d(fftSize, fft_in, fft_out, FFTW_FORWARD, FFTW_ESTIMATE);
|
||||
|
||||
sigpath::signalPath.init(sampleRate, 20, fftSize, &soapy.output, (dsp::complex_t*)fft_in, fftHandler);
|
||||
sigpath::signalPath.init(8000000, 20, fftSize, &dummyStream, (dsp::complex_t*)fft_in, fftHandler);
|
||||
sigpath::signalPath.start();
|
||||
|
||||
uiGains = new float[soapy.gainList.size()];
|
||||
|
||||
spdlog::info("Loading modules");
|
||||
mod::initAPI(&gui::waterfall);
|
||||
mod::loadFromList(ROOT_DIR "/module_list.json");
|
||||
|
||||
sourecmenu::init();
|
||||
audiomenu::init();
|
||||
bandplanmenu::init();
|
||||
displaymenu::init();
|
||||
|
||||
// Load last source configuration
|
||||
core::configManager.aquire();
|
||||
uint64_t frequency = core::configManager.conf["frequency"];
|
||||
sourceName = core::configManager.conf["source"];
|
||||
auto _sourceIt = std::find(soapy.devNameList.begin(), soapy.devNameList.end(), sourceName);
|
||||
if (_sourceIt != soapy.devNameList.end() && core::configManager.conf["sourceSettings"].contains(sourceName)) {
|
||||
json sourceSettings = core::configManager.conf["sourceSettings"][sourceName];
|
||||
devId = std::distance(soapy.devNameList.begin(), _sourceIt);
|
||||
soapy.setDevice(soapy.devList[devId]);
|
||||
loadSourceConfig(sourceName);
|
||||
}
|
||||
else {
|
||||
int i = 0;
|
||||
bool settingsFound = false;
|
||||
for (std::string devName : soapy.devNameList) {
|
||||
if (core::configManager.conf["sourceSettings"].contains(devName)) {
|
||||
sourceName = devName;
|
||||
settingsFound = true;
|
||||
devId = i;
|
||||
soapy.setDevice(soapy.devList[i]);
|
||||
loadSourceConfig(sourceName);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!settingsFound) {
|
||||
if (soapy.devNameList.size() > 0) {
|
||||
sourceName = soapy.devNameList[0];
|
||||
}
|
||||
sampleRate = soapy.getSampleRate();
|
||||
sigpath::signalPath.setSampleRate(sampleRate);
|
||||
}
|
||||
// Search for the first source in the list to have a config
|
||||
// If no pre-defined source, selected default device
|
||||
}
|
||||
|
||||
// Also add a loading screen
|
||||
// Adjustable "snap to grid" for each VFO
|
||||
|
@ -301,15 +103,17 @@ void windowInit() {
|
|||
gui::waterfall.setWaterfallMin(fftMin);
|
||||
gui::waterfall.setFFTMax(fftMax);
|
||||
gui::waterfall.setWaterfallMax(fftMax);
|
||||
|
||||
float frequency = core::configManager.conf["frequency"];
|
||||
|
||||
|
||||
gui::freqSelect.setFrequency(frequency);
|
||||
gui::freqSelect.frequencyChanged = false;
|
||||
soapy.setFrequency(frequency);
|
||||
sigpath::sourceManager.tune(frequency);
|
||||
gui::waterfall.setCenterFrequency(frequency);
|
||||
gui::waterfall.setBandwidth(sampleRate);
|
||||
gui::waterfall.setViewBandwidth(sampleRate);
|
||||
bw.val = sampleRate;
|
||||
gui::waterfall.setBandwidth(8000000);
|
||||
gui::waterfall.setViewBandwidth(8000000);
|
||||
bw.val = 8000000;
|
||||
gui::waterfall.vfoFreqChanged = false;
|
||||
gui::waterfall.centerFreqMoved = false;
|
||||
gui::waterfall.selectFirstVFO();
|
||||
|
@ -357,7 +161,7 @@ void setVFO(float freq) {
|
|||
float newVFOOffset = (BW / 2.0f) - (vfoBW / 2.0f) - (viewBW / 10.0f);
|
||||
sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset);
|
||||
gui::waterfall.setCenterFrequency(freq - newVFOOffset);
|
||||
soapy.setFrequency(freq - newVFOOffset);
|
||||
sigpath::sourceManager.tune(freq - newVFOOffset);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -367,7 +171,7 @@ void setVFO(float freq) {
|
|||
float newVFOOffset = (vfoBW / 2.0f) - (BW / 2.0f) + (viewBW / 10.0f);
|
||||
sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset);
|
||||
gui::waterfall.setCenterFrequency(freq - newVFOOffset);
|
||||
soapy.setFrequency(freq - newVFOOffset);
|
||||
sigpath::sourceManager.tune(freq - newVFOOffset);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -387,7 +191,7 @@ void setVFO(float freq) {
|
|||
float newVFOOffset = (BW / 2.0f) - (vfoBW / 2.0f) - (viewBW / 10.0f);
|
||||
sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset);
|
||||
gui::waterfall.setCenterFrequency(freq - newVFOOffset);
|
||||
soapy.setFrequency(freq - newVFOOffset);
|
||||
sigpath::sourceManager.tune(freq - newVFOOffset);
|
||||
}
|
||||
else {
|
||||
float newViewOff = vfoBottom + (viewBW / 2.0f) - (viewBW / 10.0f);
|
||||
|
@ -404,7 +208,7 @@ void setVFO(float freq) {
|
|||
float newVFOOffset = (vfoBW / 2.0f) - (BW / 2.0f) + (viewBW / 10.0f);
|
||||
sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset);
|
||||
gui::waterfall.setCenterFrequency(freq - newVFOOffset);
|
||||
soapy.setFrequency(freq - newVFOOffset);
|
||||
sigpath::sourceManager.tune(freq - newVFOOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -450,7 +254,7 @@ void drawWindow() {
|
|||
|
||||
if (gui::waterfall.centerFreqMoved) {
|
||||
gui::waterfall.centerFreqMoved = false;
|
||||
soapy.setFrequency(gui::waterfall.getCenterFrequency());
|
||||
sigpath::sourceManager.tune(gui::waterfall.getCenterFrequency());
|
||||
gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency() + vfo->generalOffset);
|
||||
core::configManager.aquire();
|
||||
core::configManager.conf["frequency"] = gui::freqSelect.frequency;
|
||||
|
@ -491,14 +295,15 @@ void drawWindow() {
|
|||
|
||||
if (playing) {
|
||||
if (ImGui::ImageButton(icons::STOP, ImVec2(40, 40), ImVec2(0, 0), ImVec2(1, 1), 0)) {
|
||||
soapy.stop();
|
||||
sigpath::sourceManager.stop();
|
||||
playing = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ImGui::ImageButton(icons::PLAY, ImVec2(40, 40), ImVec2(0, 0), ImVec2(1, 1), 0) && soapy.devList.size() > 0) {
|
||||
soapy.start();
|
||||
soapy.setFrequency(gui::waterfall.getCenterFrequency());
|
||||
else { // TODO: Might need to check if there even is a device
|
||||
if (ImGui::ImageButton(icons::PLAY, ImVec2(40, 40), ImVec2(0, 0), ImVec2(1, 1), 0)) {
|
||||
sigpath::sourceManager.start();
|
||||
// TODO: tune in module instead
|
||||
sigpath::sourceManager.tune(gui::waterfall.getCenterFrequency());
|
||||
playing = true;
|
||||
}
|
||||
}
|
||||
|
@ -623,7 +428,8 @@ void drawWindow() {
|
|||
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0f) - (ImGui::CalcTextSize("Zoom").x / 2.0f));
|
||||
ImGui::Text("Zoom");
|
||||
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0f) - 10);
|
||||
ImGui::VSliderFloat("##_7_", ImVec2(20.0f, 150.0f), &bw.val, sampleRate, 1000.0f, "");
|
||||
// TODO: use global sample rate value from DSP instead of 8000000
|
||||
ImGui::VSliderFloat("##_7_", ImVec2(20.0f, 150.0f), &bw.val, 8000000, 1000.0f, "");
|
||||
|
||||
ImGui::NewLine();
|
||||
|
||||
|
|
|
@ -28,10 +28,12 @@
|
|||
#include <config.h>
|
||||
#include <signal_path/signal_path.h>
|
||||
#include <core.h>
|
||||
#include <gui/menus/source.h>
|
||||
#include <gui/menus/display.h>
|
||||
#include <gui/menus/bandplan.h>
|
||||
#include <gui/menus/audio.h>
|
||||
#include <gui/dialogs/credits.h>
|
||||
#include <signal_path/source.h>
|
||||
|
||||
#define WINDOW_FLAGS ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground
|
||||
|
||||
|
|
|
@ -1,11 +1,33 @@
|
|||
#include <gui/menus/source.h>
|
||||
#include <imgui.h>
|
||||
#include <gui/gui.h>
|
||||
#include <core.h>
|
||||
#include <signal_path/signal_path.h>
|
||||
|
||||
namespace sourecmenu {
|
||||
void init() {
|
||||
int sourceId = 0;
|
||||
|
||||
void init() {
|
||||
// Select default
|
||||
// TODO: Replace by setting
|
||||
if (sigpath::sourceManager.sourceNames.size() > 0) {
|
||||
sigpath::sourceManager.selectSource(sigpath::sourceManager.sourceNames[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void draw(void* ctx) {
|
||||
std::string items = "";
|
||||
for (std::string name : sigpath::sourceManager.sourceNames) {
|
||||
items += name;
|
||||
items += '\0';
|
||||
}
|
||||
float itemWidth = ImGui::GetContentRegionAvailWidth();
|
||||
|
||||
ImGui::SetNextItemWidth(itemWidth);
|
||||
if (ImGui::Combo("##source", &sourceId, items.c_str())) {
|
||||
sigpath::sourceManager.selectSource(sigpath::sourceManager.sourceNames[sourceId]);
|
||||
}
|
||||
|
||||
sigpath::sourceManager.showSelectedMenu();
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <SoapySDR/Device.hpp>
|
||||
#include <SoapySDR/Modules.hpp>
|
||||
|
|
|
@ -29,45 +29,6 @@
|
|||
#endif
|
||||
|
||||
namespace mod {
|
||||
struct API_t {
|
||||
dsp::stream<dsp::complex_t>* (*registerVFO)(std::string name, int reference, float offset, float bandwidth, float sampleRate, int blockSize);
|
||||
void (*setVFOOffset)(std::string name, float offset);
|
||||
void (*setVFOCenterOffset)(std::string name, float offset);
|
||||
void (*setVFOBandwidth)(std::string name, float bandwidth);
|
||||
void (*setVFOSampleRate)(std::string name, float sampleRate, float bandwidth);
|
||||
int (*getVFOOutputBlockSize)(std::string name);
|
||||
void (*setVFOReference)(std::string name, int ref);
|
||||
void (*removeVFO)(std::string name);
|
||||
|
||||
std::string (*getSelectedVFOName)(void);
|
||||
void (*bindVolumeVariable)(float* vol);
|
||||
void (*unbindVolumeVariable)(void);
|
||||
|
||||
float (*registerMonoStream)(dsp::stream<float>* stream, std::string name, std::string vfoName, int (*sampleRateChangeHandler)(void* ctx, float sampleRate), void* ctx);
|
||||
float (*registerStereoStream)(dsp::stream<dsp::StereoFloat_t>* stream, std::string name, std::string vfoName, int (*sampleRateChangeHandler)(void* ctx, float sampleRate), void* ctx);
|
||||
void (*startStream)(std::string name);
|
||||
void (*stopStream)(std::string name);
|
||||
void (*removeStream)(std::string name);
|
||||
dsp::stream<float>* (*bindToStreamMono)(std::string name, void (*streamRemovedHandler)(void* ctx), void (*sampleRateChangeHandler)(void* ctx, float sampleRate, int blockSize), void* ctx);
|
||||
dsp::stream<dsp::StereoFloat_t>* (*bindToStreamStereo)(std::string name, void (*streamRemovedHandler)(void* ctx), void (*sampleRateChangeHandler)(void* ctx, float sampleRate, int blockSize), void* ctx);
|
||||
void (*setBlockSize)(std::string name, int blockSize);
|
||||
void (*unbindFromStreamMono)(std::string name, dsp::stream<float>* stream);
|
||||
void (*unbindFromStreamStereo)(std::string name, dsp::stream<dsp::StereoFloat_t>* stream);
|
||||
std::vector<std::string> (*getStreamNameList)(void);
|
||||
|
||||
enum {
|
||||
REF_LOWER,
|
||||
REF_CENTER,
|
||||
REF_UPPER,
|
||||
_REF_COUNT
|
||||
};
|
||||
};
|
||||
|
||||
enum {
|
||||
EVENT_STREAM_PARAM_CHANGED,
|
||||
EVENT_SELECTED_VFO_CHANGED,
|
||||
_EVENT_COUNT
|
||||
};
|
||||
|
||||
struct Module_t {
|
||||
#ifdef _WIN32
|
||||
|
@ -75,14 +36,20 @@ namespace mod {
|
|||
#else
|
||||
void* inst;
|
||||
#endif
|
||||
void* (*_INIT_)(API_t*, ImGuiContext*, std::string);
|
||||
void (*_DRAW_MENU_)(void*);
|
||||
void (*_NEW_FRAME_)(void*);
|
||||
void (*_HANDLE_EVENT_)(void*, int);
|
||||
void (*_STOP_)(void*);
|
||||
void (*_INIT_)();
|
||||
void* (*_CREATE_INSTANCE)(std::string);
|
||||
void (*_DELETE_INSTANCE)();
|
||||
void (*_STOP_)();
|
||||
void* ctx;
|
||||
};
|
||||
|
||||
struct ModuleInfo_t {
|
||||
char* name;
|
||||
char* description;
|
||||
char* author;
|
||||
char* version;
|
||||
};
|
||||
|
||||
void initAPI(ImGui::WaterFall* wtf);
|
||||
void loadModule(std::string path, std::string name);
|
||||
void broadcastEvent(int eventId);
|
||||
|
@ -92,4 +59,4 @@ namespace mod {
|
|||
extern std::vector<std::string> moduleNames;
|
||||
};
|
||||
|
||||
extern mod::API_t* API;
|
||||
#define MOD_INFO MOD_EXPORT const mod::ModuleInfo_t _INFO
|
|
@ -40,7 +40,7 @@ void SignalPath::setSampleRate(float sampleRate) {
|
|||
fftBlockDec.setSkip(skip);
|
||||
dynSplit.setBlockSize(inputBlockSize);
|
||||
|
||||
mod::broadcastEvent(mod::EVENT_STREAM_PARAM_CHANGED);
|
||||
// TODO: Tell modules that the block size has changed
|
||||
|
||||
for (auto const& [name, vfo] : vfos) {
|
||||
vfo.vfo->setInputSampleRate(sampleRate, inputBlockSize);
|
||||
|
@ -87,6 +87,7 @@ dsp::VFO* SignalPath::addVFO(std::string name, float outSampleRate, float bandwi
|
|||
void SignalPath::removeVFO(std::string name) {
|
||||
if (vfos.find(name) == vfos.end()) {
|
||||
return;
|
||||
|
||||
}
|
||||
dynSplit.stop();
|
||||
VFO_t vfo = vfos[name];
|
||||
|
@ -96,4 +97,10 @@ void SignalPath::removeVFO(std::string name) {
|
|||
delete vfo.inputStream;
|
||||
dynSplit.start();
|
||||
vfos.erase(name);
|
||||
}
|
||||
|
||||
void SignalPath::setInput(dsp::stream<dsp::complex_t>* input) {
|
||||
dcBiasRemover.stop();
|
||||
dcBiasRemover.setInput(input);
|
||||
dcBiasRemover.start();
|
||||
}
|
|
@ -22,6 +22,7 @@ public:
|
|||
void setFFTRate(float rate);
|
||||
dsp::VFO* addVFO(std::string name, float outSampleRate, float bandwidth, float offset);
|
||||
void removeVFO(std::string name);
|
||||
void setInput(dsp::stream<dsp::complex_t>* input);
|
||||
|
||||
private:
|
||||
struct VFO_t {
|
||||
|
|
|
@ -3,4 +3,5 @@
|
|||
namespace sigpath {
|
||||
SignalPath signalPath;
|
||||
VFOManager vfoManager;
|
||||
SourceManager sourceManager;
|
||||
};
|
|
@ -1,9 +1,12 @@
|
|||
#pragma once
|
||||
#include <signal_path/dsp.h>
|
||||
#include <signal_path/vfo_manager.h>
|
||||
#include <signal_path/source.h>
|
||||
#include <io/soapy.h>
|
||||
#include <module.h>
|
||||
|
||||
namespace sigpath {
|
||||
SDRPP_EXPORT SignalPath signalPath;
|
||||
SDRPP_EXPORT VFOManager vfoManager;
|
||||
SDRPP_EXPORT SourceManager sourceManager;
|
||||
};
|
|
@ -0,0 +1,58 @@
|
|||
#include <signal_path/source.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <signal_path/signal_path.h>
|
||||
|
||||
SourceManager::SourceManager() {
|
||||
|
||||
}
|
||||
|
||||
void SourceManager::registerSource(std::string name, SourceHandler* handler) {
|
||||
if (sources.find(name) != sources.end()) {
|
||||
spdlog::error("Tried to register new source with existing name: {0}", name);
|
||||
return;
|
||||
}
|
||||
sources[name] = handler;
|
||||
sourceNames.push_back(name);
|
||||
}
|
||||
|
||||
void SourceManager::selectSource(std::string name) {
|
||||
if (sources.find(name) == sources.end()) {
|
||||
spdlog::error("Tried to select non existant source: {0}", name);
|
||||
return;
|
||||
}
|
||||
if (selectedName != "") {
|
||||
sources[selectedName]->deselectHandler(sources[selectedName]->ctx);
|
||||
}
|
||||
selectedHandler = sources[name];
|
||||
selectedHandler->selectHandler(selectedHandler->ctx);
|
||||
selectedName = name;
|
||||
sigpath::signalPath.setInput(selectedHandler->stream);
|
||||
}
|
||||
|
||||
void SourceManager::showSelectedMenu() {
|
||||
if (selectedHandler == NULL) {
|
||||
return;
|
||||
}
|
||||
selectedHandler->menuHandler(selectedHandler->ctx);
|
||||
}
|
||||
|
||||
void SourceManager::start() {
|
||||
if (selectedHandler == NULL) {
|
||||
return;
|
||||
}
|
||||
selectedHandler->startHandler(selectedHandler->ctx);
|
||||
}
|
||||
|
||||
void SourceManager::stop() {
|
||||
if (selectedHandler == NULL) {
|
||||
return;
|
||||
}
|
||||
selectedHandler->stopHandler(selectedHandler->ctx);
|
||||
}
|
||||
|
||||
void SourceManager::tune(double freq) {
|
||||
if (selectedHandler == NULL) {
|
||||
return;
|
||||
}
|
||||
selectedHandler->tuneHandler(freq, selectedHandler->ctx);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <dsp/stream.h>
|
||||
#include <dsp/types.h>
|
||||
|
||||
class SourceManager {
|
||||
public:
|
||||
SourceManager();
|
||||
|
||||
struct SourceHandler {
|
||||
dsp::stream<dsp::complex_t>* stream;
|
||||
void (*menuHandler)(void* ctx);
|
||||
void (*selectHandler)(void* ctx);
|
||||
void (*deselectHandler)(void* ctx);
|
||||
void (*startHandler)(void* ctx);
|
||||
void (*stopHandler)(void* ctx);
|
||||
void (*tuneHandler)(double freq, void* ctx);
|
||||
void* ctx;
|
||||
};
|
||||
|
||||
void registerSource(std::string name, SourceHandler* handler);
|
||||
void selectSource(std::string name);
|
||||
void showSelectedMenu();
|
||||
void start();
|
||||
void stop();
|
||||
void tune(double freq);
|
||||
|
||||
std::vector<std::string> sourceNames;
|
||||
|
||||
private:
|
||||
std::map<std::string, SourceHandler*> sources;
|
||||
std::string selectedName;
|
||||
SourceHandler* selectedHandler = NULL;
|
||||
|
||||
};
|
|
@ -1,38 +1,51 @@
|
|||
#include <imgui.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <module.h>
|
||||
#include <watcher.h>
|
||||
#include <dsp/types.h>
|
||||
#include <dsp/stream.h>
|
||||
#include <thread>
|
||||
#include <ctime>
|
||||
#include <stdio.h>
|
||||
#include <gui/style.h>
|
||||
#include <gui/gui.h>
|
||||
|
||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||
|
||||
|
||||
struct DemoContext_t {
|
||||
std::string name;
|
||||
MOD_INFO {
|
||||
/* Name: */ "demo",
|
||||
/* Description: */ "Demo module for SDR++",
|
||||
/* Author: */ "Ryzerth",
|
||||
/* Version: */ "0.1.0"
|
||||
};
|
||||
|
||||
MOD_EXPORT void* _INIT_(mod::API_t* _API, ImGuiContext* imctx, std::string _name) {
|
||||
DemoContext_t* ctx = new DemoContext_t;
|
||||
ctx->name = _name;
|
||||
return ctx;
|
||||
class DemoModule {
|
||||
public:
|
||||
DemoModule(std::string name) {
|
||||
this->name = name;
|
||||
gui::menu.registerEntry(name, menuHandler, this);
|
||||
spdlog::info("DemoModule '{0}': Instance created!", name);
|
||||
}
|
||||
|
||||
~DemoModule() {
|
||||
spdlog::info("DemoModule '{0}': Instance deleted!", name);
|
||||
}
|
||||
|
||||
private:
|
||||
static void menuHandler(void* ctx) {
|
||||
DemoModule* _this = (DemoModule*)ctx;
|
||||
ImGui::Text("Hi from %s!", _this->name.c_str());
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
};
|
||||
|
||||
MOD_EXPORT void _INIT_() {
|
||||
// Do your one time init here
|
||||
}
|
||||
|
||||
MOD_EXPORT void _NEW_FRAME_(DemoContext_t* ctx) {
|
||||
|
||||
MOD_EXPORT void* _CREATE_INSTANCE_(std::string name) {
|
||||
return new DemoModule(name);
|
||||
}
|
||||
|
||||
MOD_EXPORT void _DRAW_MENU_(DemoContext_t* ctx) {
|
||||
ImGui::Text(ctx->name.c_str());
|
||||
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
||||
delete (DemoModule*)instance;
|
||||
}
|
||||
|
||||
MOD_EXPORT void _HANDLE_EVENT_(DemoContext_t* ctx, int eventId) {
|
||||
|
||||
}
|
||||
|
||||
MOD_EXPORT void _STOP_(DemoContext_t* ctx) {
|
||||
|
||||
MOD_EXPORT void _STOP_() {
|
||||
// Do your one shutdown here
|
||||
}
|
|
@ -7,12 +7,115 @@
|
|||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||
#define DEEMP_LIST "50µS\00075µS\000none\000"
|
||||
|
||||
mod::API_t* API;
|
||||
MOD_INFO {
|
||||
/* Name: */ "radio",
|
||||
/* Description: */ "Radio module for SDR++",
|
||||
/* Author: */ "Ryzerth",
|
||||
/* Version: */ "0.2.5"
|
||||
};
|
||||
|
||||
ConfigManager config;
|
||||
bool firstInit = true;
|
||||
class RadioModule {
|
||||
public:
|
||||
RadioModule(std::string name) {
|
||||
this->name = name;
|
||||
demod = 1;
|
||||
bandWidth = 200000;
|
||||
bandWidthMin = 100000;
|
||||
bandWidthMax = 200000;
|
||||
sigPath.init(name, 200000, 1000);
|
||||
sigPath.start();
|
||||
sigPath.setDemodulator(SigPath::DEMOD_FM, bandWidth);
|
||||
}
|
||||
|
||||
~RadioModule() {
|
||||
// TODO: Implement destructor
|
||||
}
|
||||
|
||||
private:
|
||||
static void menuHandler(void* ctx) {
|
||||
RadioModule* _this = (RadioModule*)ctx;
|
||||
float menuColumnWidth = ImGui::GetContentRegionAvailWidth();
|
||||
|
||||
ImGui::BeginGroup();
|
||||
|
||||
// TODO: Change VFO ref in signal path
|
||||
|
||||
ImGui::Columns(4, CONCAT("RadioModeColumns##_", _this->name), false);
|
||||
if (ImGui::RadioButton(CONCAT("NFM##_", _this->name), _this->demod == 0) && _this->demod != 0) {
|
||||
_this->demod = 0;
|
||||
_this->bandWidth = 16000;
|
||||
_this->bandWidthMin = 8000;
|
||||
_this->bandWidthMax = 16000;
|
||||
_this->sigPath.setDemodulator(SigPath::DEMOD_NFM, _this->bandWidth);
|
||||
}
|
||||
if (ImGui::RadioButton(CONCAT("WFM##_", _this->name), _this->demod == 1) && _this->demod != 1) {
|
||||
_this->demod = 1;
|
||||
_this->bandWidth = 200000;
|
||||
_this->bandWidthMin = 100000;
|
||||
_this->bandWidthMax = 200000;
|
||||
_this->sigPath.setDemodulator(SigPath::DEMOD_FM, _this->bandWidth);
|
||||
}
|
||||
ImGui::NextColumn();
|
||||
if (ImGui::RadioButton(CONCAT("AM##_", _this->name), _this->demod == 2) && _this->demod != 2) {
|
||||
_this->demod = 2;
|
||||
_this->bandWidth = 12500;
|
||||
_this->bandWidthMin = 6250;
|
||||
_this->bandWidthMax = 12500;
|
||||
_this->sigPath.setDemodulator(SigPath::DEMOD_AM, _this->bandWidth);
|
||||
}
|
||||
if (ImGui::RadioButton(CONCAT("DSB##_", _this->name), _this->demod == 3) && _this->demod != 3) {
|
||||
_this->demod = 3;
|
||||
_this->bandWidth = 6000;
|
||||
_this->bandWidthMin = 3000;
|
||||
_this->bandWidthMax = 6000;
|
||||
_this->sigPath.setDemodulator(SigPath::DEMOD_DSB, _this->bandWidth);
|
||||
}
|
||||
ImGui::NextColumn();
|
||||
if (ImGui::RadioButton(CONCAT("USB##_", _this->name), _this->demod == 4) && _this->demod != 4) {
|
||||
_this->demod = 4;
|
||||
_this->bandWidth = 3000;
|
||||
_this->bandWidthMin = 1500;
|
||||
_this->bandWidthMax = 3000;
|
||||
_this->sigPath.setDemodulator(SigPath::DEMOD_USB, _this->bandWidth);
|
||||
}
|
||||
if (ImGui::RadioButton(CONCAT("CW##_", _this->name), _this->demod == 5) && _this->demod != 5) { _this->demod = 5; };
|
||||
ImGui::NextColumn();
|
||||
if (ImGui::RadioButton(CONCAT("LSB##_", _this->name), _this->demod == 6) && _this->demod != 6) {
|
||||
_this->demod = 6;
|
||||
_this->bandWidth = 3000;
|
||||
_this->bandWidthMin = 1500;
|
||||
_this->bandWidthMax = 3000;
|
||||
_this->sigPath.setDemodulator(SigPath::DEMOD_LSB, _this->bandWidth);
|
||||
}
|
||||
if (ImGui::RadioButton(CONCAT("RAW##_", _this->name), _this->demod == 7) && _this->demod != 7) {
|
||||
_this->demod = 7;
|
||||
_this->bandWidth = 10000;
|
||||
_this->bandWidthMin = 3000;
|
||||
_this->bandWidthMax = 10000;
|
||||
_this->sigPath.setDemodulator(SigPath::DEMOD_RAW, _this->bandWidth);
|
||||
};
|
||||
ImGui::Columns(1, CONCAT("EndRadioModeColumns##_", _this->name), false);
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
ImGui::Text("WFM Deemphasis");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(menuColumnWidth - ImGui::GetCursorPosX());
|
||||
if (ImGui::Combo(CONCAT("##_deemp_select_", _this->name), &_this->deemp, DEEMP_LIST)) {
|
||||
_this->sigPath.setDeemphasis(_this->deemp);
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::Text("Bandwidth");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(menuColumnWidth - ImGui::GetCursorPosX());
|
||||
if (ImGui::InputInt(CONCAT("##_bw_select_", _this->name), &_this->bandWidth, 100, 1000)) {
|
||||
_this->bandWidth = std::clamp<int>(_this->bandWidth, _this->bandWidthMin, _this->bandWidthMax);
|
||||
_this->sigPath.setBandwidth(_this->bandWidth);
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
struct RadioContext_t {
|
||||
std::string name;
|
||||
int demod = 1;
|
||||
int deemp = 0;
|
||||
|
@ -20,117 +123,21 @@ struct RadioContext_t {
|
|||
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->demod = 1;
|
||||
ctx->bandWidth = 200000;
|
||||
ctx->bandWidthMin = 100000;
|
||||
ctx->bandWidthMax = 200000;
|
||||
ctx->sigPath.init(_name, 200000, 1000);
|
||||
ctx->sigPath.start();
|
||||
ctx->sigPath.setDemodulator(SigPath::DEMOD_FM, ctx->bandWidth);
|
||||
ImGui::SetCurrentContext(imctx);
|
||||
return ctx;
|
||||
MOD_EXPORT void _INIT_() {
|
||||
// Do your one time init here
|
||||
}
|
||||
|
||||
MOD_EXPORT void _NEW_FRAME_(RadioContext_t* ctx) {
|
||||
|
||||
MOD_EXPORT void* _CREATE_INSTANCE_(std::string name) {
|
||||
return new RadioModule(name);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
};
|
||||
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 _DELETE_INSTANCE_(void* instance) {
|
||||
delete (RadioModule*)instance;
|
||||
}
|
||||
|
||||
MOD_EXPORT void _HANDLE_EVENT_(RadioContext_t* ctx, int eventId) {
|
||||
|
||||
}
|
||||
|
||||
MOD_EXPORT void _STOP_(RadioContext_t* ctx) {
|
||||
API->removeVFO(ctx->name);
|
||||
delete ctx;
|
||||
MOD_EXPORT void _STOP_() {
|
||||
// Do your one shutdown here
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include <path.h>
|
||||
#include <signal_path/audio.h>
|
||||
|
||||
SigPath::SigPath() {
|
||||
|
||||
|
@ -23,7 +24,7 @@ void SigPath::init(std::string vfoName, uint64_t sampleRate, int blockSize) {
|
|||
this->blockSize = blockSize;
|
||||
this->vfoName = vfoName;
|
||||
|
||||
vfo = sigpath::vfoManager.createVFO(vfoName, mod::API_t::REF_CENTER, 0, 200000, 200000, 1000);
|
||||
vfo = sigpath::vfoManager.createVFO(vfoName, ImGui::WaterfallVFO::REF_CENTER, 0, 200000, 200000, 1000);
|
||||
|
||||
_demod = DEMOD_FM;
|
||||
_deemp = DEEMP_50US;
|
||||
|
@ -40,8 +41,9 @@ void SigPath::init(std::string vfoName, uint64_t sampleRate, int blockSize) {
|
|||
|
||||
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());
|
||||
|
||||
outputSampleRate = audio::registerMonoStream(&deemp.output, vfoName, vfoName, sampleRateChangeHandler, this);
|
||||
audio::setBlockSize(vfoName, audioResamp.getOutputBlockSize());
|
||||
|
||||
setDemodulator(_demod, bandwidth);
|
||||
}
|
||||
|
@ -101,7 +103,7 @@ void SigPath::setDemodulator(int demId, float bandWidth) {
|
|||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(200000, vfo->getOutputBlockSize(), audioBw, audioBw);
|
||||
deemp.bypass = (_deemp == DEEMP_NONE);
|
||||
vfo->setReference(mod::API_t::REF_CENTER);
|
||||
vfo->setReference(ImGui::WaterfallVFO::REF_CENTER);
|
||||
demod.start();
|
||||
}
|
||||
else if (demId == DEMOD_NFM) {
|
||||
|
@ -113,7 +115,7 @@ void SigPath::setDemodulator(int demId, float bandWidth) {
|
|||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(16000, vfo->getOutputBlockSize(), audioBw, audioBw);
|
||||
deemp.bypass = true;
|
||||
vfo->setReference(mod::API_t::REF_CENTER);
|
||||
vfo->setReference(ImGui::WaterfallVFO::REF_CENTER);
|
||||
demod.start();
|
||||
}
|
||||
else if (demId == DEMOD_AM) {
|
||||
|
@ -123,7 +125,7 @@ void SigPath::setDemodulator(int demId, float bandWidth) {
|
|||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(12500, vfo->getOutputBlockSize(), audioBw, audioBw);
|
||||
deemp.bypass = true;
|
||||
vfo->setReference(mod::API_t::REF_CENTER);
|
||||
vfo->setReference(ImGui::WaterfallVFO::REF_CENTER);
|
||||
amDemod.start();
|
||||
}
|
||||
else if (demId == DEMOD_USB) {
|
||||
|
@ -134,7 +136,7 @@ void SigPath::setDemodulator(int demId, float bandWidth) {
|
|||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(6000, vfo->getOutputBlockSize(), audioBw, audioBw);
|
||||
deemp.bypass = true;
|
||||
vfo->setReference(mod::API_t::REF_LOWER);
|
||||
vfo->setReference(ImGui::WaterfallVFO::REF_LOWER);
|
||||
ssbDemod.start();
|
||||
}
|
||||
else if (demId == DEMOD_LSB) {
|
||||
|
@ -145,7 +147,7 @@ void SigPath::setDemodulator(int demId, float bandWidth) {
|
|||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(6000, vfo->getOutputBlockSize(), audioBw, audioBw);
|
||||
deemp.bypass = true;
|
||||
vfo->setReference(mod::API_t::REF_UPPER);
|
||||
vfo->setReference(ImGui::WaterfallVFO::REF_UPPER);
|
||||
ssbDemod.start();
|
||||
}
|
||||
else if (demId == DEMOD_DSB) {
|
||||
|
@ -156,7 +158,7 @@ void SigPath::setDemodulator(int demId, float bandWidth) {
|
|||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(6000, vfo->getOutputBlockSize(), audioBw, audioBw);
|
||||
deemp.bypass = true;
|
||||
vfo->setReference(mod::API_t::REF_CENTER);
|
||||
vfo->setReference(ImGui::WaterfallVFO::REF_CENTER);
|
||||
ssbDemod.start();
|
||||
}
|
||||
else if (demId == DEMOD_RAW) {
|
||||
|
@ -165,7 +167,7 @@ void SigPath::setDemodulator(int demId, float bandWidth) {
|
|||
//audioResamp.setInput(&cpx2stereo.output);
|
||||
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
|
||||
audioResamp.setInputSampleRate(10000, vfo->getOutputBlockSize(), audioBw, audioBw);
|
||||
vfo->setReference(mod::API_t::REF_LOWER);
|
||||
vfo->setReference(ImGui::WaterfallVFO::REF_LOWER);
|
||||
cpx2stereo.start();
|
||||
}
|
||||
else {
|
||||
|
@ -249,5 +251,5 @@ void SigPath::start() {
|
|||
demod.start();
|
||||
audioResamp.start();
|
||||
deemp.start();
|
||||
API->startStream(vfoName);
|
||||
audio::startStream(vfoName);
|
||||
}
|
Ładowanie…
Reference in New Issue