Fixed issues with new module system

This commit is contained in:
Ryzerth 2020-09-20 00:19:39 +02:00
parent d6b9e1d86a
commit 9de585190f
38 changed files with 460 additions and 358 deletions

3
.gitignore vendored
View File

@ -2,4 +2,5 @@ build/
.vscode/ .vscode/
*.old *.old
*.dll *.dll
*.exe *.exe
*.zip

View File

@ -9,13 +9,16 @@ else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive -fsanitize=address -g") set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive -fsanitize=address -g")
# set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") # set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
endif (MSVC) endif (MSVC)
add_definitions(-DSDRPP_IS_CORE)
# Main code # Main code
file(GLOB SRC "src/*.cpp") file(GLOB SRC "src/*.cpp")
file(GLOB GUI "src/gui/*.cpp")
file(GLOB SIGPATH "src/signal_path/*.cpp")
file(GLOB IMGUI "src/imgui/*.cpp") file(GLOB IMGUI "src/imgui/*.cpp")
# Add code to dyn lib # Add code to dyn lib
add_library(sdrpp_core SHARED ${SRC} ${IMGUI}) add_library(sdrpp_core SHARED ${SRC} ${GUI} ${SIGPATH} ${IMGUI})
# Include core headers # Include core headers
target_include_directories(sdrpp_core PUBLIC "src/") target_include_directories(sdrpp_core PUBLIC "src/")

View File

@ -4,12 +4,12 @@
#include <stdio.h> #include <stdio.h>
#include <GL/glew.h> #include <GL/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <main_window.h> #include <gui/main_window.h>
#include <style.h> #include <gui/style.h>
#include <icons.h> #include <gui/icons.h>
#include <version.h> #include <version.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <bandplan.h> #include <gui/bandplan.h>
#include <module.h> #include <module.h>
#include <stb_image.h> #include <stb_image.h>
#include <config.h> #include <config.h>
@ -139,23 +139,23 @@ int sdrpp_main() {
// ==================================================== // ====================================================
// glfwPollEvents(); // // glfwPollEvents();
ImGui_ImplOpenGL3_NewFrame(); // ImGui_ImplOpenGL3_NewFrame();
// ImGui_ImplGlfw_NewFrame(); // // ImGui_ImplGlfw_NewFrame();
// ImGui::NewFrame(); // // ImGui::NewFrame();
// ImGui::ShowDemoWindow(); // // ImGui::ShowDemoWindow();
// ImGui::Render(); // // ImGui::Render();
int display_w, display_h; // int display_w, display_h;
glfwGetFramebufferSize(window, &display_w, &display_h); // glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h); // glViewport(0, 0, display_w, display_h);
glClearColor(0.0666f, 0.0666f, 0.0666f, 1.0f); // glClearColor(0.0666f, 0.0666f, 0.0666f, 1.0f);
//glClearColor(0.9f, 0.9f, 0.9f, 1.0f); // //glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); // glClear(GL_COLOR_BUFFER_BIT);
// ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); // // ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window); // glfwSwapBuffers(window);
// ==================================================== // ====================================================
spdlog::info("Loading icons"); spdlog::info("Loading icons");

View File

@ -1,4 +1,4 @@
#include <bandplan.h> #include <gui/bandplan.h>
namespace bandplan { namespace bandplan {
std::map<std::string, BandPlan_t> bandplans; std::map<std::string, BandPlan_t> bandplans;

View File

@ -1,4 +1,4 @@
#include <frequency_select.h> #include <gui/frequency_select.h>
bool isInArea(ImVec2 val, ImVec2 min, ImVec2 max) { bool isInArea(ImVec2 val, ImVec2 min, ImVec2 max) {
return val.x >= min.x && val.x < max.x && val.y >= min.y && val.y < max.y; return val.x >= min.x && val.x < max.x && val.y >= min.y && val.y < max.y;

6
core/src/gui/gui.cpp Normal file
View File

@ -0,0 +1,6 @@
#include <gui/gui.h>
namespace gui {
ImGui::WaterFall waterfall;
FrequencySelect freqSelect;
};

9
core/src/gui/gui.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <gui/waterfall.h>
#include <gui/frequency_select.h>
#include <module.h>
namespace gui {
SDRPP_EXPORT ImGui::WaterFall waterfall;
SDRPP_EXPORT FrequencySelect freqSelect;
};

View File

@ -1,4 +1,4 @@
#include <icons.h> #include <gui/icons.h>
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include <imgui/stb_image.h> #include <imgui/stb_image.h>

View File

@ -1,9 +1,8 @@
#include <main_window.h> #include <gui/main_window.h>
#include <gui/gui.h>
std::thread worker; std::thread worker;
std::mutex fft_mtx; std::mutex fft_mtx;
ImGui::WaterFall wtf;
FrequencySelect fSel;
fftwf_complex *fft_in, *fft_out; fftwf_complex *fft_in, *fft_out;
fftwf_plan p; fftwf_plan p;
float* tempData; float* tempData;
@ -14,8 +13,6 @@ ImFont* bigFont;
int fftSize = 8192 * 8; int fftSize = 8192 * 8;
io::SoapyWrapper soapy; io::SoapyWrapper soapy;
SignalPath sigPath;
std::vector<float> _data; std::vector<float> _data;
std::vector<float> fftTaps; std::vector<float> fftTaps;
void fftHandler(dsp::complex_t* samples) { void fftHandler(dsp::complex_t* samples) {
@ -33,7 +30,7 @@ void fftHandler(dsp::complex_t* samples) {
_data[i] = (_data[i - 4] + _data[i - 3] + _data[i - 2] + _data[i - 1] + _data[i]) / 5.0f; _data[i] = (_data[i - 4] + _data[i - 3] + _data[i - 2] + _data[i - 1] + _data[i]) / 5.0f;
} }
wtf.pushFFT(_data, fftSize); gui::waterfall.pushFFT(_data, fftSize);
_data.clear(); _data.clear();
} }
@ -87,7 +84,7 @@ void loadSourceConfig(std::string name) {
else { else {
srId = std::distance(soapy.sampleRates.begin(), _srIt); srId = std::distance(soapy.sampleRates.begin(), _srIt);
} }
sigPath.setSampleRate(sampleRate); sigpath::signalPath.setSampleRate(sampleRate);
soapy.setSampleRate(sampleRate); soapy.setSampleRate(sampleRate);
// Set gains // Set gains
@ -107,8 +104,8 @@ void loadSourceConfig(std::string name) {
} }
// Update GUI // Update GUI
wtf.setBandwidth(sampleRate); gui::waterfall.setBandwidth(sampleRate);
wtf.setViewBandwidth(sampleRate); gui::waterfall.setViewBandwidth(sampleRate);
bw.val = sampleRate; bw.val = sampleRate;
} }
@ -158,21 +155,19 @@ void windowInit() {
spdlog::info("Initializing SoapySDR"); spdlog::info("Initializing SoapySDR");
soapy.init(); soapy.init();
fSel.init(); gui::freqSelect.init();
fft_in = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize); fft_in = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
fft_out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize); fft_out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize);
p = fftwf_plan_dft_1d(fftSize, fft_in, fft_out, FFTW_FORWARD, FFTW_ESTIMATE); p = fftwf_plan_dft_1d(fftSize, fft_in, fft_out, FFTW_FORWARD, FFTW_ESTIMATE);
sigPath.init(sampleRate, 20, fftSize, &soapy.output, (dsp::complex_t*)fft_in, fftHandler); sigpath::signalPath.init(sampleRate, 20, fftSize, &soapy.output, (dsp::complex_t*)fft_in, fftHandler);
sigPath.start(); sigpath::signalPath.start();
vfoman::init(&wtf, &sigPath);
uiGains = new float[soapy.gainList.size()]; uiGains = new float[soapy.gainList.size()];
spdlog::info("Loading modules"); spdlog::info("Loading modules");
mod::initAPI(&wtf); mod::initAPI(&gui::waterfall);
mod::loadFromList(config::getRootDirectory() + "/module_list.json"); mod::loadFromList(config::getRootDirectory() + "/module_list.json");
bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF((config::getRootDirectory() + "/res/fonts/Roboto-Medium.ttf").c_str(), 128.0f); bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF((config::getRootDirectory() + "/res/fonts/Roboto-Medium.ttf").c_str(), 128.0f);
@ -206,7 +201,7 @@ void windowInit() {
sourceName = soapy.devNameList[0]; sourceName = soapy.devNameList[0];
} }
sampleRate = soapy.getSampleRate(); sampleRate = soapy.getSampleRate();
sigPath.setSampleRate(sampleRate); sigpath::signalPath.setSampleRate(sampleRate);
} }
// Search for the first source in the list to have a config // Search for the first source in the list to have a config
// If no pre-defined source, selected default device // If no pre-defined source, selected default device
@ -229,10 +224,10 @@ void windowInit() {
// Update UI settings // Update UI settings
fftMin = config::config["min"]; fftMin = config::config["min"];
fftMax = config::config["max"]; fftMax = config::config["max"];
wtf.setFFTMin(fftMin); gui::waterfall.setFFTMin(fftMin);
wtf.setWaterfallMin(fftMin); gui::waterfall.setWaterfallMin(fftMin);
wtf.setFFTMax(fftMax); gui::waterfall.setFFTMax(fftMax);
wtf.setWaterfallMax(fftMax); gui::waterfall.setWaterfallMax(fftMax);
bandPlanEnabled.val = config::config["bandPlanEnabled"]; bandPlanEnabled.val = config::config["bandPlanEnabled"];
bandPlanEnabled.markAsChanged(); bandPlanEnabled.markAsChanged();
@ -243,10 +238,10 @@ void windowInit() {
bandplanId.val = std::distance(bandplan::bandplans.begin(), bandplan::bandplans.find(bandPlanName)); bandplanId.val = std::distance(bandplan::bandplans.begin(), bandplan::bandplans.find(bandPlanName));
if (bandPlanEnabled.val) { if (bandPlanEnabled.val) {
wtf.bandplan = &bandplan::bandplans[bandPlanName]; gui::waterfall.bandplan = &bandplan::bandplans[bandPlanName];
} }
else { else {
wtf.bandplan = NULL; gui::waterfall.bandplan = NULL;
} }
} }
else { else {
@ -255,16 +250,16 @@ void windowInit() {
bandplanId.markAsChanged(); bandplanId.markAsChanged();
fSel.setFrequency(frequency); gui::freqSelect.setFrequency(frequency);
fSel.frequencyChanged = false; gui::freqSelect.frequencyChanged = false;
soapy.setFrequency(frequency); soapy.setFrequency(frequency);
wtf.setCenterFrequency(frequency); gui::waterfall.setCenterFrequency(frequency);
wtf.setBandwidth(sampleRate); gui::waterfall.setBandwidth(sampleRate);
wtf.setViewBandwidth(sampleRate); gui::waterfall.setViewBandwidth(sampleRate);
bw.val = sampleRate; bw.val = sampleRate;
wtf.vfoFreqChanged = false; gui::waterfall.vfoFreqChanged = false;
wtf.centerFreqMoved = false; gui::waterfall.centerFreqMoved = false;
wtf.selectFirstVFO(); gui::waterfall.selectFirstVFO();
for (auto [name, stream] : audio::streams) { for (auto [name, stream] : audio::streams) {
if (config::config["audio"].contains(name)) { if (config::config["audio"].contains(name)) {
@ -277,7 +272,7 @@ void windowInit() {
} }
} }
audioStreamName = audio::getNameFromVFO(wtf.selectedVFO); audioStreamName = audio::getNameFromVFO(gui::waterfall.selectedVFO);
if (audioStreamName != "") { if (audioStreamName != "") {
volume = &audio::streams[audioStreamName]->volume; volume = &audio::streams[audioStreamName]->volume;
} }
@ -287,18 +282,18 @@ void windowInit() {
showWaterfall = config::config["showWaterfall"]; showWaterfall = config::config["showWaterfall"];
if (!showWaterfall) { if (!showWaterfall) {
wtf.hideWaterfall(); gui::waterfall.hideWaterfall();
} }
fftHeight = config::config["fftHeight"]; fftHeight = config::config["fftHeight"];
wtf.setFFTHeight(fftHeight); gui::waterfall.setFFTHeight(fftHeight);
} }
void setVFO(float freq) { void setVFO(float freq) {
ImGui::WaterfallVFO* vfo = wtf.vfos[wtf.selectedVFO]; ImGui::WaterfallVFO* vfo = gui::waterfall.vfos[gui::waterfall.selectedVFO];
float currentOff = vfo->centerOffset; float currentOff = vfo->centerOffset;
float currentTune = wtf.getCenterFrequency() + vfo->generalOffset; float currentTune = gui::waterfall.getCenterFrequency() + vfo->generalOffset;
float delta = freq - currentTune; float delta = freq - currentTune;
float newVFO = currentOff + delta; float newVFO = currentOff + delta;
@ -306,38 +301,38 @@ void setVFO(float freq) {
float vfoBottom = newVFO - (vfoBW / 2.0f); float vfoBottom = newVFO - (vfoBW / 2.0f);
float vfoTop = newVFO + (vfoBW / 2.0f); float vfoTop = newVFO + (vfoBW / 2.0f);
float view = wtf.getViewOffset(); float view = gui::waterfall.getViewOffset();
float viewBW = wtf.getViewBandwidth(); float viewBW = gui::waterfall.getViewBandwidth();
float viewBottom = view - (viewBW / 2.0f); float viewBottom = view - (viewBW / 2.0f);
float viewTop = view + (viewBW / 2.0f); float viewTop = view + (viewBW / 2.0f);
float wholeFreq = wtf.getCenterFrequency(); float wholeFreq = gui::waterfall.getCenterFrequency();
float BW = wtf.getBandwidth(); float BW = gui::waterfall.getBandwidth();
float bottom = -(BW / 2.0f); float bottom = -(BW / 2.0f);
float top = (BW / 2.0f); float top = (BW / 2.0f);
// VFO still fints in the view // VFO still fints in the view
if (vfoBottom > viewBottom && vfoTop < viewTop) { if (vfoBottom > viewBottom && vfoTop < viewTop) {
vfoman::setCenterOffset(wtf.selectedVFO, newVFO); sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFO);
return; return;
} }
// VFO too low for current SDR tuning // VFO too low for current SDR tuning
if (vfoBottom < bottom) { if (vfoBottom < bottom) {
wtf.setViewOffset((BW / 2.0f) - (viewBW / 2.0f)); gui::waterfall.setViewOffset((BW / 2.0f) - (viewBW / 2.0f));
float newVFOOffset = (BW / 2.0f) - (vfoBW / 2.0f) - (viewBW / 10.0f); float newVFOOffset = (BW / 2.0f) - (vfoBW / 2.0f) - (viewBW / 10.0f);
vfoman::setCenterOffset(wtf.selectedVFO, newVFOOffset); sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset);
wtf.setCenterFrequency(freq - newVFOOffset); gui::waterfall.setCenterFrequency(freq - newVFOOffset);
soapy.setFrequency(freq - newVFOOffset); soapy.setFrequency(freq - newVFOOffset);
return; return;
} }
// VFO too high for current SDR tuning // VFO too high for current SDR tuning
if (vfoTop > top) { if (vfoTop > top) {
wtf.setViewOffset((viewBW / 2.0f) - (BW / 2.0f)); gui::waterfall.setViewOffset((viewBW / 2.0f) - (BW / 2.0f));
float newVFOOffset = (vfoBW / 2.0f) - (BW / 2.0f) + (viewBW / 10.0f); float newVFOOffset = (vfoBW / 2.0f) - (BW / 2.0f) + (viewBW / 10.0f);
vfoman::setCenterOffset(wtf.selectedVFO, newVFOOffset); sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset);
wtf.setCenterFrequency(freq - newVFOOffset); gui::waterfall.setCenterFrequency(freq - newVFOOffset);
soapy.setFrequency(freq - newVFOOffset); soapy.setFrequency(freq - newVFOOffset);
return; return;
} }
@ -349,15 +344,15 @@ void setVFO(float freq) {
float newViewTop = newViewOff + (viewBW / 2.0f); float newViewTop = newViewOff + (viewBW / 2.0f);
if (newViewBottom > bottom) { if (newViewBottom > bottom) {
wtf.setViewOffset(newViewOff); gui::waterfall.setViewOffset(newViewOff);
vfoman::setCenterOffset(wtf.selectedVFO, newVFO); sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFO);
return; return;
} }
wtf.setViewOffset((BW / 2.0f) - (viewBW / 2.0f)); gui::waterfall.setViewOffset((BW / 2.0f) - (viewBW / 2.0f));
float newVFOOffset = (BW / 2.0f) - (vfoBW / 2.0f) - (viewBW / 10.0f); float newVFOOffset = (BW / 2.0f) - (vfoBW / 2.0f) - (viewBW / 10.0f);
vfoman::setCenterOffset(wtf.selectedVFO, newVFOOffset); sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset);
wtf.setCenterFrequency(freq - newVFOOffset); gui::waterfall.setCenterFrequency(freq - newVFOOffset);
soapy.setFrequency(freq - newVFOOffset); soapy.setFrequency(freq - newVFOOffset);
} }
else { else {
@ -366,15 +361,15 @@ void setVFO(float freq) {
float newViewTop = newViewOff + (viewBW / 2.0f); float newViewTop = newViewOff + (viewBW / 2.0f);
if (newViewTop < top) { if (newViewTop < top) {
wtf.setViewOffset(newViewOff); gui::waterfall.setViewOffset(newViewOff);
vfoman::setCenterOffset(wtf.selectedVFO, newVFO); sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFO);
return; return;
} }
wtf.setViewOffset((viewBW / 2.0f) - (BW / 2.0f)); gui::waterfall.setViewOffset((viewBW / 2.0f) - (BW / 2.0f));
float newVFOOffset = (vfoBW / 2.0f) - (BW / 2.0f) + (viewBW / 10.0f); float newVFOOffset = (vfoBW / 2.0f) - (BW / 2.0f) + (viewBW / 10.0f);
vfoman::setCenterOffset(wtf.selectedVFO, newVFOOffset); sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset);
wtf.setCenterFrequency(freq - newVFOOffset); gui::waterfall.setCenterFrequency(freq - newVFOOffset);
soapy.setFrequency(freq - newVFOOffset); soapy.setFrequency(freq - newVFOOffset);
} }
} }
@ -382,61 +377,61 @@ void setVFO(float freq) {
void drawWindow() { void drawWindow() {
ImGui::Begin("Main", NULL, WINDOW_FLAGS); ImGui::Begin("Main", NULL, WINDOW_FLAGS);
ImGui::WaterfallVFO* vfo = wtf.vfos[wtf.selectedVFO]; ImGui::WaterfallVFO* vfo = gui::waterfall.vfos[gui::waterfall.selectedVFO];
if (vfo->centerOffsetChanged) { if (vfo->centerOffsetChanged) {
fSel.setFrequency(wtf.getCenterFrequency() + vfo->generalOffset); gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency() + vfo->generalOffset);
fSel.frequencyChanged = false; gui::freqSelect.frequencyChanged = false;
config::config["frequency"] = fSel.frequency; config::config["frequency"] = gui::freqSelect.frequency;
config::configModified = true; config::configModified = true;
} }
vfoman::updateFromWaterfall(); sigpath::vfoManager.updateFromWaterfall(&gui::waterfall);
if (wtf.selectedVFOChanged) { if (gui::waterfall.selectedVFOChanged) {
wtf.selectedVFOChanged = false; gui::waterfall.selectedVFOChanged = false;
fSel.setFrequency(vfo->generalOffset + wtf.getCenterFrequency()); gui::freqSelect.setFrequency(vfo->generalOffset + gui::waterfall.getCenterFrequency());
fSel.frequencyChanged = false; gui::freqSelect.frequencyChanged = false;
mod::broadcastEvent(mod::EVENT_SELECTED_VFO_CHANGED); mod::broadcastEvent(mod::EVENT_SELECTED_VFO_CHANGED);
audioStreamName = audio::getNameFromVFO(wtf.selectedVFO); audioStreamName = audio::getNameFromVFO(gui::waterfall.selectedVFO);
if (audioStreamName != "") { if (audioStreamName != "") {
volume = &audio::streams[audioStreamName]->volume; volume = &audio::streams[audioStreamName]->volume;
} }
config::config["frequency"] = fSel.frequency; config::config["frequency"] = gui::freqSelect.frequency;
config::configModified = true; config::configModified = true;
} }
if (fSel.frequencyChanged) { if (gui::freqSelect.frequencyChanged) {
fSel.frequencyChanged = false; gui::freqSelect.frequencyChanged = false;
setVFO(fSel.frequency); setVFO(gui::freqSelect.frequency);
vfo->centerOffsetChanged = false; vfo->centerOffsetChanged = false;
vfo->lowerOffsetChanged = false; vfo->lowerOffsetChanged = false;
vfo->upperOffsetChanged = false; vfo->upperOffsetChanged = false;
config::config["frequency"] = fSel.frequency; config::config["frequency"] = gui::freqSelect.frequency;
config::configModified = true; config::configModified = true;
} }
if (wtf.centerFreqMoved) { if (gui::waterfall.centerFreqMoved) {
wtf.centerFreqMoved = false; gui::waterfall.centerFreqMoved = false;
soapy.setFrequency(wtf.getCenterFrequency()); soapy.setFrequency(gui::waterfall.getCenterFrequency());
fSel.setFrequency(wtf.getCenterFrequency() + vfo->generalOffset); gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency() + vfo->generalOffset);
config::config["frequency"] = fSel.frequency; config::config["frequency"] = gui::freqSelect.frequency;
config::configModified = true; config::configModified = true;
} }
if (dcbias.changed()) { if (dcbias.changed()) {
sigPath.setDCBiasCorrection(dcbias.val); sigpath::signalPath.setDCBiasCorrection(dcbias.val);
} }
if (bandplanId.changed() && bandPlanEnabled.val) { if (bandplanId.changed() && bandPlanEnabled.val) {
wtf.bandplan = &bandplan::bandplans[bandplan::bandplanNames[bandplanId.val]]; gui::waterfall.bandplan = &bandplan::bandplans[bandplan::bandplanNames[bandplanId.val]];
} }
if (bandPlanEnabled.changed()) { if (bandPlanEnabled.changed()) {
wtf.bandplan = bandPlanEnabled.val ? &bandplan::bandplans[bandplan::bandplanNames[bandplanId.val]] : NULL; gui::waterfall.bandplan = bandPlanEnabled.val ? &bandplan::bandplans[bandplan::bandplanNames[bandplanId.val]] : NULL;
} }
int _fftHeight = wtf.getFFTHeight(); int _fftHeight = gui::waterfall.getFFTHeight();
if (fftHeight != _fftHeight) { if (fftHeight != _fftHeight) {
fftHeight = _fftHeight; fftHeight = _fftHeight;
config::config["fftHeight"] = fftHeight; config::config["fftHeight"] = fftHeight;
@ -472,7 +467,7 @@ void drawWindow() {
else { else {
if (ImGui::ImageButton(icons::PLAY, ImVec2(40, 40), ImVec2(0, 0), ImVec2(1, 1), 0) && soapy.devList.size() > 0) { if (ImGui::ImageButton(icons::PLAY, ImVec2(40, 40), ImVec2(0, 0), ImVec2(1, 1), 0) && soapy.devList.size() > 0) {
soapy.start(); soapy.start();
soapy.setFrequency(wtf.getCenterFrequency()); soapy.setFrequency(gui::waterfall.getCenterFrequency());
playing = true; playing = true;
} }
} }
@ -494,7 +489,7 @@ void drawWindow() {
ImGui::SameLine(); ImGui::SameLine();
fSel.draw(); gui::freqSelect.draw();
ImGui::SameLine(); ImGui::SameLine();
@ -564,9 +559,9 @@ void drawWindow() {
srId = 0; srId = 0;
sampleRate = soapy.getSampleRate(); sampleRate = soapy.getSampleRate();
bw.val = sampleRate; bw.val = sampleRate;
wtf.setBandwidth(sampleRate); gui::waterfall.setBandwidth(sampleRate);
wtf.setViewBandwidth(sampleRate); gui::waterfall.setViewBandwidth(sampleRate);
sigPath.setSampleRate(sampleRate); sigpath::signalPath.setSampleRate(sampleRate);
if (soapy.gainList.size() >= 0) { if (soapy.gainList.size() >= 0) {
delete[] uiGains; delete[] uiGains;
@ -576,7 +571,7 @@ void drawWindow() {
} }
} }
} }
setVFO(fSel.frequency); setVFO(gui::freqSelect.frequency);
config::config["source"] = sourceName; config::config["source"] = sourceName;
config::configModified = true; config::configModified = true;
} }
@ -586,9 +581,9 @@ void drawWindow() {
spdlog::info("Changed sample rate: {0}", srId); spdlog::info("Changed sample rate: {0}", srId);
sampleRate = soapy.sampleRates[srId]; sampleRate = soapy.sampleRates[srId];
soapy.setSampleRate(sampleRate); soapy.setSampleRate(sampleRate);
wtf.setBandwidth(sampleRate); gui::waterfall.setBandwidth(sampleRate);
wtf.setViewBandwidth(sampleRate); gui::waterfall.setViewBandwidth(sampleRate);
sigPath.setSampleRate(sampleRate); sigpath::signalPath.setSampleRate(sampleRate);
bw.val = sampleRate; bw.val = sampleRate;
if (!config::config["sourceSettings"].contains(sourceName)) { if (!config::config["sourceSettings"].contains(sourceName)) {
@ -739,7 +734,7 @@ void drawWindow() {
if (ImGui::CollapsingHeader("Display", ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::CollapsingHeader("Display", ImGuiTreeNodeFlags_DefaultOpen)) {
if (ImGui::Checkbox("Show waterfall", &showWaterfall)) { if (ImGui::Checkbox("Show waterfall", &showWaterfall)) {
showWaterfall ? wtf.showWaterfall() : wtf.hideWaterfall(); showWaterfall ? gui::waterfall.showWaterfall() : gui::waterfall.hideWaterfall();
} }
ImGui::Spacing(); ImGui::Spacing();
} }
@ -747,7 +742,7 @@ void drawWindow() {
if(ImGui::CollapsingHeader("Debug")) { if(ImGui::CollapsingHeader("Debug")) {
ImGui::Text("Frame time: %.3f ms/frame", 1000.0f / ImGui::GetIO().Framerate); ImGui::Text("Frame time: %.3f ms/frame", 1000.0f / ImGui::GetIO().Framerate);
ImGui::Text("Framerate: %.1f FPS", ImGui::GetIO().Framerate); ImGui::Text("Framerate: %.1f FPS", ImGui::GetIO().Framerate);
ImGui::Text("Center Frequency: %.0f Hz", wtf.getCenterFrequency()); ImGui::Text("Center Frequency: %.0f Hz", gui::waterfall.getCenterFrequency());
ImGui::Text("Source name: %s", sourceName.c_str()); ImGui::Text("Source name: %s", sourceName.c_str());
ImGui::Spacing(); ImGui::Spacing();
} }
@ -769,7 +764,7 @@ void drawWindow() {
ImGui::BeginChild("Waterfall"); ImGui::BeginChild("Waterfall");
wtf.draw(); gui::waterfall.draw();
ImGui::EndChild(); ImGui::EndChild();
@ -807,14 +802,14 @@ void drawWindow() {
ImGui::EndChild(); ImGui::EndChild();
if (bw.changed()) { if (bw.changed()) {
wtf.setViewBandwidth(bw.val); gui::waterfall.setViewBandwidth(bw.val);
wtf.setViewOffset(vfo->centerOffset); gui::waterfall.setViewOffset(vfo->centerOffset);
} }
wtf.setFFTMin(fftMin); gui::waterfall.setFFTMin(fftMin);
wtf.setFFTMax(fftMax); gui::waterfall.setFFTMax(fftMax);
wtf.setWaterfallMin(fftMin); gui::waterfall.setWaterfallMin(fftMin);
wtf.setWaterfallMax(fftMax); gui::waterfall.setWaterfallMax(fftMax);
ImGui::End(); ImGui::End();

View File

@ -13,19 +13,20 @@
#include <complex> #include <complex>
#include <dsp/source.h> #include <dsp/source.h>
#include <dsp/math.h> #include <dsp/math.h>
#include <waterfall.h> #include <gui/waterfall.h>
#include <frequency_select.h> #include <gui/frequency_select.h>
#include <fftw3.h> #include <fftw3.h>
#include <signal_path.h> #include <signal_path/dsp.h>
#include <io/soapy.h> #include <io/soapy.h>
#include <icons.h> #include <gui/icons.h>
#include <bandplan.h> #include <gui/bandplan.h>
#include <watcher.h> #include <watcher.h>
#include <module.h> #include <module.h>
#include <vfo_manager.h> #include <signal_path/vfo_manager.h>
#include <audio.h> #include <signal_path/audio.h>
#include <style.h> #include <gui/style.h>
#include <config.h> #include <config.h>
#include <signal_path/signal_path.h>
#define WINDOW_FLAGS ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground #define WINDOW_FLAGS ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground

24
core/src/gui/menu.cpp Normal file
View File

@ -0,0 +1,24 @@
#include <gui/menu.h>
Menu::Menu() {
}
void Menu::registerEntry(std::string name, void (*drawHandler)(void* ctx), void* ctx) {
MenuItem_t item;
item.drawHandler = drawHandler;
item.ctx = ctx;
items[name] = item;
}
void Menu::removeEntry(std::string name) {
items.erase(name);
}
void Menu::draw() {
MenuItem_t item;
for (std::string name : order) {
item = items[name];
item.drawHandler(item.ctx);
}
}

23
core/src/gui/menu.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include <string>
#include <vector>
#include <map>
class Menu {
public:
Menu();
struct MenuItem_t {
void (*drawHandler)(void* ctx);
void* ctx;
};
void registerEntry(std::string name, void (*drawHandler)(void* ctx), void* ctx = NULL);
void removeEntry(std::string name);
void draw();
std::vector<std::string> order;
private:
std::map<std::string, MenuItem_t> items;
};

View File

@ -1,4 +1,4 @@
#include <style.h> #include <gui/style.h>
namespace style { namespace style {
void setDefaultStyle() { void setDefaultStyle() {

View File

@ -1,4 +1,4 @@
#include <waterfall.h> #include <gui/waterfall.h>
float COLOR_MAP[][3] = { float COLOR_MAP[][3] = {
{0x00, 0x00, 0x20}, {0x00, 0x00, 0x20},
@ -650,6 +650,7 @@ namespace ImGui {
} }
void WaterfallVFO::setOffset(float offset) { void WaterfallVFO::setOffset(float offset) {
printf("WaterfallVFO::SetOffset: %p\n", this);
generalOffset = offset; generalOffset = offset;
if (reference == REF_CENTER) { if (reference == REF_CENTER) {
centerOffset = offset; centerOffset = offset;

View File

@ -5,7 +5,7 @@
#include <mutex> #include <mutex>
#include <GL/glew.h> #include <GL/glew.h>
#include <imutils.h> #include <imutils.h>
#include <bandplan.h> #include <gui/bandplan.h>
#include <algorithm> #include <algorithm>
#define WATERFALL_RESOLUTION 1000000 #define WATERFALL_RESOLUTION 1000000

View File

@ -1,7 +1,7 @@
#include <module.h> #include <module.h>
#include <vfo_manager.h> #include <signal_path/vfo_manager.h>
#include <main_window.h> #include <gui/main_window.h>
#include <audio.h> #include <signal_path/audio.h>
namespace mod { namespace mod {
API_t API; API_t API;
@ -16,16 +16,6 @@ namespace mod {
void initAPI(ImGui::WaterFall* wtf) { void initAPI(ImGui::WaterFall* wtf) {
_wtf = wtf; _wtf = wtf;
// VFO Manager
API.registerVFO = vfoman::create;
API.setVFOOffset = vfoman::setOffset;
API.setVFOCenterOffset = vfoman::setCenterOffset;
API.setVFOBandwidth = vfoman::setBandwidth;
API.setVFOSampleRate = vfoman::setSampleRate;
API.getVFOOutputBlockSize = vfoman::getOutputBlockSize;
API.setVFOReference = vfoman::setReference;
API.removeVFO = vfoman::remove;
// GUI // GUI
API.getSelectedVFOName = api_getSelectedVFOName; API.getSelectedVFOName = api_getSelectedVFOName;
API.bindVolumeVariable = bindVolumeVariable; API.bindVolumeVariable = bindVolumeVariable;

View File

@ -7,16 +7,25 @@
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <dsp/types.h> #include <dsp/types.h>
#include <dsp/stream.h> #include <dsp/stream.h>
#include <waterfall.h> #include <gui/waterfall.h>
#include <json.hpp> #include <json.hpp>
#ifdef _WIN32
#ifdef SDRPP_IS_CORE
#define SDRPP_EXPORT extern "C" __declspec(dllexport)
#else
#define SDRPP_EXPORT extern "C" __declspec(dllimport)
#endif
#else
#define SDRPP_EXPORT /**/
#endif
#ifdef _WIN32 #ifdef _WIN32
#include <Windows.h> #include <Windows.h>
#define MOD_EXPORT extern "C" \ #define MOD_EXPORT extern "C" __declspec(dllexport)
__declspec(dllexport)
#else #else
#include <dlfcn.h> #include <dlfcn.h>
#define MOD_EXPORT extern "C" #define MOD_EXPORT extern "C"
#endif #endif
namespace mod { namespace mod {

View File

@ -1,4 +1,4 @@
#include <audio.h> #include <signal_path/audio.h>
namespace audio { namespace audio {
std::map<std::string, AudioStream_t*> streams; std::map<std::string, AudioStream_t*> streams;

View File

@ -1,4 +1,4 @@
#include <signal_path.h> #include <signal_path/dsp.h>
SignalPath::SignalPath() { SignalPath::SignalPath() {

View File

@ -0,0 +1,6 @@
#include <signal_path/signal_path.h>
namespace sigpath {
SignalPath signalPath;
VFOManager vfoManager;
};

View File

@ -0,0 +1,9 @@
#pragma once
#include <signal_path/dsp.h>
#include <signal_path/vfo_manager.h>
#include <module.h>
namespace sigpath {
SDRPP_EXPORT SignalPath signalPath;
SDRPP_EXPORT VFOManager vfoManager;
};

View File

@ -0,0 +1,128 @@
#include <signal_path/vfo_manager.h>
#include <signal_path/signal_path.h>
VFOManager::VFO::VFO(std::string name, int reference, float offset, float bandwidth, float sampleRate, int blockSize) {
this->name = name;
dspVFO = sigpath::signalPath.addVFO(name, sampleRate, bandwidth, offset);
wtfVFO = new ImGui::WaterfallVFO;
wtfVFO->setReference(reference);
wtfVFO->setBandwidth(bandwidth);
wtfVFO->setOffset(offset);
output = dspVFO->output;
printf("Created VFO: %p", wtfVFO);
gui::waterfall.vfos[name] = wtfVFO;
}
VFOManager::VFO::~VFO() {
gui::waterfall.vfos.erase(name);
sigpath::signalPath.removeVFO(name);
delete wtfVFO;
}
void VFOManager::VFO::setOffset(float offset) {
wtfVFO->setOffset(offset);
dspVFO->setOffset(wtfVFO->centerOffset);
}
void VFOManager::VFO::setCenterOffset(float offset) {
wtfVFO->setCenterOffset(offset);
dspVFO->setOffset(offset);
}
void VFOManager::VFO::setBandwidth(float bandwidth) {
wtfVFO->setBandwidth(bandwidth);
dspVFO->setBandwidth(bandwidth);
}
void VFOManager::VFO::setSampleRate(float sampleRate, float bandwidth) {
dspVFO->setOutputSampleRate(sampleRate, bandwidth);
wtfVFO->setBandwidth(bandwidth);
}
void VFOManager::VFO::setReference(int ref) {
wtfVFO->setReference(ref);
}
int VFOManager::VFO::getOutputBlockSize() {
return dspVFO->getOutputBlockSize();
}
VFOManager::VFOManager() {
}
VFOManager::VFO* VFOManager::createVFO(std::string name, int reference, float offset, float bandwidth, float sampleRate, int blockSize) {
if (vfos.find(name) != vfos.end() || name == "") {
return NULL;
}
VFOManager::VFO* vfo = new VFO(name, reference, offset, bandwidth, sampleRate, blockSize);
vfos[name] = vfo;
return vfo;
}
void VFOManager::deleteVFO(VFOManager::VFO* vfo) {
std::string name = "";
for (auto const& [_name, _vfo] : vfos) {
if (_vfo == vfo) {
name == _name;
break;
}
}
if (name == "") {
return;
}
vfos.erase(name);
}
void VFOManager::setOffset(std::string name, float offset) {
if (vfos.find(name) == vfos.end()) {
return;
}
vfos[name]->setOffset(offset);
}
void VFOManager::setCenterOffset(std::string name, float offset) {
if (vfos.find(name) == vfos.end()) {
return;
}
vfos[name]->setCenterOffset(offset);
}
void VFOManager::setBandwidth(std::string name, float bandwidth) {
if (vfos.find(name) == vfos.end()) {
return;
}
vfos[name]->setBandwidth(bandwidth);
}
void VFOManager::setSampleRate(std::string name, float sampleRate, float bandwidth) {
if (vfos.find(name) == vfos.end()) {
return;
}
vfos[name]->setSampleRate(sampleRate, bandwidth);
}
void VFOManager::setReference(std::string name, int ref) {
if (vfos.find(name) == vfos.end()) {
return;
}
vfos[name]->setReference(ref);
}
int VFOManager::getOutputBlockSize(std::string name) {
if (vfos.find(name) == vfos.end()) {
return -1;
}
return vfos[name]->getOutputBlockSize();
}
void VFOManager::updateFromWaterfall(ImGui::WaterFall* wtf) {
for (auto const& [name, vfo] : vfos) {
if (vfo->wtfVFO->centerOffsetChanged) {
spdlog::info("UH OH: Change!");
vfo->wtfVFO->centerOffsetChanged = false;
vfo->dspVFO->setOffset(vfo->wtfVFO->centerOffset);
}
}
}

View File

@ -0,0 +1,47 @@
#pragma once
#include <dsp/vfo.h>
#include <gui/waterfall.h>
#include <gui/gui.h>
class VFOManager {
public:
VFOManager();
class VFO {
public:
VFO(std::string name, int reference, float offset, float bandwidth, float sampleRate, int blockSize);
~VFO();
void setOffset(float offset);
void setCenterOffset(float offset);
void setBandwidth(float bandwidth);
void setSampleRate(float sampleRate, float bandwidth);
void setReference(int ref);
int getOutputBlockSize();
dsp::stream<dsp::complex_t>* output;
friend class VFOManager;
private:
std::string name;
dsp::VFO* dspVFO;
ImGui::WaterfallVFO* wtfVFO;
};
VFOManager::VFO* createVFO(std::string name, int reference, float offset, float bandwidth, float sampleRate, int blockSize);
void deleteVFO(VFOManager::VFO* vfo);
void setOffset(std::string name, float offset);
void setCenterOffset(std::string name, float offset);
void setBandwidth(std::string name, float bandwidth);
void setSampleRate(std::string name, float sampleRate, float bandwidth);
void setReference(std::string name, int ref);
int getOutputBlockSize(std::string name);
void updateFromWaterfall(ImGui::WaterFall* wtf);
private:
std::map<std::string, VFO*> vfos;
};

View File

@ -1,99 +0,0 @@
#include <vfo_manager.h>
namespace vfoman {
std::map<std::string, VFO_t> vfos;
ImGui::WaterFall* _wtf;
SignalPath* _sigPath;
void init(ImGui::WaterFall* wtf, SignalPath* sigPath) {
_wtf = wtf;
_sigPath = sigPath;
}
dsp::stream<dsp::complex_t>* create(std::string name, int reference, float offset, float bandwidth, float sampleRate, int blockSize) {
if (vfos.find(name) != vfos.end()) {
spdlog::warn("Tried to add VFO with an already existing name: {0}", name);
return NULL;
}
spdlog::info("Creating new VFO '{0}'", name);
VFO_t vfo;
vfo.dspVFO = _sigPath->addVFO(name, sampleRate, bandwidth, offset);
vfo.wtfVFO = new ImGui::WaterfallVFO;
vfo.wtfVFO->setReference(reference);
vfo.wtfVFO->setBandwidth(bandwidth);
vfo.wtfVFO->setOffset(offset);
_wtf->vfos[name] = vfo.wtfVFO;
vfos[name] = vfo;
return vfo.dspVFO->output;
}
void setOffset(std::string name, float offset) {
if (vfos.find(name) == vfos.end()) {
return;
}
VFO_t vfo = vfos[name];
vfo.wtfVFO->setOffset(offset);
vfo.dspVFO->setOffset(vfo.wtfVFO->centerOffset);
}
void setCenterOffset(std::string name, float offset) {
if (vfos.find(name) == vfos.end()) {
return;
}
VFO_t vfo = vfos[name];
vfo.wtfVFO->setCenterOffset(offset);
vfo.dspVFO->setOffset(offset);
}
void setBandwidth(std::string name, float bandwidth) {
if (vfos.find(name) == vfos.end()) {
return;
}
VFO_t vfo = vfos[name];
vfo.wtfVFO->setBandwidth(bandwidth);
vfo.dspVFO->setBandwidth(bandwidth);
}
void setSampleRate(std::string name, float sampleRate, float bandwidth) {
if (vfos.find(name) == vfos.end()) {
return;
}
VFO_t vfo = vfos[name];
vfo.dspVFO->setOutputSampleRate(sampleRate, bandwidth);
vfo.wtfVFO->setBandwidth(bandwidth);
}
void setReference(std::string name, int ref){
if (vfos.find(name) == vfos.end()) {
return;
}
vfos[name].wtfVFO->setReference(ref);
}
int getOutputBlockSize(std::string name) {
if (vfos.find(name) == vfos.end()) {
return -1;
}
return vfos[name].dspVFO->getOutputBlockSize();
}
void remove(std::string name) {
if (vfos.find(name) == vfos.end()) {
return;
}
VFO_t vfo = vfos[name];
_wtf->vfos.erase(name);
_sigPath->removeVFO(name);
delete vfo.wtfVFO;
vfos.erase(name);
}
void updateFromWaterfall() {
for (auto const& [name, vfo] : vfos) {
if (vfo.wtfVFO->centerOffsetChanged) {
vfo.wtfVFO->centerOffsetChanged = false;
vfo.dspVFO->setOffset(vfo.wtfVFO->centerOffset);
}
}
}
};

View File

@ -1,24 +0,0 @@
#pragma once
#include <dsp/vfo.h>
#include <waterfall.h>
#include <signal_path.h>
namespace vfoman {
struct VFO_t {
dsp::VFO* dspVFO;
ImGui::WaterfallVFO* wtfVFO;
};
void init(ImGui::WaterFall* wtf, SignalPath* sigPath);
dsp::stream<dsp::complex_t>* create(std::string name, int reference, float offset, float bandwidth, float sampleRate, int blockSize);
void setOffset(std::string name, float offset);
void setCenterOffset(std::string name, float offset);
void setBandwidth(std::string name, float bandwidth);
void setSampleRate(std::string name, float sampleRate, float bandwidth);
void setReference(std::string name, int ref);
int getOutputBlockSize(std::string name);
void remove(std::string name);
void updateFromWaterfall();
};

View File

@ -1,6 +1,13 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
project(demo) project(demo)
if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17")
else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive -fsanitize=address -g")
# set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
endif (MSVC)
file(GLOB SRC "src/*.cpp") file(GLOB SRC "src/*.cpp")
add_library(demo SHARED ${SRC}) add_library(demo SHARED ${SRC})

View File

@ -6,7 +6,7 @@
#include <thread> #include <thread>
#include <ctime> #include <ctime>
#include <stdio.h> #include <stdio.h>
#include <style.h> #include <gui/style.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str()) #define CONCAT(a, b) ((std::string(a) + b).c_str())

View File

@ -3,53 +3,14 @@ project(radio)
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17") 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() else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fsanitize=address -g") set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive -fsanitize=address -g")
include_directories(radio "/usr/include/volk") # set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
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) 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 SRC "src/*.cpp")
file(GLOB IMGUI "../core/src/imgui/*.cpp")
add_library(radio SHARED ${SRC} ${IMGUI})
set_target_properties(radio PROPERTIES PREFIX "")
if (MSVC) include_directories("src/")
# Glew
find_package(GLEW REQUIRED)
target_link_libraries(radio PRIVATE GLEW::GLEW)
# GLFW3 add_library(radio SHARED ${SRC})
find_package(glfw3 CONFIG REQUIRED) target_link_libraries(radio PRIVATE sdrpp_core)
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"

View File

@ -25,7 +25,7 @@ MOD_EXPORT void* _INIT_(mod::API_t* _API, ImGuiContext* imctx, std::string _name
ctx->bandWidth = 200000; ctx->bandWidth = 200000;
ctx->bandWidthMin = 100000; ctx->bandWidthMin = 100000;
ctx->bandWidthMax = 200000; ctx->bandWidthMax = 200000;
ctx->sigPath.init(_name, 200000, 1000, API->registerVFO(_name, mod::API_t::REF_CENTER, 0, 200000, 200000, 1000)); ctx->sigPath.init(_name, 200000, 1000);
ctx->sigPath.start(); ctx->sigPath.start();
ImGui::SetCurrentContext(imctx); ImGui::SetCurrentContext(imctx);
return ctx; return ctx;
@ -49,7 +49,6 @@ MOD_EXPORT void _DRAW_MENU_(RadioContext_t* ctx) {
ctx->bandWidthMin = 8000; ctx->bandWidthMin = 8000;
ctx->bandWidthMax = 16000; ctx->bandWidthMax = 16000;
ctx->sigPath.setDemodulator(SigPath::DEMOD_NFM, ctx->bandWidth); 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) { if (ImGui::RadioButton(CONCAT("WFM##_", ctx->name), ctx->demod == 1) && ctx->demod != 1) {
ctx->demod = 1; ctx->demod = 1;
@ -57,7 +56,6 @@ MOD_EXPORT void _DRAW_MENU_(RadioContext_t* ctx) {
ctx->bandWidthMin = 100000; ctx->bandWidthMin = 100000;
ctx->bandWidthMax = 200000; ctx->bandWidthMax = 200000;
ctx->sigPath.setDemodulator(SigPath::DEMOD_FM, ctx->bandWidth); ctx->sigPath.setDemodulator(SigPath::DEMOD_FM, ctx->bandWidth);
API->setVFOReference(ctx->name, mod::API_t::REF_CENTER);
} }
ImGui::NextColumn(); ImGui::NextColumn();
if (ImGui::RadioButton(CONCAT("AM##_", ctx->name), ctx->demod == 2) && ctx->demod != 2) { if (ImGui::RadioButton(CONCAT("AM##_", ctx->name), ctx->demod == 2) && ctx->demod != 2) {
@ -66,7 +64,6 @@ MOD_EXPORT void _DRAW_MENU_(RadioContext_t* ctx) {
ctx->bandWidthMin = 6250; ctx->bandWidthMin = 6250;
ctx->bandWidthMax = 12500; ctx->bandWidthMax = 12500;
ctx->sigPath.setDemodulator(SigPath::DEMOD_AM, ctx->bandWidth); 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) { if (ImGui::RadioButton(CONCAT("DSB##_", ctx->name), ctx->demod == 3) && ctx->demod != 3) {
ctx->demod = 3; ctx->demod = 3;
@ -74,7 +71,6 @@ MOD_EXPORT void _DRAW_MENU_(RadioContext_t* ctx) {
ctx->bandWidthMin = 3000; ctx->bandWidthMin = 3000;
ctx->bandWidthMax = 6000; ctx->bandWidthMax = 6000;
ctx->sigPath.setDemodulator(SigPath::DEMOD_DSB, ctx->bandWidth); ctx->sigPath.setDemodulator(SigPath::DEMOD_DSB, ctx->bandWidth);
API->setVFOReference(ctx->name, mod::API_t::REF_CENTER);
} }
ImGui::NextColumn(); ImGui::NextColumn();
if (ImGui::RadioButton(CONCAT("USB##_", ctx->name), ctx->demod == 4) && ctx->demod != 4) { if (ImGui::RadioButton(CONCAT("USB##_", ctx->name), ctx->demod == 4) && ctx->demod != 4) {
@ -83,7 +79,6 @@ MOD_EXPORT void _DRAW_MENU_(RadioContext_t* ctx) {
ctx->bandWidthMin = 1500; ctx->bandWidthMin = 1500;
ctx->bandWidthMax = 3000; ctx->bandWidthMax = 3000;
ctx->sigPath.setDemodulator(SigPath::DEMOD_USB, ctx->bandWidth); 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; }; if (ImGui::RadioButton(CONCAT("CW##_", ctx->name), ctx->demod == 5) && ctx->demod != 5) { ctx->demod = 5; };
ImGui::NextColumn(); ImGui::NextColumn();
@ -93,7 +88,6 @@ MOD_EXPORT void _DRAW_MENU_(RadioContext_t* ctx) {
ctx->bandWidthMin = 1500; ctx->bandWidthMin = 1500;
ctx->bandWidthMax = 3000; ctx->bandWidthMax = 3000;
ctx->sigPath.setDemodulator(SigPath::DEMOD_LSB, ctx->bandWidth); 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) { if (ImGui::RadioButton(CONCAT("RAW##_", ctx->name), ctx->demod == 7) && ctx->demod != 7) {
ctx->demod = 7; ctx->demod = 7;
@ -101,7 +95,6 @@ MOD_EXPORT void _DRAW_MENU_(RadioContext_t* ctx) {
ctx->bandWidthMin = 3000; ctx->bandWidthMin = 3000;
ctx->bandWidthMax = 10000; ctx->bandWidthMax = 10000;
ctx->sigPath.setDemodulator(SigPath::DEMOD_RAW, ctx->bandWidth); 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::Columns(1, CONCAT("EndRadioModeColumns##_", ctx->name), false);

View File

@ -18,11 +18,13 @@ int SigPath::sampleRateChangeHandler(void* ctx, float sampleRate) {
return _this->audioResamp.getOutputBlockSize(); return _this->audioResamp.getOutputBlockSize();
} }
void SigPath::init(std::string vfoName, uint64_t sampleRate, int blockSize, dsp::stream<dsp::complex_t>* input) { void SigPath::init(std::string vfoName, uint64_t sampleRate, int blockSize) {
this->sampleRate = sampleRate; this->sampleRate = sampleRate;
this->blockSize = blockSize; this->blockSize = blockSize;
this->vfoName = vfoName; this->vfoName = vfoName;
vfo = sigpath::vfoManager.createVFO(vfoName, mod::API_t::REF_CENTER, 0, 200000, 200000, 1000);
_demod = DEMOD_FM; _demod = DEMOD_FM;
_deemp = DEEMP_50US; _deemp = DEEMP_50US;
bandwidth = 200000; bandwidth = 200000;
@ -31,10 +33,10 @@ void SigPath::init(std::string vfoName, uint64_t sampleRate, int blockSize, dsp:
// TODO: ajust deemphasis for different output sample rates // TODO: ajust deemphasis for different output sample rates
// TODO: Add a mono to stereo for different modes // TODO: Add a mono to stereo for different modes
demod.init(input, 100000, 200000, 800); demod.init(vfo->output, 100000, 200000, 800);
amDemod.init(input, 50); amDemod.init(vfo->output, 50);
ssbDemod.init(input, 6000, 3000, 22); ssbDemod.init(vfo->output, 6000, 3000, 22);
cpx2stereo.init(input, 22); cpx2stereo.init(vfo->output, 22);
audioResamp.init(&demod.output, 200000, 48000, 800); audioResamp.init(&demod.output, 200000, 48000, 800);
deemp.init(&audioResamp.output, 800, 50e-6, 48000); deemp.init(&audioResamp.output, 800, 50e-6, 48000);
@ -91,72 +93,79 @@ void SigPath::setDemodulator(int demId, float bandWidth) {
// Set input of the audio resampler // Set input of the audio resampler
// TODO: Set bandwidth from argument // TODO: Set bandwidth from argument
if (demId == DEMOD_FM) { if (demId == DEMOD_FM) {
API->setVFOSampleRate(vfoName, 200000, bandwidth); vfo->setSampleRate(200000, bandwidth);
demod.setBlockSize(API->getVFOOutputBlockSize(vfoName)); demod.setBlockSize(vfo->getOutputBlockSize());
demod.setSampleRate(200000); demod.setSampleRate(200000);
demod.setDeviation(bandwidth / 2.0f); demod.setDeviation(bandwidth / 2.0f);
audioResamp.setInput(&demod.output); audioResamp.setInput(&demod.output);
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f); audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
audioResamp.setInputSampleRate(200000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); audioResamp.setInputSampleRate(200000, vfo->getOutputBlockSize(), audioBw, audioBw);
deemp.bypass = (_deemp == DEEMP_NONE); deemp.bypass = (_deemp == DEEMP_NONE);
vfo->setReference(mod::API_t::REF_CENTER);
demod.start(); demod.start();
} }
else if (demId == DEMOD_NFM) { else if (demId == DEMOD_NFM) {
API->setVFOSampleRate(vfoName, 16000, bandwidth); vfo->setSampleRate(16000, bandwidth);
demod.setBlockSize(API->getVFOOutputBlockSize(vfoName)); demod.setBlockSize(vfo->getOutputBlockSize());
demod.setSampleRate(16000); demod.setSampleRate(16000);
demod.setDeviation(bandwidth / 2.0f); demod.setDeviation(bandwidth / 2.0f);
audioResamp.setInput(&demod.output); audioResamp.setInput(&demod.output);
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f); audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
audioResamp.setInputSampleRate(16000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); audioResamp.setInputSampleRate(16000, vfo->getOutputBlockSize(), audioBw, audioBw);
deemp.bypass = true; deemp.bypass = true;
vfo->setReference(mod::API_t::REF_CENTER);
demod.start(); demod.start();
} }
else if (demId == DEMOD_AM) { else if (demId == DEMOD_AM) {
API->setVFOSampleRate(vfoName, 12500, bandwidth); vfo->setSampleRate(12500, bandwidth);
amDemod.setBlockSize(API->getVFOOutputBlockSize(vfoName)); amDemod.setBlockSize(vfo->getOutputBlockSize());
audioResamp.setInput(&amDemod.output); audioResamp.setInput(&amDemod.output);
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f); audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
audioResamp.setInputSampleRate(12500, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); audioResamp.setInputSampleRate(12500, vfo->getOutputBlockSize(), audioBw, audioBw);
deemp.bypass = true; deemp.bypass = true;
vfo->setReference(mod::API_t::REF_CENTER);
amDemod.start(); amDemod.start();
} }
else if (demId == DEMOD_USB) { else if (demId == DEMOD_USB) {
API->setVFOSampleRate(vfoName, 6000, bandwidth); vfo->setSampleRate(6000, bandwidth);
ssbDemod.setBlockSize(API->getVFOOutputBlockSize(vfoName)); ssbDemod.setBlockSize(vfo->getOutputBlockSize());
ssbDemod.setMode(dsp::SSBDemod::MODE_USB); ssbDemod.setMode(dsp::SSBDemod::MODE_USB);
audioResamp.setInput(&ssbDemod.output); audioResamp.setInput(&ssbDemod.output);
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f); audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
audioResamp.setInputSampleRate(6000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); audioResamp.setInputSampleRate(6000, vfo->getOutputBlockSize(), audioBw, audioBw);
deemp.bypass = true; deemp.bypass = true;
vfo->setReference(mod::API_t::REF_LOWER);
ssbDemod.start(); ssbDemod.start();
} }
else if (demId == DEMOD_LSB) { else if (demId == DEMOD_LSB) {
API->setVFOSampleRate(vfoName, 6000, bandwidth); vfo->setSampleRate(6000, bandwidth);
ssbDemod.setBlockSize(API->getVFOOutputBlockSize(vfoName)); ssbDemod.setBlockSize(vfo->getOutputBlockSize());
ssbDemod.setMode(dsp::SSBDemod::MODE_LSB); ssbDemod.setMode(dsp::SSBDemod::MODE_LSB);
audioResamp.setInput(&ssbDemod.output); audioResamp.setInput(&ssbDemod.output);
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f); audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
audioResamp.setInputSampleRate(6000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); audioResamp.setInputSampleRate(6000, vfo->getOutputBlockSize(), audioBw, audioBw);
deemp.bypass = true; deemp.bypass = true;
vfo->setReference(mod::API_t::REF_UPPER);
ssbDemod.start(); ssbDemod.start();
} }
else if (demId == DEMOD_DSB) { else if (demId == DEMOD_DSB) {
API->setVFOSampleRate(vfoName, 6000, bandwidth); vfo->setSampleRate(6000, bandwidth);
ssbDemod.setBlockSize(API->getVFOOutputBlockSize(vfoName)); ssbDemod.setBlockSize(vfo->getOutputBlockSize());
ssbDemod.setMode(dsp::SSBDemod::MODE_DSB); ssbDemod.setMode(dsp::SSBDemod::MODE_DSB);
audioResamp.setInput(&ssbDemod.output); audioResamp.setInput(&ssbDemod.output);
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f); audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
audioResamp.setInputSampleRate(6000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); audioResamp.setInputSampleRate(6000, vfo->getOutputBlockSize(), audioBw, audioBw);
deemp.bypass = true; deemp.bypass = true;
vfo->setReference(mod::API_t::REF_CENTER);
ssbDemod.start(); ssbDemod.start();
} }
else if (demId == DEMOD_RAW) { else if (demId == DEMOD_RAW) {
API->setVFOSampleRate(vfoName, 10000, bandwidth); vfo->setSampleRate(10000, bandwidth);
cpx2stereo.setBlockSize(API->getVFOOutputBlockSize(vfoName)); cpx2stereo.setBlockSize(vfo->getOutputBlockSize());
//audioResamp.setInput(&cpx2stereo.output); //audioResamp.setInput(&cpx2stereo.output);
audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f); audioBw = std::min<float>(bandwidth, outputSampleRate / 2.0f);
audioResamp.setInputSampleRate(10000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); audioResamp.setInputSampleRate(10000, vfo->getOutputBlockSize(), audioBw, audioBw);
vfo->setReference(mod::API_t::REF_LOWER);
cpx2stereo.start(); cpx2stereo.start();
} }
else { else {
@ -192,7 +201,7 @@ void SigPath::setDeemphasis(int deemph) {
void SigPath::setBandwidth(float bandWidth) { void SigPath::setBandwidth(float bandWidth) {
bandwidth = bandWidth; bandwidth = bandWidth;
API->setVFOBandwidth(vfoName, bandwidth); vfo->setBandwidth(bandwidth);
if (_demod == DEMOD_FM) { if (_demod == DEMOD_FM) {
demod.stop(); demod.stop();
demod.setDeviation(bandwidth / 2.0f); demod.setDeviation(bandwidth / 2.0f);
@ -231,7 +240,7 @@ void SigPath::setBandwidth(float bandWidth) {
if (audioBw != _audioBw) { if (audioBw != _audioBw) {
audioBw = _audioBw; audioBw = _audioBw;
audioResamp.stop(); audioResamp.stop();
audioResamp.setInputSampleRate(6000, API->getVFOOutputBlockSize(vfoName), audioBw, audioBw); audioResamp.setInputSampleRate(6000, vfo->getOutputBlockSize(), audioBw, audioBw);
audioResamp.start(); audioResamp.start();
} }
} }

View File

@ -10,11 +10,12 @@
#include <dsp/vfo.h> #include <dsp/vfo.h>
#include <io/audio.h> #include <io/audio.h>
#include <module.h> #include <module.h>
#include <signal_path/signal_path.h>
class SigPath { class SigPath {
public: public:
SigPath(); SigPath();
void init(std::string vfoName, uint64_t sampleRate, int blockSize, dsp::stream<dsp::complex_t>* input); void init(std::string vfoName, uint64_t sampleRate, int blockSize);
void start(); void start();
void setSampleRate(float sampleRate); void setSampleRate(float sampleRate);
void setVFOFrequency(uint64_t frequency); void setVFOFrequency(uint64_t frequency);
@ -46,6 +47,8 @@ public:
private: private:
static int sampleRateChangeHandler(void* ctx, float sampleRate); static int sampleRateChangeHandler(void* ctx, float sampleRate);
VFOManager::VFO* vfo;
dsp::stream<dsp::complex_t> input; dsp::stream<dsp::complex_t> input;

View File

@ -3,13 +3,13 @@
"Radio": { "Radio": {
"device": "Speakers (Realtek High Definiti", "device": "Speakers (Realtek High Definiti",
"sampleRate": 48000.0, "sampleRate": 48000.0,
"volume": 0.4032258093357086 "volume": 0.6666666865348816
} }
}, },
"bandPlan": "General", "bandPlan": "General",
"bandPlanEnabled": true, "bandPlanEnabled": true,
"fftHeight": 300, "fftHeight": 300,
"frequency": 99000000, "frequency": 103200000,
"max": 0.0, "max": 0.0,
"maximized": false, "maximized": false,
"menuWidth": 300, "menuWidth": 300,