mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-07-09 10:35:21 +02:00
Compare commits
89 Commits
0.2.5_beta
...
0.2.5_beta
Author | SHA1 | Date | |
---|---|---|---|
a2d93915e8 | |||
29e9db184f | |||
2f93c7ae58 | |||
4abfe407da | |||
9b27e81091 | |||
39787743fd | |||
22e47807b8 | |||
898525a6d8 | |||
1ebcfe7d80 | |||
1dbc39b970 | |||
80f5f6c288 | |||
b18acd469f | |||
cefcd18269 | |||
4de3ac176d | |||
afd5699ff1 | |||
b79461e3ce | |||
de6ab8ecdf | |||
d0180d42a8 | |||
2e504b40f6 | |||
9b00304c29 | |||
979928ded8 | |||
7c4e442432 | |||
0dd445f101 | |||
f217804838 | |||
9a630fff06 | |||
db508214d7 | |||
8e764f48ae | |||
2583063f5f | |||
dd4ec22b39 | |||
42dbcec93f | |||
9bbf634f5d | |||
d6b09759de | |||
5bb8a943ad | |||
b370eda0d5 | |||
69bcbf6f27 | |||
04823abb83 | |||
7269a0ea12 | |||
153b58fbbd | |||
149af55e61 | |||
9cac95fd82 | |||
09498f3b18 | |||
bb919d0f32 | |||
6d0abd73a5 | |||
717f2a822b | |||
8946b4b4b6 | |||
db279d2b36 | |||
bb7965b3c4 | |||
a33fe5a4cc | |||
4a03f0870c | |||
bfe15aff19 | |||
42bc2d01f7 | |||
0cb9fc0df8 | |||
450896b122 | |||
cc0b89dbe2 | |||
c887b96a77 | |||
22541ae0f4 | |||
d83da38d79 | |||
b21f8abbd6 | |||
e9aade4d0d | |||
2bf2fff3d6 | |||
463a22fdfb | |||
3175022b31 | |||
504d910226 | |||
c2769e1a72 | |||
7577253dbf | |||
e4c5b2dbd1 | |||
fafd76ff94 | |||
e354d11820 | |||
a3374c7eca | |||
552b886cea | |||
ff9a19381b | |||
77aacc2e5d | |||
6a1fa2c13b | |||
c3bb64bf6e | |||
da68ab4ed0 | |||
1aedf92bcd | |||
abcf484506 | |||
a93681a980 | |||
a08758ea54 | |||
0a0f5b8e8c | |||
84f67a3ac1 | |||
22d18a9e58 | |||
d1a8425d43 | |||
65d94f03e4 | |||
3a49041f27 | |||
eec2f7c4a0 | |||
720df5ce89 | |||
d7cea16d4a | |||
d5c0fdd525 |
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
patreon: ryzerth
|
45
.github/workflows/cmake.yml
vendored
Normal file
45
.github/workflows/cmake.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
name: Linux Build
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||||
|
BUILD_TYPE: Release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
# The CMake configure and build commands are platform agnostic and should work equally
|
||||||
|
# well on Windows or Mac. You can convert this to a matrix build if you need
|
||||||
|
# cross-platform coverage.
|
||||||
|
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Update repositories
|
||||||
|
run: sudo apt update
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: sudo apt install libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libairspy-dev libiio-dev libad9361-dev portaudio19-dev libhackrf-dev
|
||||||
|
|
||||||
|
- name: Create Build Environment
|
||||||
|
# Some projects don't allow in-source building, so create a separate build directory
|
||||||
|
# We'll use this as our working directory for all subsequent commands
|
||||||
|
run: cmake -E make_directory ${{runner.workspace}}/build
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
# Use a bash shell so we can use the same syntax for environment variable
|
||||||
|
# access regardless of the host operating system
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{runner.workspace}}/build
|
||||||
|
# Note the current convention is to use the -S and -B options here to specify source
|
||||||
|
# and build directories, but this is only available with CMake 3.13 and higher.
|
||||||
|
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
|
||||||
|
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
working-directory: ${{runner.workspace}}/build
|
||||||
|
shell: bash
|
||||||
|
# Execute the build. You can specify a specific target with "--target <NAME>"
|
||||||
|
run: cmake --build . --config $BUILD_TYPE
|
@ -5,7 +5,9 @@ option(OPT_BUILD_RTL_TCP_SOURCE "Build RTL-TCP Source Module (no dependencies re
|
|||||||
option(OPT_BUILD_SPYSERVER_SOURCE "Build SpyServer Source Module (no dependencies required)" ON)
|
option(OPT_BUILD_SPYSERVER_SOURCE "Build SpyServer Source Module (no dependencies required)" ON)
|
||||||
option(OPT_BUILD_SOAPY_SOURCE "Build SoapySDR Source Module (Depedencies: soapysdr)" ON)
|
option(OPT_BUILD_SOAPY_SOURCE "Build SoapySDR Source Module (Depedencies: soapysdr)" ON)
|
||||||
option(OPT_BUILD_AIRSPYHF_SOURCE "Build Airspy HF+ Source Module (Depedencies: libairspyhf)" ON)
|
option(OPT_BUILD_AIRSPYHF_SOURCE "Build Airspy HF+ Source Module (Depedencies: libairspyhf)" ON)
|
||||||
|
option(OPT_BUILD_AIRSPY_SOURCE "Build Airspy Source Module (Depedencies: libairspy)" ON)
|
||||||
option(OPT_BUILD_PLUTOSDR_SOURCE "Build PlutoSDR Source Module (Depedencies: libiio, libad9361)" ON)
|
option(OPT_BUILD_PLUTOSDR_SOURCE "Build PlutoSDR Source Module (Depedencies: libiio, libad9361)" ON)
|
||||||
|
option(OPT_BUILD_HACKRF_SOURCE "Build HackRF Source Module (Depedencies: libhackrf)" ON)
|
||||||
option(OPT_BUILD_AUDIO_SINK "Build Audio Sink Module (Depedencies: portaudio)" ON)
|
option(OPT_BUILD_AUDIO_SINK "Build Audio Sink Module (Depedencies: portaudio)" ON)
|
||||||
|
|
||||||
# Core of SDR++
|
# Core of SDR++
|
||||||
@ -32,10 +34,18 @@ if (OPT_BUILD_AIRSPYHF_SOURCE)
|
|||||||
add_subdirectory("airspyhf_source")
|
add_subdirectory("airspyhf_source")
|
||||||
endif (OPT_BUILD_AIRSPYHF_SOURCE)
|
endif (OPT_BUILD_AIRSPYHF_SOURCE)
|
||||||
|
|
||||||
|
if (OPT_BUILD_AIRSPY_SOURCE)
|
||||||
|
add_subdirectory("airspy_source")
|
||||||
|
endif (OPT_BUILD_AIRSPY_SOURCE)
|
||||||
|
|
||||||
if (OPT_BUILD_PLUTOSDR_SOURCE)
|
if (OPT_BUILD_PLUTOSDR_SOURCE)
|
||||||
add_subdirectory("plutosdr_source")
|
add_subdirectory("plutosdr_source")
|
||||||
endif (OPT_BUILD_PLUTOSDR_SOURCE)
|
endif (OPT_BUILD_PLUTOSDR_SOURCE)
|
||||||
|
|
||||||
|
if (OPT_BUILD_HACKRF_SOURCE)
|
||||||
|
add_subdirectory("hackrf_source")
|
||||||
|
endif (OPT_BUILD_HACKRF_SOURCE)
|
||||||
|
|
||||||
if (OPT_BUILD_AUDIO_SINK)
|
if (OPT_BUILD_AUDIO_SINK)
|
||||||
add_subdirectory("audio_sink")
|
add_subdirectory("audio_sink")
|
||||||
endif (OPT_BUILD_AUDIO_SINK)
|
endif (OPT_BUILD_AUDIO_SINK)
|
||||||
|
31
airspy_source/CMakeLists.txt
Normal file
31
airspy_source/CMakeLists.txt
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
project(airspy_source)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
|
||||||
|
else()
|
||||||
|
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
|
||||||
|
endif (MSVC)
|
||||||
|
|
||||||
|
include_directories("src/")
|
||||||
|
|
||||||
|
file(GLOB SRC "src/*.cpp")
|
||||||
|
|
||||||
|
add_library(airspy_source SHARED ${SRC})
|
||||||
|
target_link_libraries(airspy_source PRIVATE sdrpp_core)
|
||||||
|
set_target_properties(airspy_source PROPERTIES PREFIX "")
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
# Lib path
|
||||||
|
target_link_directories(sdrpp_core PUBLIC "C:/Program Files/PothosSDR/bin/")
|
||||||
|
|
||||||
|
target_link_libraries(airspy_source PUBLIC airspy)
|
||||||
|
else (MSVC)
|
||||||
|
find_package(PkgConfig)
|
||||||
|
|
||||||
|
pkg_check_modules(LIBAIRSPYHF REQUIRED libairspy)
|
||||||
|
|
||||||
|
target_include_directories(airspy_source PUBLIC ${LIBAIRSPYHF_INCLUDE_DIRS})
|
||||||
|
target_link_directories(airspy_source PUBLIC ${LIBAIRSPYHF_LIBRARY_DIRS})
|
||||||
|
target_link_libraries(airspy_source PUBLIC ${LIBAIRSPYHF_LIBRARIES})
|
||||||
|
endif (MSVC)
|
597
airspy_source/src/main.cpp
Normal file
597
airspy_source/src/main.cpp
Normal file
@ -0,0 +1,597 @@
|
|||||||
|
#include <imgui.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <module.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <signal_path/signal_path.h>
|
||||||
|
#include <core.h>
|
||||||
|
#include <gui/style.h>
|
||||||
|
#include <config.h>
|
||||||
|
#include <options.h>
|
||||||
|
#include <libairspy/airspy.h>
|
||||||
|
|
||||||
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
|
|
||||||
|
SDRPP_MOD_INFO {
|
||||||
|
/* Name: */ "airspy_source",
|
||||||
|
/* Description: */ "Airspy source module for SDR++",
|
||||||
|
/* Author: */ "Ryzerth",
|
||||||
|
/* Version: */ 0, 1, 0,
|
||||||
|
/* Max instances */ 1
|
||||||
|
};
|
||||||
|
|
||||||
|
ConfigManager config;
|
||||||
|
|
||||||
|
class AirspySourceModule : public ModuleManager::Instance {
|
||||||
|
public:
|
||||||
|
AirspySourceModule(std::string name) {
|
||||||
|
this->name = name;
|
||||||
|
|
||||||
|
sampleRate = 10000000.0;
|
||||||
|
|
||||||
|
handler.ctx = this;
|
||||||
|
handler.selectHandler = menuSelected;
|
||||||
|
handler.deselectHandler = menuDeselected;
|
||||||
|
handler.menuHandler = menuHandler;
|
||||||
|
handler.startHandler = start;
|
||||||
|
handler.stopHandler = stop;
|
||||||
|
handler.tuneHandler = tune;
|
||||||
|
handler.stream = &stream;
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
if (sampleRateList.size() > 0) {
|
||||||
|
sampleRate = sampleRateList[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select device from config
|
||||||
|
config.aquire();
|
||||||
|
std::string devSerial = config.conf["device"];
|
||||||
|
config.release();
|
||||||
|
selectByString(devSerial);
|
||||||
|
core::setInputSampleRate(sampleRate);
|
||||||
|
|
||||||
|
sigpath::sourceManager.registerSource("Airspy", &handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
~AirspySourceModule() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable() {
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable() {
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() {
|
||||||
|
devList.clear();
|
||||||
|
devListTxt = "";
|
||||||
|
|
||||||
|
uint64_t serials[256];
|
||||||
|
int n = airspy_list_devices(serials, 256);
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
sprintf(buf, "%016" PRIX64, serials[i]);
|
||||||
|
devList.push_back(serials[i]);
|
||||||
|
devListTxt += buf;
|
||||||
|
devListTxt += '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectFirst() {
|
||||||
|
if (devList.size() != 0) {
|
||||||
|
selectBySerial(devList[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectByString(std::string serial) {
|
||||||
|
char buf[1024];
|
||||||
|
for (int i = 0; i < devList.size(); i++) {
|
||||||
|
sprintf(buf, "%016" PRIX64, devList[i]);
|
||||||
|
std::string str = buf;
|
||||||
|
if (serial == str) {
|
||||||
|
selectBySerial(devList[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectBySerial(uint64_t serial) {
|
||||||
|
selectedSerial = serial;
|
||||||
|
airspy_device* dev;
|
||||||
|
int err = airspy_open_sn(&dev, selectedSerial);
|
||||||
|
if (err != 0) {
|
||||||
|
char buf[1024];
|
||||||
|
sprintf(buf, "%016" PRIX64, selectedSerial);
|
||||||
|
spdlog::error("Could not open Airspy HF+ {0}", buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sampleRates[256];
|
||||||
|
airspy_get_samplerates(dev, sampleRates, 0);
|
||||||
|
int n = sampleRates[0];
|
||||||
|
airspy_get_samplerates(dev, sampleRates, n);
|
||||||
|
sampleRateList.clear();
|
||||||
|
sampleRateListTxt = "";
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
sampleRateList.push_back(sampleRates[i]);
|
||||||
|
sampleRateListTxt += getBandwdithScaled(sampleRates[i]);
|
||||||
|
sampleRateListTxt += '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
sprintf(buf, "%016" PRIX64, serial);
|
||||||
|
selectedSerStr = std::string(buf);
|
||||||
|
|
||||||
|
// Load config here
|
||||||
|
config.aquire();
|
||||||
|
bool created = false;
|
||||||
|
if (!config.conf["devices"].contains(selectedSerStr)) {
|
||||||
|
created = true;
|
||||||
|
config.conf["devices"][selectedSerStr]["sampleRate"] = 10000000;
|
||||||
|
config.conf["devices"][selectedSerStr]["gainMode"] = 0;
|
||||||
|
config.conf["devices"][selectedSerStr]["sensitiveGain"] = 0;
|
||||||
|
config.conf["devices"][selectedSerStr]["linearGain"] = 0;
|
||||||
|
config.conf["devices"][selectedSerStr]["lnaGain"] = 0;
|
||||||
|
config.conf["devices"][selectedSerStr]["mixerGain"] = 0;
|
||||||
|
config.conf["devices"][selectedSerStr]["vgaGain"] = 0;
|
||||||
|
config.conf["devices"][selectedSerStr]["lnaAgc"] = false;
|
||||||
|
config.conf["devices"][selectedSerStr]["mixerAgc"] = false;
|
||||||
|
config.conf["devices"][selectedSerStr]["biasT"] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load sample rate
|
||||||
|
srId = 0;
|
||||||
|
sampleRate = sampleRateList[0];
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("sampleRate")) {
|
||||||
|
int selectedSr = config.conf["devices"][selectedSerStr]["sampleRate"];
|
||||||
|
for (int i = 0; i < sampleRateList.size(); i++) {
|
||||||
|
if (sampleRateList[i] == selectedSr) {
|
||||||
|
srId = i;
|
||||||
|
sampleRate = selectedSr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load gains
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("gainMode")) {
|
||||||
|
gainMode = config.conf["devices"][selectedSerStr]["gainMode"];
|
||||||
|
}
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("sensitiveGain")) {
|
||||||
|
sensitiveGain = config.conf["devices"][selectedSerStr]["sensitiveGain"];
|
||||||
|
}
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("linearGain")) {
|
||||||
|
linearGain = config.conf["devices"][selectedSerStr]["linearGain"];
|
||||||
|
}
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("lnaGain")) {
|
||||||
|
lnaGain = config.conf["devices"][selectedSerStr]["lnaGain"];
|
||||||
|
}
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("mixerGain")) {
|
||||||
|
mixerGain = config.conf["devices"][selectedSerStr]["mixerGain"];
|
||||||
|
}
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("vgaGain")) {
|
||||||
|
vgaGain = config.conf["devices"][selectedSerStr]["vgaGain"];
|
||||||
|
}
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("lnaAgc")) {
|
||||||
|
lnaAgc = config.conf["devices"][selectedSerStr]["lnaAgc"];
|
||||||
|
}
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("mixerAgc")) {
|
||||||
|
mixerAgc = config.conf["devices"][selectedSerStr]["mixerAgc"];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Bias-T
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("biasT")) {
|
||||||
|
biasT = config.conf["devices"][selectedSerStr]["biasT"];
|
||||||
|
}
|
||||||
|
|
||||||
|
config.release(created);
|
||||||
|
|
||||||
|
airspy_close(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string getBandwdithScaled(double bw) {
|
||||||
|
char buf[1024];
|
||||||
|
if (bw >= 1000000.0) {
|
||||||
|
sprintf(buf, "%.1lfMHz", bw / 1000000.0);
|
||||||
|
}
|
||||||
|
else if (bw >= 1000.0) {
|
||||||
|
sprintf(buf, "%.1lfKHz", bw / 1000.0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sprintf(buf, "%.1lfHz", bw);
|
||||||
|
}
|
||||||
|
return std::string(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menuSelected(void* ctx) {
|
||||||
|
AirspySourceModule* _this = (AirspySourceModule*)ctx;
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
spdlog::info("AirspySourceModule '{0}': Menu Select!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menuDeselected(void* ctx) {
|
||||||
|
AirspySourceModule* _this = (AirspySourceModule*)ctx;
|
||||||
|
spdlog::info("AirspySourceModule '{0}': Menu Deselect!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start(void* ctx) {
|
||||||
|
AirspySourceModule* _this = (AirspySourceModule*)ctx;
|
||||||
|
if (_this->running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_this->selectedSerial == 0) {
|
||||||
|
spdlog::error("Tried to start AirspyHF+ source with null serial");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int err = airspy_open_sn(&_this->openDev, _this->selectedSerial);
|
||||||
|
if (err != 0) {
|
||||||
|
char buf[1024];
|
||||||
|
sprintf(buf, "%016" PRIX64, _this->selectedSerial);
|
||||||
|
spdlog::error("Could not open Airspy {0}", buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
airspy_set_samplerate(_this->openDev, _this->sampleRateList[_this->srId]);
|
||||||
|
airspy_set_freq(_this->openDev, _this->freq);
|
||||||
|
|
||||||
|
if (_this->gainMode == 0) {
|
||||||
|
airspy_set_lna_agc(_this->openDev, 0);
|
||||||
|
airspy_set_mixer_agc(_this->openDev, 0);
|
||||||
|
airspy_set_sensitivity_gain(_this->openDev, _this->sensitiveGain);
|
||||||
|
}
|
||||||
|
else if (_this->gainMode == 1) {
|
||||||
|
airspy_set_lna_agc(_this->openDev, 0);
|
||||||
|
airspy_set_mixer_agc(_this->openDev, 0);
|
||||||
|
airspy_set_linearity_gain(_this->openDev, _this->linearGain);
|
||||||
|
}
|
||||||
|
else if (_this->gainMode == 2) {
|
||||||
|
if (_this->lnaAgc) {
|
||||||
|
airspy_set_lna_agc(_this->openDev, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
airspy_set_lna_agc(_this->openDev, 0);
|
||||||
|
airspy_set_lna_gain(_this->openDev, _this->lnaGain);
|
||||||
|
}
|
||||||
|
if (_this->mixerAgc) {
|
||||||
|
airspy_set_mixer_agc(_this->openDev, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
airspy_set_mixer_agc(_this->openDev, 0);
|
||||||
|
airspy_set_mixer_gain(_this->openDev, _this->mixerGain);
|
||||||
|
}
|
||||||
|
airspy_set_vga_gain(_this->openDev, _this->vgaGain);
|
||||||
|
}
|
||||||
|
|
||||||
|
airspy_set_rf_bias(_this->openDev, _this->biasT);
|
||||||
|
|
||||||
|
airspy_start_rx(_this->openDev, callback, _this);
|
||||||
|
|
||||||
|
_this->running = true;
|
||||||
|
spdlog::info("AirspySourceModule '{0}': Start!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stop(void* ctx) {
|
||||||
|
AirspySourceModule* _this = (AirspySourceModule*)ctx;
|
||||||
|
if (!_this->running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_this->running = false;
|
||||||
|
_this->stream.stopWriter();
|
||||||
|
airspy_close(_this->openDev);
|
||||||
|
_this->stream.clearWriteStop();
|
||||||
|
spdlog::info("AirspySourceModule '{0}': Stop!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tune(double freq, void* ctx) {
|
||||||
|
AirspySourceModule* _this = (AirspySourceModule*)ctx;
|
||||||
|
if (_this->running) {
|
||||||
|
airspy_set_freq(_this->openDev, freq);
|
||||||
|
}
|
||||||
|
_this->freq = freq;
|
||||||
|
spdlog::info("AirspySourceModule '{0}': Tune: {1}!", _this->name, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menuHandler(void* ctx) {
|
||||||
|
AirspySourceModule* _this = (AirspySourceModule*)ctx;
|
||||||
|
float menuWidth = ImGui::GetContentRegionAvailWidth();
|
||||||
|
|
||||||
|
if (_this->running) { style::beginDisabled(); }
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(menuWidth);
|
||||||
|
if (ImGui::Combo(CONCAT("##_airspy_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) {
|
||||||
|
_this->selectBySerial(_this->devList[_this->devId]);
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["device"] = _this->selectedSerStr;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Combo(CONCAT("##_airspy_sr_sel_", _this->name), &_this->srId, _this->sampleRateListTxt.c_str())) {
|
||||||
|
_this->sampleRate = _this->sampleRateList[_this->srId];
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["sampleRate"] = _this->sampleRate;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX();
|
||||||
|
if (ImGui::Button(CONCAT("Refresh##_airspy_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) {
|
||||||
|
_this->refresh();
|
||||||
|
config.aquire();
|
||||||
|
std::string devSerial = config.conf["device"];
|
||||||
|
config.release();
|
||||||
|
_this->selectByString(devSerial);
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_this->running) { style::endDisabled(); }
|
||||||
|
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
ImGui::Columns(3, CONCAT("AirspyGainModeColumns##_", _this->name), false);
|
||||||
|
if (ImGui::RadioButton(CONCAT("Sensitive##_airspy_gm_", _this->name), _this->gainMode == 0)) {
|
||||||
|
_this->gainMode = 0;
|
||||||
|
if (_this->running) {
|
||||||
|
airspy_set_lna_agc(_this->openDev, 0);
|
||||||
|
airspy_set_mixer_agc(_this->openDev, 0);
|
||||||
|
airspy_set_sensitivity_gain(_this->openDev, _this->sensitiveGain);
|
||||||
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["gainMode"] = 0;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::NextColumn();
|
||||||
|
if (ImGui::RadioButton(CONCAT("Linear##_airspy_gm_", _this->name), _this->gainMode == 1)) {
|
||||||
|
_this->gainMode = 1;
|
||||||
|
if (_this->running) {
|
||||||
|
airspy_set_lna_agc(_this->openDev, 0);
|
||||||
|
airspy_set_mixer_agc(_this->openDev, 0);
|
||||||
|
airspy_set_linearity_gain(_this->openDev, _this->linearGain);
|
||||||
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["gainMode"] = 1;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::NextColumn();
|
||||||
|
if (ImGui::RadioButton(CONCAT("Free##_airspy_gm_", _this->name), _this->gainMode == 2)) {
|
||||||
|
_this->gainMode = 2;
|
||||||
|
if (_this->running) {
|
||||||
|
if (_this->lnaAgc) {
|
||||||
|
airspy_set_lna_agc(_this->openDev, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
airspy_set_lna_agc(_this->openDev, 0);
|
||||||
|
airspy_set_lna_gain(_this->openDev, _this->lnaGain);
|
||||||
|
}
|
||||||
|
if (_this->mixerAgc) {
|
||||||
|
airspy_set_mixer_agc(_this->openDev, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
airspy_set_mixer_agc(_this->openDev, 0);
|
||||||
|
airspy_set_mixer_gain(_this->openDev, _this->mixerGain);
|
||||||
|
}
|
||||||
|
airspy_set_vga_gain(_this->openDev, _this->vgaGain);
|
||||||
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["gainMode"] = 2;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::Columns(1, CONCAT("EndAirspyGainModeColumns##_", _this->name), false);
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
// Gain menus
|
||||||
|
|
||||||
|
if (_this->gainMode == 0) {
|
||||||
|
ImGui::Text("Gain");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
|
if (ImGui::SliderInt(CONCAT("##_airspy_sens_gain_", _this->name), &_this->sensitiveGain, 0, 21)) {
|
||||||
|
if (_this->running) {
|
||||||
|
airspy_set_sensitivity_gain(_this->openDev, _this->sensitiveGain);
|
||||||
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["sensitiveGain"] = _this->sensitiveGain;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_this->gainMode == 1) {
|
||||||
|
ImGui::Text("Gain");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
|
if (ImGui::SliderInt(CONCAT("##_airspy_lin_gain_", _this->name), &_this->linearGain, 0, 21)) {
|
||||||
|
if (_this->running) {
|
||||||
|
airspy_set_linearity_gain(_this->openDev, _this->linearGain);
|
||||||
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["linearGain"] = _this->linearGain;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_this->gainMode == 2) {
|
||||||
|
// Calculate position of sliders
|
||||||
|
float pos = ImGui::CalcTextSize("Mixer Gain").x + 10;
|
||||||
|
|
||||||
|
if (_this->lnaAgc) { style::beginDisabled(); }
|
||||||
|
ImGui::Text("LNA Gain");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetCursorPosX(pos);
|
||||||
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
|
if (ImGui::SliderInt(CONCAT("##_airspy_lna_gain_", _this->name), &_this->lnaGain, 0, 15)) {
|
||||||
|
if (_this->running) {
|
||||||
|
airspy_set_lna_gain(_this->openDev, _this->lnaGain);
|
||||||
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["lnaGain"] = _this->lnaGain;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_this->lnaAgc) { style::endDisabled(); }
|
||||||
|
|
||||||
|
if (_this->mixerAgc) { style::beginDisabled(); }
|
||||||
|
ImGui::Text("Mixer Gain");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetCursorPosX(pos);
|
||||||
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
|
if (ImGui::SliderInt(CONCAT("##_airspy_mix_gain_", _this->name), &_this->mixerGain, 0, 15)) {
|
||||||
|
if (_this->running) {
|
||||||
|
airspy_set_mixer_gain(_this->openDev, _this->mixerGain);
|
||||||
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["mixerGain"] = _this->mixerGain;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_this->mixerAgc) { style::endDisabled(); }
|
||||||
|
|
||||||
|
ImGui::Text("VGA Gain");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetCursorPosX(pos);
|
||||||
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
|
if (ImGui::SliderInt(CONCAT("##_airspy_vga_gain_", _this->name), &_this->vgaGain, 0, 15)) {
|
||||||
|
if (_this->running) {
|
||||||
|
airspy_set_vga_gain(_this->openDev, _this->vgaGain);
|
||||||
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["vgaGain"] = _this->vgaGain;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AGC Control
|
||||||
|
if (ImGui::Checkbox(CONCAT("LNA AGC##_airspy_", _this->name), &_this->lnaAgc)) {
|
||||||
|
if (_this->running) {
|
||||||
|
if (_this->lnaAgc) {
|
||||||
|
airspy_set_lna_agc(_this->openDev, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
airspy_set_lna_agc(_this->openDev, 0);
|
||||||
|
airspy_set_lna_gain(_this->openDev, _this->lnaGain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["lnaAgc"] = _this->lnaAgc;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::Checkbox(CONCAT("Mixer AGC##_airspy_", _this->name), &_this->mixerAgc)) {
|
||||||
|
if (_this->running) {
|
||||||
|
if (_this->mixerAgc) {
|
||||||
|
airspy_set_mixer_agc(_this->openDev, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
airspy_set_mixer_agc(_this->openDev, 0);
|
||||||
|
airspy_set_mixer_gain(_this->openDev, _this->mixerGain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["mixerAgc"] = _this->mixerAgc;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bias T
|
||||||
|
|
||||||
|
if (ImGui::Checkbox(CONCAT("Bias T##_airspy_", _this->name), &_this->biasT)) {
|
||||||
|
if (_this->running) {
|
||||||
|
airspy_set_rf_bias(_this->openDev, _this->biasT);
|
||||||
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["biasT"] = _this->biasT;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int callback(airspy_transfer_t* transfer) {
|
||||||
|
AirspySourceModule* _this = (AirspySourceModule*)transfer->ctx;
|
||||||
|
memcpy(_this->stream.writeBuf, transfer->samples, transfer->sample_count * sizeof(dsp::complex_t));
|
||||||
|
if (!_this->stream.swap(transfer->sample_count)) { return -1; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
airspy_device* openDev;
|
||||||
|
bool enabled = true;
|
||||||
|
dsp::stream<dsp::complex_t> stream;
|
||||||
|
double sampleRate;
|
||||||
|
SourceManager::SourceHandler handler;
|
||||||
|
bool running = false;
|
||||||
|
double freq;
|
||||||
|
uint64_t selectedSerial = 0;
|
||||||
|
std::string selectedSerStr = "";
|
||||||
|
int devId = 0;
|
||||||
|
int srId = 0;
|
||||||
|
|
||||||
|
bool biasT = false;
|
||||||
|
|
||||||
|
int lnaGain = 0;
|
||||||
|
int vgaGain = 0;
|
||||||
|
int mixerGain = 0;
|
||||||
|
int linearGain = 0;
|
||||||
|
int sensitiveGain = 0;
|
||||||
|
|
||||||
|
int gainMode = 0;
|
||||||
|
|
||||||
|
bool lnaAgc = false;
|
||||||
|
bool mixerAgc = false;
|
||||||
|
|
||||||
|
std::vector<uint64_t> devList;
|
||||||
|
std::string devListTxt;
|
||||||
|
std::vector<uint32_t> sampleRateList;
|
||||||
|
std::string sampleRateListTxt;
|
||||||
|
};
|
||||||
|
|
||||||
|
MOD_EXPORT void _INIT_() {
|
||||||
|
json def = json({});
|
||||||
|
def["devices"] = json({});
|
||||||
|
def["device"] = "";
|
||||||
|
config.setPath(options::opts.root + "/airspy_config.json");
|
||||||
|
config.load(def);
|
||||||
|
config.enableAutoSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
||||||
|
return new AirspySourceModule(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
|
||||||
|
delete (AirspySourceModule*)instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT void _END_() {
|
||||||
|
config.disableAutoSave();
|
||||||
|
config.save();
|
||||||
|
}
|
@ -23,9 +23,9 @@ if (MSVC)
|
|||||||
else (MSVC)
|
else (MSVC)
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
|
|
||||||
pkg_check_modules(SOAPY REQUIRED airspyhf)
|
pkg_check_modules(LIBAIRSPYHF REQUIRED libairspyhf)
|
||||||
|
|
||||||
target_include_directories(airspyhf_source PUBLIC ${AIRSPYHF_INCLUDE_DIRS})
|
target_include_directories(airspyhf_source PUBLIC ${LIBAIRSPYHF_INCLUDE_DIRS})
|
||||||
target_link_directories(airspyhf_source PUBLIC ${AIRSPYHF_LIBRARY_DIRS})
|
target_link_directories(airspyhf_source PUBLIC ${LIBAIRSPYHF_LIBRARY_DIRS})
|
||||||
target_link_libraries(airspyhf_source PUBLIC ${AIRSPYHF_LIBRARIES})
|
target_link_libraries(airspyhf_source PUBLIC ${LIBAIRSPYHF_LIBRARIES})
|
||||||
endif (MSVC)
|
endif (MSVC)
|
@ -1,11 +1,12 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <core.h>
|
#include <core.h>
|
||||||
#include <gui/style.h>
|
#include <gui/style.h>
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#include <options.h>
|
||||||
#include <libairspyhf/airspyhf.h>
|
#include <libairspyhf/airspyhf.h>
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
@ -18,7 +19,7 @@ SDRPP_MOD_INFO {
|
|||||||
/* Max instances */ 1
|
/* Max instances */ 1
|
||||||
};
|
};
|
||||||
|
|
||||||
//ConfigManager config;
|
ConfigManager config;
|
||||||
|
|
||||||
const char* AGG_MODES_STR = "Off\0Low\0High\0";
|
const char* AGG_MODES_STR = "Off\0Low\0High\0";
|
||||||
|
|
||||||
@ -40,9 +41,11 @@ public:
|
|||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
// config.aquire();
|
config.aquire();
|
||||||
// std::string serString = config.conf["device"];
|
std::string devSerial = config.conf["device"];
|
||||||
// config.release();
|
config.release();
|
||||||
|
selectByString(devSerial);
|
||||||
|
core::setInputSampleRate(sampleRate);
|
||||||
|
|
||||||
sigpath::sourceManager.registerSource("Airspy HF+", &handler);
|
sigpath::sourceManager.registerSource("Airspy HF+", &handler);
|
||||||
}
|
}
|
||||||
@ -119,25 +122,74 @@ public:
|
|||||||
airspyhf_get_samplerates(dev, sampleRates, 0);
|
airspyhf_get_samplerates(dev, sampleRates, 0);
|
||||||
int n = sampleRates[0];
|
int n = sampleRates[0];
|
||||||
airspyhf_get_samplerates(dev, sampleRates, n);
|
airspyhf_get_samplerates(dev, sampleRates, n);
|
||||||
char buf[1024];
|
|
||||||
sampleRateList.clear();
|
sampleRateList.clear();
|
||||||
sampleRateListTxt = "";
|
sampleRateListTxt = "";
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
sampleRateList.push_back(sampleRates[i]);
|
sampleRateList.push_back(sampleRates[i]);
|
||||||
sprintf(buf, "%d", sampleRates[i]);
|
sampleRateListTxt += getBandwdithScaled(sampleRates[i]);
|
||||||
sampleRateListTxt += buf;
|
|
||||||
sampleRateListTxt += '\0';
|
sampleRateListTxt += '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
blockSize = airspyhf_get_output_size(dev);
|
char buf[1024];
|
||||||
spdlog::info("AirspyHF block size {0}", blockSize);
|
sprintf(buf, "%016" PRIX64, serial);
|
||||||
|
selectedSerStr = std::string(buf);
|
||||||
|
|
||||||
|
// Load config here
|
||||||
|
config.aquire();
|
||||||
|
bool created = false;
|
||||||
|
if (!config.conf["devices"].contains(selectedSerStr)) {
|
||||||
|
created = true;
|
||||||
|
config.conf["devices"][selectedSerStr]["sampleRate"] = 768000;
|
||||||
|
config.conf["devices"][selectedSerStr]["agcMode"] = 0;
|
||||||
|
config.conf["devices"][selectedSerStr]["lna"] = false;
|
||||||
|
config.conf["devices"][selectedSerStr]["attenuation"] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load sample rate
|
||||||
srId = 0;
|
srId = 0;
|
||||||
|
sampleRate = sampleRateList[0];
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("sampleRate")) {
|
||||||
|
int selectedSr = config.conf["devices"][selectedSerStr]["sampleRate"];
|
||||||
|
for (int i = 0; i < sampleRateList.size(); i++) {
|
||||||
|
if (sampleRateList[i] == selectedSr) {
|
||||||
|
srId = i;
|
||||||
|
sampleRate = selectedSr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Gains
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("agcMode")) {
|
||||||
|
agcMode = config.conf["devices"][selectedSerStr]["agcMode"];
|
||||||
|
}
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("lna")) {
|
||||||
|
hfLNA = config.conf["devices"][selectedSerStr]["lna"];
|
||||||
|
}
|
||||||
|
if (config.conf["devices"][selectedSerStr].contains("attenuation")) {
|
||||||
|
atten = config.conf["devices"][selectedSerStr]["attenuation"];
|
||||||
|
}
|
||||||
|
|
||||||
|
config.release(created);
|
||||||
|
|
||||||
airspyhf_close(dev);
|
airspyhf_close(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::string getBandwdithScaled(double bw) {
|
||||||
|
char buf[1024];
|
||||||
|
if (bw >= 1000000.0) {
|
||||||
|
sprintf(buf, "%.1lfMHz", bw / 1000000.0);
|
||||||
|
}
|
||||||
|
else if (bw >= 1000.0) {
|
||||||
|
sprintf(buf, "%.1lfKHz", bw / 1000.0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sprintf(buf, "%.1lfHz", bw);
|
||||||
|
}
|
||||||
|
return std::string(buf);
|
||||||
|
}
|
||||||
|
|
||||||
static void menuSelected(void* ctx) {
|
static void menuSelected(void* ctx) {
|
||||||
AirspyHFSourceModule* _this = (AirspyHFSourceModule*)ctx;
|
AirspyHFSourceModule* _this = (AirspyHFSourceModule*)ctx;
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
@ -167,8 +219,6 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::warn("{0}", _this->sampleRateList[_this->srId]);
|
|
||||||
|
|
||||||
airspyhf_set_samplerate(_this->openDev, _this->sampleRateList[_this->srId]);
|
airspyhf_set_samplerate(_this->openDev, _this->sampleRateList[_this->srId]);
|
||||||
airspyhf_set_freq(_this->openDev, _this->freq);
|
airspyhf_set_freq(_this->openDev, _this->freq);
|
||||||
airspyhf_set_hf_agc(_this->openDev, (_this->agcMode != 0));
|
airspyhf_set_hf_agc(_this->openDev, (_this->agcMode != 0));
|
||||||
@ -214,18 +264,33 @@ private:
|
|||||||
ImGui::SetNextItemWidth(menuWidth);
|
ImGui::SetNextItemWidth(menuWidth);
|
||||||
if (ImGui::Combo(CONCAT("##_airspyhf_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) {
|
if (ImGui::Combo(CONCAT("##_airspyhf_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) {
|
||||||
_this->selectBySerial(_this->devList[_this->devId]);
|
_this->selectBySerial(_this->devList[_this->devId]);
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["device"] = _this->selectedSerStr;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Combo(CONCAT("##_airspyhf_sr_sel_", _this->name), &_this->srId, _this->sampleRateListTxt.c_str())) {
|
if (ImGui::Combo(CONCAT("##_airspyhf_sr_sel_", _this->name), &_this->srId, _this->sampleRateListTxt.c_str())) {
|
||||||
_this->sampleRate = _this->sampleRateList[_this->srId];
|
_this->sampleRate = _this->sampleRateList[_this->srId];
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["sampleRate"] = _this->sampleRate;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX();
|
float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX();
|
||||||
if (ImGui::Button(CONCAT("Refresh##_airspyhf_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) {
|
if (ImGui::Button(CONCAT("Refresh##_airspyhf_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) {
|
||||||
_this->refresh();
|
_this->refresh();
|
||||||
_this->selectFirst();
|
config.aquire();
|
||||||
|
std::string devSerial = config.conf["device"];
|
||||||
|
config.release();
|
||||||
|
_this->selectByString(devSerial);
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_this->running) { style::endDisabled(); }
|
if (_this->running) { style::endDisabled(); }
|
||||||
@ -240,6 +305,11 @@ private:
|
|||||||
airspyhf_set_hf_agc_threshold(_this->openDev, _this->agcMode - 1);
|
airspyhf_set_hf_agc_threshold(_this->openDev, _this->agcMode - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["agcMode"] = _this->agcMode;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Text("HF LNA");
|
ImGui::Text("HF LNA");
|
||||||
@ -247,6 +317,11 @@ private:
|
|||||||
if (ImGui::Checkbox(CONCAT("##_airspyhf_lna_", _this->name), &_this->hfLNA)) {
|
if (ImGui::Checkbox(CONCAT("##_airspyhf_lna_", _this->name), &_this->hfLNA)) {
|
||||||
if (_this->running) {
|
if (_this->running) {
|
||||||
airspyhf_set_hf_lna(_this->openDev, _this->hfLNA);
|
airspyhf_set_hf_lna(_this->openDev, _this->hfLNA);
|
||||||
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["lna"] = _this->hfLNA;
|
||||||
|
config.release(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,23 +333,24 @@ private:
|
|||||||
if (_this->running) {
|
if (_this->running) {
|
||||||
airspyhf_set_hf_att(_this->openDev, _this->atten / 6);
|
airspyhf_set_hf_att(_this->openDev, _this->atten / 6);
|
||||||
}
|
}
|
||||||
|
if (_this->selectedSerStr != "") {
|
||||||
|
config.aquire();
|
||||||
|
config.conf["devices"][_this->selectedSerStr]["attenuation"] = _this->atten;
|
||||||
|
config.release(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int callback(airspyhf_transfer_t* transfer) {
|
static int callback(airspyhf_transfer_t* transfer) {
|
||||||
AirspyHFSourceModule* _this = (AirspyHFSourceModule*)transfer->ctx;
|
AirspyHFSourceModule* _this = (AirspyHFSourceModule*)transfer->ctx;
|
||||||
if (_this->stream.aquire() < 0) {
|
memcpy(_this->stream.writeBuf, transfer->samples, transfer->sample_count * sizeof(dsp::complex_t));
|
||||||
return -1;
|
if (!_this->stream.swap(transfer->sample_count)) { return -1; }
|
||||||
}
|
|
||||||
memcpy(_this->stream.data, transfer->samples, transfer->sample_count * sizeof(dsp::complex_t));
|
|
||||||
_this->stream.write(transfer->sample_count);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
airspyhf_device_t* openDev;
|
airspyhf_device_t* openDev;
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
int blockSize = 0;
|
|
||||||
dsp::stream<dsp::complex_t> stream;
|
dsp::stream<dsp::complex_t> stream;
|
||||||
double sampleRate;
|
double sampleRate;
|
||||||
SourceManager::SourceHandler handler;
|
SourceManager::SourceHandler handler;
|
||||||
@ -286,6 +362,7 @@ private:
|
|||||||
int agcMode = AGC_MODE_OFF;
|
int agcMode = AGC_MODE_OFF;
|
||||||
bool hfLNA = false;
|
bool hfLNA = false;
|
||||||
int atten = 0;
|
int atten = 0;
|
||||||
|
std::string selectedSerStr = "";
|
||||||
|
|
||||||
std::vector<uint64_t> devList;
|
std::vector<uint64_t> devList;
|
||||||
std::string devListTxt;
|
std::string devListTxt;
|
||||||
@ -294,12 +371,12 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
MOD_EXPORT void _INIT_() {
|
||||||
// config.setPath(ROOT_DIR "/airspyhf_config.json");
|
json def = json({});
|
||||||
// json defConf;
|
def["devices"] = json({});
|
||||||
// defConf["device"] = "";
|
def["device"] = "";
|
||||||
// defConf["devices"] = json::object();
|
config.setPath(options::opts.root + "/airspyhf_config.json");
|
||||||
// config.load(defConf);
|
config.load(def);
|
||||||
// config.enableAutoSave();
|
config.enableAutoSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
||||||
@ -311,6 +388,6 @@ MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MOD_EXPORT void _END_() {
|
MOD_EXPORT void _END_() {
|
||||||
// config.disableAutoSave();
|
config.disableAutoSave();
|
||||||
// config.save();
|
config.save();
|
||||||
}
|
}
|
@ -13,4 +13,20 @@ include_directories("src/")
|
|||||||
|
|
||||||
add_library(audio_sink SHARED ${SRC})
|
add_library(audio_sink SHARED ${SRC})
|
||||||
target_link_libraries(audio_sink PRIVATE sdrpp_core)
|
target_link_libraries(audio_sink PRIVATE sdrpp_core)
|
||||||
set_target_properties(audio_sink PROPERTIES PREFIX "")
|
set_target_properties(audio_sink PROPERTIES PREFIX "")
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
find_package(portaudio CONFIG REQUIRED)
|
||||||
|
target_link_libraries(sdrpp_core PUBLIC portaudio)
|
||||||
|
else (MSVC)
|
||||||
|
find_package(PkgConfig)
|
||||||
|
|
||||||
|
pkg_check_modules(PORTAUDIO REQUIRED portaudio-2.0)
|
||||||
|
|
||||||
|
target_include_directories(sdrpp_core PUBLIC ${PORTAUDIO_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
target_link_directories(sdrpp_core PUBLIC ${PORTAUDIO_LIBRARY_DIRS})
|
||||||
|
|
||||||
|
target_link_libraries(sdrpp_core PUBLIC ${PORTAUDIO_LIBRARIES})
|
||||||
|
|
||||||
|
endif (MSVC)
|
@ -1,5 +1,5 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <signal_path/sink.h>
|
#include <signal_path/sink.h>
|
||||||
@ -36,7 +36,6 @@ public:
|
|||||||
stereoRB.init(_stream->sinkOut);
|
stereoRB.init(_stream->sinkOut);
|
||||||
|
|
||||||
// Initialize PortAudio
|
// Initialize PortAudio
|
||||||
Pa_Initialize();
|
|
||||||
devCount = Pa_GetDeviceCount();
|
devCount = Pa_GetDeviceCount();
|
||||||
devId = Pa_GetDefaultOutputDevice();
|
devId = Pa_GetDefaultOutputDevice();
|
||||||
const PaDeviceInfo *deviceInfo;
|
const PaDeviceInfo *deviceInfo;
|
||||||
@ -179,6 +178,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void doStop() {
|
void doStop() {
|
||||||
|
s2m.stop();
|
||||||
monoRB.stop();
|
monoRB.stop();
|
||||||
stereoRB.stop();
|
stereoRB.stop();
|
||||||
monoRB.data.stopReader();
|
monoRB.data.stopReader();
|
||||||
@ -238,11 +238,14 @@ public:
|
|||||||
this->name = name;
|
this->name = name;
|
||||||
provider.create = create_sink;
|
provider.create = create_sink;
|
||||||
provider.ctx = this;
|
provider.ctx = this;
|
||||||
|
|
||||||
|
Pa_Initialize();
|
||||||
|
|
||||||
sigpath::sinkManager.registerSinkProvider("Audio", provider);
|
sigpath::sinkManager.registerSinkProvider("Audio", provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
~AudioSinkModule() {
|
~AudioSinkModule() {
|
||||||
|
Pa_Terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void enable() {
|
void enable() {
|
||||||
|
@ -30,9 +30,6 @@ if (MSVC)
|
|||||||
|
|
||||||
# Volk
|
# Volk
|
||||||
target_link_libraries(sdrpp_core PUBLIC volk)
|
target_link_libraries(sdrpp_core PUBLIC volk)
|
||||||
|
|
||||||
# SoapySDR
|
|
||||||
target_link_libraries(sdrpp_core PUBLIC SoapySDR)
|
|
||||||
|
|
||||||
# Glew
|
# Glew
|
||||||
find_package(GLEW REQUIRED)
|
find_package(GLEW REQUIRED)
|
||||||
@ -46,12 +43,6 @@ if (MSVC)
|
|||||||
find_package(FFTW3f CONFIG REQUIRED)
|
find_package(FFTW3f CONFIG REQUIRED)
|
||||||
target_link_libraries(sdrpp_core PUBLIC FFTW3::fftw3f)
|
target_link_libraries(sdrpp_core PUBLIC FFTW3::fftw3f)
|
||||||
|
|
||||||
# PortAudio
|
|
||||||
find_package(portaudio CONFIG REQUIRED)
|
|
||||||
target_link_libraries(sdrpp_core PUBLIC portaudio portaudio_static)
|
|
||||||
|
|
||||||
target_link_libraries(sdrpp_core PUBLIC volk)
|
|
||||||
|
|
||||||
else()
|
else()
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
@ -60,32 +51,28 @@ else()
|
|||||||
pkg_check_modules(FFTW3 REQUIRED fftw3f)
|
pkg_check_modules(FFTW3 REQUIRED fftw3f)
|
||||||
pkg_check_modules(VOLK REQUIRED volk)
|
pkg_check_modules(VOLK REQUIRED volk)
|
||||||
pkg_check_modules(GLFW3 REQUIRED glfw3)
|
pkg_check_modules(GLFW3 REQUIRED glfw3)
|
||||||
pkg_check_modules(PORTAUDIO REQUIRED portaudio-2.0)
|
|
||||||
|
|
||||||
target_include_directories(sdrpp_core PUBLIC
|
target_include_directories(sdrpp_core PUBLIC
|
||||||
${GLEW_INCLUDE_DIRS}
|
${GLEW_INCLUDE_DIRS}
|
||||||
${FFTW3_INCLUDE_DIRS}
|
${FFTW3_INCLUDE_DIRS}
|
||||||
${GLFW3_INCLUDE_DIRS}
|
${GLFW3_INCLUDE_DIRS}
|
||||||
${VOLK_INCLUDE_DIRS}
|
${VOLK_INCLUDE_DIRS}
|
||||||
${PORTAUDIO_INCLUDE_DIRS}
|
)
|
||||||
)
|
|
||||||
|
|
||||||
target_link_directories(sdrpp_core PUBLIC
|
target_link_directories(sdrpp_core PUBLIC
|
||||||
${GLEW_LIBRARY_DIRS}
|
${GLEW_LIBRARY_DIRS}
|
||||||
${FFTW3_LIBRARY_DIRS}
|
${FFTW3_LIBRARY_DIRS}
|
||||||
${GLFW3_LIBRARY_DIRS}
|
${GLFW3_LIBRARY_DIRS}
|
||||||
${VOLK_LIBRARY_DIRS}
|
${VOLK_LIBRARY_DIRS}
|
||||||
${PORTAUDIO_LIBRARY_DIRS}
|
)
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(sdrpp_core PUBLIC
|
target_link_libraries(sdrpp_core PUBLIC
|
||||||
${OPENGL_LIBRARIES}
|
${OPENGL_LIBRARIES}
|
||||||
${GLEW_STATIC_LIBRARIES}
|
${GLEW_LIBRARIES}
|
||||||
${FFTW3_STATIC_LIBRARIES}
|
${FFTW3_LIBRARIES}
|
||||||
${GLFW3_STATIC_LIBRARIES}
|
${GLFW3_LIBRARIES}
|
||||||
${VOLK_STATIC_LIBRARIES}
|
${VOLK_LIBRARIES}
|
||||||
${PORTAUDIO_STATIC_LIBRARIES}
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
target_link_libraries(sdrpp_core PUBLIC stdc++fs)
|
target_link_libraries(sdrpp_core PUBLIC stdc++fs)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <options.h>
|
#include <options.h>
|
||||||
#include <duktape/duktape.h>
|
#include <duktape/duktape.h>
|
||||||
#include <duktape/duk_console.h>
|
#include <duktape/duk_console.h>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||||
#include <stb_image_resize.h>
|
#include <stb_image_resize.h>
|
||||||
@ -77,6 +78,20 @@ int sdrpp_main(int argc, char *argv[]) {
|
|||||||
options::loadDefaults();
|
options::loadDefaults();
|
||||||
if (!options::parse(argc, argv)) { return -1; }
|
if (!options::parse(argc, argv)) { return -1; }
|
||||||
|
|
||||||
|
// Check root directory
|
||||||
|
if (!std::filesystem::exists(options::opts.root)) {
|
||||||
|
spdlog::warn("Root directory {0} does not exist, creating it", options::opts.root);
|
||||||
|
if (!std::filesystem::create_directory(options::opts.root)) {
|
||||||
|
spdlog::error("Could not create root directory {0}", options::opts.root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::filesystem::is_directory(options::opts.root)) {
|
||||||
|
spdlog::error("{0} is not a directory", options::opts.root);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// ======== DEFAULT CONFIG ========
|
// ======== DEFAULT CONFIG ========
|
||||||
json defConfig;
|
json defConfig;
|
||||||
defConfig["bandColors"]["amateur"] = "#FF0000FF";
|
defConfig["bandColors"]["amateur"] = "#FF0000FF";
|
||||||
@ -87,6 +102,7 @@ int sdrpp_main(int argc, char *argv[]) {
|
|||||||
defConfig["bandPlan"] = "General";
|
defConfig["bandPlan"] = "General";
|
||||||
defConfig["bandPlanEnabled"] = true;
|
defConfig["bandPlanEnabled"] = true;
|
||||||
defConfig["centerTuning"] = false;
|
defConfig["centerTuning"] = false;
|
||||||
|
defConfig["colorMap"] = "Classic";
|
||||||
defConfig["fftHeight"] = 300;
|
defConfig["fftHeight"] = 300;
|
||||||
defConfig["frequency"] = 100000000.0;
|
defConfig["frequency"] = 100000000.0;
|
||||||
defConfig["max"] = 0.0;
|
defConfig["max"] = 0.0;
|
||||||
@ -103,12 +119,17 @@ int sdrpp_main(int argc, char *argv[]) {
|
|||||||
};
|
};
|
||||||
defConfig["menuWidth"] = 300;
|
defConfig["menuWidth"] = 300;
|
||||||
defConfig["min"] = -70.0;
|
defConfig["min"] = -70.0;
|
||||||
defConfig["moduleInstances"]["Audio Sink"] = "audio_sink";
|
|
||||||
defConfig["moduleInstances"]["PlutoSDR Source"] = "plutosdr_source";
|
|
||||||
defConfig["moduleInstances"]["RTL-TCP Source"] = "rtl_tcp_source";
|
|
||||||
defConfig["moduleInstances"]["Radio"] = "radio";
|
defConfig["moduleInstances"]["Radio"] = "radio";
|
||||||
defConfig["moduleInstances"]["Recorder"] = "recorder";
|
defConfig["moduleInstances"]["Recorder"] = "recorder";
|
||||||
defConfig["moduleInstances"]["SoapySDR Source"] = "soapy_source";
|
defConfig["moduleInstances"]["SoapySDR Source"] = "soapy_source";
|
||||||
|
defConfig["moduleInstances"]["PlutoSDR Source"] = "plutosdr_source";
|
||||||
|
defConfig["moduleInstances"]["RTL-TCP Source"] = "rtl_tcp_source";
|
||||||
|
defConfig["moduleInstances"]["AirspyHF+ Source"] = "airspyhf_source";
|
||||||
|
defConfig["moduleInstances"]["Airspy Source"] = "airspy_source";
|
||||||
|
defConfig["moduleInstances"]["HackRF Source"] = "hackrf_source";
|
||||||
|
defConfig["moduleInstances"]["Audio Sink"] = "audio_sink";
|
||||||
|
|
||||||
defConfig["modules"] = json::array();
|
defConfig["modules"] = json::array();
|
||||||
defConfig["offset"] = 0.0;
|
defConfig["offset"] = 0.0;
|
||||||
defConfig["showWaterfall"] = true;
|
defConfig["showWaterfall"] = true;
|
||||||
@ -116,6 +137,20 @@ int sdrpp_main(int argc, char *argv[]) {
|
|||||||
defConfig["streams"] = json::object();
|
defConfig["streams"] = json::object();
|
||||||
defConfig["windowSize"]["h"] = 720;
|
defConfig["windowSize"]["h"] = 720;
|
||||||
defConfig["windowSize"]["w"] = 1280;
|
defConfig["windowSize"]["w"] = 1280;
|
||||||
|
|
||||||
|
defConfig["bandColors"]["broadcast"] = "#0000FFFF";
|
||||||
|
defConfig["bandColors"]["amateur"] = "#FF0000FF";
|
||||||
|
defConfig["bandColors"]["aviation"] = "#00FF00FF";
|
||||||
|
defConfig["bandColors"]["marine"] = "#00FFFFFF";
|
||||||
|
defConfig["bandColors"]["military"] = "#FFFF00FF";
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
defConfig["modulesDirectory"] = "./modules";
|
||||||
|
defConfig["resourcesDirectory"] = "./res";
|
||||||
|
#else
|
||||||
|
defConfig["modulesDirectory"] = "/usr/lib/sdrpp/plugins";
|
||||||
|
defConfig["resourcesDirectory"] = "/usr/share/sdrpp";
|
||||||
|
#endif
|
||||||
|
|
||||||
// Load config
|
// Load config
|
||||||
spdlog::info("Loading config");
|
spdlog::info("Loading config");
|
||||||
@ -123,21 +158,42 @@ int sdrpp_main(int argc, char *argv[]) {
|
|||||||
core::configManager.load(defConfig);
|
core::configManager.load(defConfig);
|
||||||
core::configManager.enableAutoSave();
|
core::configManager.enableAutoSave();
|
||||||
|
|
||||||
|
// Fix config
|
||||||
|
core::configManager.aquire();
|
||||||
|
for (auto const& item : defConfig.items()) {
|
||||||
|
if (!core::configManager.conf.contains(item.key())) {
|
||||||
|
spdlog::warn("Missing key in config {0}, repairing", item.key());
|
||||||
|
core::configManager.conf[item.key()] = defConfig[item.key()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core::configManager.release(true);
|
||||||
|
|
||||||
// Setup window
|
// Setup window
|
||||||
glfwSetErrorCallback(glfw_error_callback);
|
glfwSetErrorCallback(glfw_error_callback);
|
||||||
if (!glfwInit()) {
|
if (!glfwInit()) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// GL 3.2 + GLSL 150
|
||||||
|
const char* glsl_version = "#version 150";
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
|
||||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
|
||||||
|
#else
|
||||||
|
// GL 3.0 + GLSL 120
|
||||||
|
const char* glsl_version = "#version 120";
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
core::configManager.aquire();
|
core::configManager.aquire();
|
||||||
int winWidth = core::configManager.conf["windowSize"]["w"];
|
int winWidth = core::configManager.conf["windowSize"]["w"];
|
||||||
int winHeight = core::configManager.conf["windowSize"]["h"];
|
int winHeight = core::configManager.conf["windowSize"]["h"];
|
||||||
maximized = core::configManager.conf["maximized"];
|
maximized = core::configManager.conf["maximized"];
|
||||||
|
std::string resDir = core::configManager.conf["resourcesDirectory"];
|
||||||
|
json bandColors = core::configManager.conf["bandColors"];
|
||||||
core::configManager.release();
|
core::configManager.release();
|
||||||
|
|
||||||
// Create window with graphics context
|
// Create window with graphics context
|
||||||
@ -157,7 +213,7 @@ int sdrpp_main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// Load app icon
|
// Load app icon
|
||||||
GLFWimage icons[10];
|
GLFWimage icons[10];
|
||||||
icons[0].pixels = stbi_load(((std::string)(options::opts.root + "/res/icons/sdrpp.png")).c_str(), &icons[0].width, &icons[0].height, 0, 4);
|
icons[0].pixels = stbi_load(((std::string)(resDir + "/icons/sdrpp.png")).c_str(), &icons[0].width, &icons[0].height, 0, 4);
|
||||||
icons[1].pixels = (unsigned char*)malloc(16 * 16 * 4); icons[1].width = icons[1].height = 16;
|
icons[1].pixels = (unsigned char*)malloc(16 * 16 * 4); icons[1].width = icons[1].height = 16;
|
||||||
icons[2].pixels = (unsigned char*)malloc(24 * 24 * 4); icons[2].width = icons[2].height = 24;
|
icons[2].pixels = (unsigned char*)malloc(24 * 24 * 4); icons[2].width = icons[2].height = 24;
|
||||||
icons[3].pixels = (unsigned char*)malloc(32 * 32 * 4); icons[3].width = icons[3].height = 32;
|
icons[3].pixels = (unsigned char*)malloc(32 * 32 * 4); icons[3].width = icons[3].height = 32;
|
||||||
@ -196,23 +252,23 @@ int sdrpp_main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// Setup Platform/Renderer bindings
|
// Setup Platform/Renderer bindings
|
||||||
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||||
ImGui_ImplOpenGL3_Init("#version 150");
|
ImGui_ImplOpenGL3_Init(glsl_version);
|
||||||
|
|
||||||
style::setDarkStyle();
|
if (!style::setDarkStyle(resDir)) { return -1; }
|
||||||
|
|
||||||
LoadingScreen::setWindow(window);
|
LoadingScreen::setWindow(window);
|
||||||
|
|
||||||
LoadingScreen::show("Loading icons");
|
LoadingScreen::show("Loading icons");
|
||||||
spdlog::info("Loading icons");
|
spdlog::info("Loading icons");
|
||||||
icons::load();
|
if (!icons::load(resDir)) { return -1; }
|
||||||
|
|
||||||
LoadingScreen::show("Loading band plans");
|
LoadingScreen::show("Loading band plans");
|
||||||
spdlog::info("Loading band plans");
|
spdlog::info("Loading band plans");
|
||||||
bandplan::loadFromDir(options::opts.root + "/bandplans");
|
bandplan::loadFromDir(resDir + "/bandplans");
|
||||||
|
|
||||||
LoadingScreen::show("Loading band plan colors");
|
LoadingScreen::show("Loading band plan colors");
|
||||||
spdlog::info("Loading band plans color table");
|
spdlog::info("Loading band plans color table");
|
||||||
bandplan::loadColorTable(options::opts.root + "/band_colors.json");
|
bandplan::loadColorTable(bandColors);
|
||||||
|
|
||||||
windowInit();
|
windowInit();
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
#include <scripting.h>
|
#include <scripting.h>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
|
|
||||||
namespace core {
|
namespace core {
|
||||||
SDRPP_EXPORT ConfigManager configManager;
|
SDRPP_EXPORT ConfigManager configManager;
|
||||||
|
@ -6,9 +6,12 @@ namespace sdrpp_credits {
|
|||||||
"aosync",
|
"aosync",
|
||||||
"Alexsey Shestacov",
|
"Alexsey Shestacov",
|
||||||
"Benjamin Kyd",
|
"Benjamin Kyd",
|
||||||
"Tobias Mädel",
|
"Cropinghigh",
|
||||||
|
"Howard0su",
|
||||||
|
"Martin Hauke",
|
||||||
"Raov",
|
"Raov",
|
||||||
"Howard0su"
|
"Szymon Zakrent",
|
||||||
|
"Tobias Mädel"
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* libraries[] = {
|
const char* libraries[] = {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
|
|
||||||
namespace sdrpp_credits {
|
namespace sdrpp_credits {
|
||||||
SDRPP_EXPORT const char* contributors[];
|
SDRPP_EXPORT const char* contributors[];
|
||||||
|
@ -29,14 +29,13 @@ namespace dsp {
|
|||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
out.data[i].l = _in->data[i];
|
out.writeBuf[i].l = _in->readBuf[i];
|
||||||
out.data[i].r = _in->data[i];
|
out.writeBuf[i].r = _in->readBuf[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,13 +74,12 @@ namespace dsp {
|
|||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
out.data[i] = (_in->data[i].l + _in->data[i].r) / 2.0f;
|
out.writeBuf[i] = (_in->readBuf[i].l + _in->readBuf[i].r) / 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
#define FL_M_PI 3.1415926535f
|
#define FL_M_PI 3.1415926535f
|
||||||
|
|
||||||
namespace dsp {
|
namespace dsp {
|
||||||
@ -77,10 +79,10 @@ namespace dsp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void doStop() {
|
virtual void doStop() {
|
||||||
for (auto const& in : inputs) {
|
for (auto& in : inputs) {
|
||||||
in->stopReader();
|
in->stopReader();
|
||||||
}
|
}
|
||||||
for (auto const& out : outputs) {
|
for (auto& out : outputs) {
|
||||||
out->stopWriter();
|
out->stopWriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,11 +90,11 @@ namespace dsp {
|
|||||||
if (workerThread.joinable()) {
|
if (workerThread.joinable()) {
|
||||||
workerThread.join();
|
workerThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& in : inputs) {
|
for (auto& in : inputs) {
|
||||||
in->clearReadStop();
|
in->clearReadStop();
|
||||||
}
|
}
|
||||||
for (auto const& out : outputs) {
|
for (auto& out : outputs) {
|
||||||
out->clearWriteStop();
|
out->clearWriteStop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <dsp/block.h>
|
#include <dsp/block.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#define RING_BUF_SZ 1000000
|
#define RING_BUF_SZ 1000000
|
||||||
|
|
||||||
|
@ -31,11 +31,10 @@ namespace dsp {
|
|||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
memcpy(out.writeBuf, _in->readBuf, count * sizeof(complex_t));
|
||||||
memcpy(out.data, _in->data, count * sizeof(complex_t));
|
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,11 +74,10 @@ namespace dsp {
|
|||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
volk_32fc_deinterleave_real_32f(out.writeBuf, (lv_32fc_t*)_in->readBuf, count);
|
||||||
volk_32fc_deinterleave_real_32f(out.data, (lv_32fc_t*)_in->data, count);
|
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,11 +117,10 @@ namespace dsp {
|
|||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
volk_32fc_deinterleave_imag_32f(out.writeBuf, (lv_32fc_t*)_in->readBuf, count);
|
||||||
volk_32fc_deinterleave_imag_32f(out.data, (lv_32fc_t*)_in->data, count);
|
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if(!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,4 +132,54 @@ namespace dsp {
|
|||||||
stream<complex_t>* _in;
|
stream<complex_t>* _in;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class RealToComplex : public generic_block<RealToComplex> {
|
||||||
|
public:
|
||||||
|
RealToComplex() {}
|
||||||
|
|
||||||
|
RealToComplex(stream<float>* in) { init(in); }
|
||||||
|
|
||||||
|
~RealToComplex() {
|
||||||
|
delete[] nullBuffer;
|
||||||
|
generic_block<RealToComplex>::stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(stream<float>* in) {
|
||||||
|
_in = in;
|
||||||
|
nullBuffer = new float[STREAM_BUFFER_SIZE];
|
||||||
|
memset(nullBuffer, 0, STREAM_BUFFER_SIZE * sizeof(float));
|
||||||
|
generic_block<RealToComplex>::registerInput(_in);
|
||||||
|
generic_block<RealToComplex>::registerOutput(&out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setInput(stream<float>* in) {
|
||||||
|
std::lock_guard<std::mutex> lck(generic_block<RealToComplex>::ctrlMtx);
|
||||||
|
generic_block<RealToComplex>::tempStop();
|
||||||
|
generic_block<RealToComplex>::unregisterInput(_in);
|
||||||
|
_in = in;
|
||||||
|
generic_block<RealToComplex>::registerInput(_in);
|
||||||
|
generic_block<RealToComplex>::tempStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
int run() {
|
||||||
|
count = _in->read();
|
||||||
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
|
volk_32f_x2_interleave_32fc((lv_32fc_t*)out.writeBuf, _in->readBuf, nullBuffer, count);
|
||||||
|
|
||||||
|
_in->flush();
|
||||||
|
if (!out.swap(count)) { return -1; }
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream<complex_t> out;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float avg;
|
||||||
|
int count;
|
||||||
|
float* nullBuffer;
|
||||||
|
stream<float>* _in;
|
||||||
|
|
||||||
|
};
|
||||||
}
|
}
|
@ -83,19 +83,17 @@ namespace dsp {
|
|||||||
// This is somehow faster than volk...
|
// This is somehow faster than volk...
|
||||||
|
|
||||||
float diff, currentPhase;
|
float diff, currentPhase;
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
currentPhase = fast_arctan2(_in->data[i].i, _in->data[i].q);
|
currentPhase = fast_arctan2(_in->readBuf[i].i, _in->readBuf[i].q);
|
||||||
diff = currentPhase - phase;
|
diff = currentPhase - phase;
|
||||||
if (diff > 3.1415926535f) { diff -= 2 * 3.1415926535f; }
|
if (diff > 3.1415926535f) { diff -= 2 * 3.1415926535f; }
|
||||||
else if (diff <= -3.1415926535f) { diff += 2 * 3.1415926535f; }
|
else if (diff <= -3.1415926535f) { diff += 2 * 3.1415926535f; }
|
||||||
out.data[i] = diff / phasorSpeed;
|
out.writeBuf[i] = diff / phasorSpeed;
|
||||||
phase = currentPhase;
|
phase = currentPhase;
|
||||||
}
|
}
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,19 +133,18 @@ namespace dsp {
|
|||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
volk_32fc_magnitude_32f(out.writeBuf, (lv_32fc_t*)_in->readBuf, count);
|
||||||
volk_32fc_magnitude_32f(out.data, (lv_32fc_t*)_in->data, count);
|
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
|
|
||||||
volk_32f_accumulator_s32f(&avg, out.data, count);
|
volk_32f_accumulator_s32f(&avg, out.writeBuf, count);
|
||||||
avg /= (float)count;
|
avg /= (float)count;
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
out.data[i] -= avg;
|
out.writeBuf[i] -= avg;
|
||||||
}
|
}
|
||||||
|
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,12 +256,11 @@ namespace dsp {
|
|||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
volk_32fc_s32fc_x2_rotator_32fc(buffer, (lv_32fc_t*)_in->readBuf, phaseDelta, &phase, count);
|
||||||
volk_32fc_s32fc_x2_rotator_32fc(buffer, (lv_32fc_t*)_in->data, phaseDelta, &phase, count);
|
volk_32fc_deinterleave_real_32f(out.writeBuf, buffer, count);
|
||||||
volk_32fc_deinterleave_real_32f(out.data, buffer, count);
|
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,24 +52,21 @@ namespace dsp {
|
|||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
memcpy(bufStart, _in->data, count * sizeof(T));
|
memcpy(bufStart, _in->readBuf, count * sizeof(T));
|
||||||
_in->flush();
|
_in->flush();
|
||||||
|
|
||||||
// Write to output
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
|
||||||
|
|
||||||
if constexpr (std::is_same_v<T, float>) {
|
if constexpr (std::is_same_v<T, float>) {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
volk_32f_x2_dot_prod_32f((float*)&out.data[i], (float*)&buffer[i+1], taps, tapCount);
|
volk_32f_x2_dot_prod_32f((float*)&out.writeBuf[i], (float*)&buffer[i+1], taps, tapCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if constexpr (std::is_same_v<T, complex_t>) {
|
if constexpr (std::is_same_v<T, complex_t>) {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
volk_32fc_32f_dot_prod_32fc((lv_32fc_t*)&out.data[i], (lv_32fc_t*)&buffer[i+1], taps, tapCount);
|
volk_32fc_32f_dot_prod_32fc((lv_32fc_t*)&out.writeBuf[i], (lv_32fc_t*)&buffer[i+1], taps, tapCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
|
|
||||||
memmove(buffer, &buffer[count], tapCount * sizeof(T));
|
memmove(buffer, &buffer[count], tapCount * sizeof(T));
|
||||||
|
|
||||||
@ -135,25 +132,23 @@ namespace dsp {
|
|||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
if (bypass) {
|
if (bypass) {
|
||||||
if (out.aquire() < 0) { return -1; }
|
memcpy(out.writeBuf, _in->readBuf, count * sizeof(float));
|
||||||
memcpy(out.data, _in->data, count * sizeof(float));
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isnan(lastOut)) {
|
if (isnan(lastOut)) {
|
||||||
lastOut = 0.0f;
|
lastOut = 0.0f;
|
||||||
}
|
}
|
||||||
if (out.aquire() < 0) { return -1; }
|
out.writeBuf[0] = (alpha * _in->readBuf[0]) + ((1-alpha) * lastOut);
|
||||||
out.data[0] = (alpha * _in->data[0]) + ((1-alpha) * lastOut);
|
|
||||||
for (int i = 1; i < count; i++) {
|
for (int i = 1; i < count; i++) {
|
||||||
out.data[i] = (alpha * _in->data[i]) + ((1 - alpha) * out.data[i - 1]);
|
out.writeBuf[i] = (alpha * _in->readBuf[i]) + ((1 - alpha) * out.writeBuf[i - 1]);
|
||||||
}
|
}
|
||||||
lastOut = out.data[count - 1];
|
lastOut = out.writeBuf[count - 1];
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,17 +31,16 @@ namespace dsp {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
|
||||||
if constexpr (std::is_same_v<T, complex_t> || std::is_same_v<T, stereo_t>) {
|
if constexpr (std::is_same_v<T, complex_t> || std::is_same_v<T, stereo_t>) {
|
||||||
volk_32fc_x2_add_32fc(out.data, _a->data, _b->data, a_count);
|
volk_32fc_x2_add_32fc(out.writeBuf, _a->readBuf, _b->readBuf, a_count);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
volk_32f_x2_add_32f(out.data, _a->data, _b->data, a_count);
|
volk_32f_x2_add_32f(out.writeBuf, _a->readBuf, _b->readBuf, a_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
_a->flush();
|
_a->flush();
|
||||||
_b->flush();
|
_b->flush();
|
||||||
out.write(a_count);
|
if (!out.swap(a_count)) { return -1; }
|
||||||
return a_count;
|
return a_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,17 +81,16 @@ namespace dsp {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
|
||||||
if constexpr (std::is_same_v<T, complex_t>) {
|
if constexpr (std::is_same_v<T, complex_t>) {
|
||||||
volk_32fc_x2_multiply_32fc(out.data, _a->data, _b->data, a_count);
|
volk_32fc_x2_multiply_32fc(out.writeBuf, _a->readBuf, _b->readBuf, a_count);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
volk_32f_x2_multiply_32f(out.data, _a->data, _b->data, a_count);
|
volk_32f_x2_multiply_32f(out.writeBuf, _a->readBuf, _b->readBuf, a_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
_a->flush();
|
_a->flush();
|
||||||
_b->flush();
|
_b->flush();
|
||||||
out.write(a_count);
|
if (!out.swap(a_count)) { return -1; }
|
||||||
return a_count;
|
return a_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
99
core/src/dsp/measure.h
Normal file
99
core/src/dsp/measure.h
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <dsp/block.h>
|
||||||
|
#include <fftw3.h>
|
||||||
|
#include <volk/volk.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <dsp/types.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace dsp {
|
||||||
|
class VolumeMeasure : public generic_block<VolumeMeasure> {
|
||||||
|
public:
|
||||||
|
VolumeMeasure() {}
|
||||||
|
|
||||||
|
VolumeMeasure(stream<stereo_t>* in) { init(in); }
|
||||||
|
|
||||||
|
~VolumeMeasure() {
|
||||||
|
generic_block<VolumeMeasure>::stop();
|
||||||
|
delete[] leftBuf;
|
||||||
|
delete[] rightBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(stream<stereo_t>* in) {
|
||||||
|
_in = in;
|
||||||
|
leftBuf = new float[STREAM_BUFFER_SIZE];
|
||||||
|
rightBuf = new float[STREAM_BUFFER_SIZE];
|
||||||
|
generic_block<VolumeMeasure>::registerInput(_in);
|
||||||
|
generic_block<VolumeMeasure>::registerOutput(&out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setInput(stream<stereo_t>* in) {
|
||||||
|
std::lock_guard<std::mutex> lck(generic_block<VolumeMeasure>::ctrlMtx);
|
||||||
|
generic_block<VolumeMeasure>::tempStop();
|
||||||
|
generic_block<VolumeMeasure>::unregisterInput(_in);
|
||||||
|
_in = in;
|
||||||
|
generic_block<VolumeMeasure>::registerInput(_in);
|
||||||
|
generic_block<VolumeMeasure>::tempStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
int run() {
|
||||||
|
count = _in->read();
|
||||||
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
|
memcpy(out.writeBuf, _in->readBuf, count * sizeof(stereo_t));
|
||||||
|
volk_32fc_deinterleave_32f_x2(leftBuf, rightBuf, (lv_32fc_t*)_in->readBuf, count);
|
||||||
|
|
||||||
|
_in->flush();
|
||||||
|
if (!out.swap(count)) { return -1; }
|
||||||
|
|
||||||
|
// Get peak from last value
|
||||||
|
float time = (float)count / sampleRate;
|
||||||
|
peak.l -= peakFall * time;
|
||||||
|
peak.r -= peakFall * time;
|
||||||
|
stereo_t _peak;
|
||||||
|
_peak.l = powf(10, peak.l / 10.0f);
|
||||||
|
_peak.r = powf(10, peak.r / 10.0f);
|
||||||
|
|
||||||
|
stereo_t _average;
|
||||||
|
|
||||||
|
// Calculate average
|
||||||
|
volk_32f_s32f_power_32f(leftBuf, leftBuf, 2, count);
|
||||||
|
volk_32f_s32f_power_32f(rightBuf, rightBuf, 2, count);
|
||||||
|
volk_32f_sqrt_32f(leftBuf, leftBuf, count);
|
||||||
|
volk_32f_sqrt_32f(rightBuf, rightBuf, count);
|
||||||
|
volk_32f_accumulator_s32f(&_average.l, leftBuf, count);
|
||||||
|
volk_32f_accumulator_s32f(&_average.r, rightBuf, count);
|
||||||
|
_average.l /= (float)count;
|
||||||
|
_average.r /= (float)count;
|
||||||
|
|
||||||
|
// Calculate peak
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (leftBuf[i] > _peak.l) { _peak.l = leftBuf[i]; }
|
||||||
|
if (rightBuf[i] > _peak.r) { _peak.r = rightBuf[i]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign
|
||||||
|
peak.l = 10.0f * log10f(_peak.l);
|
||||||
|
peak.r = 10.0f * log10f(_peak.r);
|
||||||
|
average.l = (average.l * (1.0f - avgFilt)) + (10.0f * log10f(_average.l) * avgFilt);
|
||||||
|
average.r = (average.r * (1.0f - avgFilt)) + (10.0f * log10f(_average.r) * avgFilt);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream<stereo_t> out;
|
||||||
|
|
||||||
|
stereo_t peak = {0, 0};
|
||||||
|
stereo_t average = {0, 0};
|
||||||
|
|
||||||
|
private:
|
||||||
|
int count;
|
||||||
|
float peakFall = 10.0f; // dB/S
|
||||||
|
float avgFilt = 0.2f; // IIR filter coef
|
||||||
|
float sampleRate = 48000;
|
||||||
|
stream<stereo_t>* _in;
|
||||||
|
|
||||||
|
float* leftBuf;
|
||||||
|
float* rightBuf;
|
||||||
|
};
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <dsp/block.h>
|
#include <dsp/block.h>
|
||||||
#include <fftw3.h>
|
|
||||||
#include <volk/volk.h>
|
#include <volk/volk.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -60,18 +59,16 @@ namespace dsp {
|
|||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
|
||||||
|
|
||||||
// TODO: Do float xlation
|
// TODO: Do float xlation
|
||||||
if constexpr (std::is_same_v<T, float>) {
|
if constexpr (std::is_same_v<T, float>) {
|
||||||
spdlog::error("XLATOR NOT IMPLEMENTED FOR FLOAT");
|
spdlog::error("XLATOR NOT IMPLEMENTED FOR FLOAT");
|
||||||
}
|
}
|
||||||
if constexpr (std::is_same_v<T, complex_t>) {
|
if constexpr (std::is_same_v<T, complex_t>) {
|
||||||
volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)out.data, (lv_32fc_t*)_in->data, phaseDelta, &phase, count);
|
volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)out.writeBuf, (lv_32fc_t*)_in->readBuf, phaseDelta, &phase, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,13 +88,15 @@ namespace dsp {
|
|||||||
public:
|
public:
|
||||||
AGC() {}
|
AGC() {}
|
||||||
|
|
||||||
AGC(stream<float>* in, float ratio) { init(in, ratio); }
|
AGC(stream<float>* in, float fallRate, float sampleRate) { init(in, fallRate, sampleRate); }
|
||||||
|
|
||||||
~AGC() { generic_block<AGC>::stop(); }
|
~AGC() { generic_block<AGC>::stop(); }
|
||||||
|
|
||||||
void init(stream<float>* in, float ratio) {
|
void init(stream<float>* in, float fallRate, float sampleRate) {
|
||||||
_in = in;
|
_in = in;
|
||||||
_ratio = ratio;
|
_sampleRate = sampleRate;
|
||||||
|
_fallRate = fallRate;
|
||||||
|
_CorrectedFallRate = _fallRate / _sampleRate;
|
||||||
generic_block<AGC>::registerInput(_in);
|
generic_block<AGC>::registerInput(_in);
|
||||||
generic_block<AGC>::registerOutput(&out);
|
generic_block<AGC>::registerOutput(&out);
|
||||||
}
|
}
|
||||||
@ -111,21 +110,32 @@ namespace dsp {
|
|||||||
generic_block<AGC>::tempStart();
|
generic_block<AGC>::tempStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setSampleRate(float sampleRate) {
|
||||||
|
std::lock_guard<std::mutex> lck(generic_block<AGC>::ctrlMtx);
|
||||||
|
_sampleRate = sampleRate;
|
||||||
|
_CorrectedFallRate = _fallRate / _sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFallRate(float fallRate) {
|
||||||
|
std::lock_guard<std::mutex> lck(generic_block<AGC>::ctrlMtx);
|
||||||
|
_fallRate = fallRate;
|
||||||
|
_CorrectedFallRate = _fallRate / _sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
int run() {
|
int run() {
|
||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
level = pow(10, ((10.0f * log10f(level)) - (_CorrectedFallRate * count)) / 10.0f);
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
level = (fabsf(_in->data[i]) * _ratio) + (level * (1.0f - _ratio));
|
if (_in->readBuf[i] > level) { level = _in->readBuf[i]; }
|
||||||
out.data[i] = _in->data[i] / level;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
volk_32f_s32f_multiply_32f(out.writeBuf, _in->readBuf, 1.0f / level, count);
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,8 +143,10 @@ namespace dsp {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
int count;
|
int count;
|
||||||
float level = 1.0f;
|
float level = 0.0f;
|
||||||
float _ratio;
|
float _fallRate;
|
||||||
|
float _CorrectedFallRate;
|
||||||
|
float _sampleRate;
|
||||||
stream<float>* _in;
|
stream<float>* _in;
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -185,27 +197,25 @@ namespace dsp {
|
|||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
|
||||||
|
|
||||||
if (_muted) {
|
if (_muted) {
|
||||||
if constexpr (std::is_same_v<T, stereo_t>) {
|
if constexpr (std::is_same_v<T, stereo_t>) {
|
||||||
memset(out.data, 0, sizeof(stereo_t) * count);
|
memset(out.writeBuf, 0, sizeof(stereo_t) * count);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
memset(out.data, 0, sizeof(float) * count);
|
memset(out.writeBuf, 0, sizeof(float) * count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if constexpr (std::is_same_v<T, stereo_t>) {
|
if constexpr (std::is_same_v<T, stereo_t>) {
|
||||||
volk_32f_s32f_multiply_32f((float*)out.data, (float*)_in->data, level, count * 2);
|
volk_32f_s32f_multiply_32f((float*)out.writeBuf, (float*)_in->readBuf, level, count * 2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
volk_32f_s32f_multiply_32f((float*)out.data, (float*)_in->data, level, count);
|
volk_32f_s32f_multiply_32f((float*)out.writeBuf, (float*)_in->readBuf, level, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,21 +270,20 @@ namespace dsp {
|
|||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
if (out.aquire() < 0) { return -1; }
|
|
||||||
float sum = 0.0f;
|
float sum = 0.0f;
|
||||||
volk_32fc_magnitude_32f(normBuffer, (lv_32fc_t*)_in->data, count);
|
volk_32fc_magnitude_32f(normBuffer, (lv_32fc_t*)_in->readBuf, count);
|
||||||
volk_32f_accumulator_s32f(&sum, normBuffer, count);
|
volk_32f_accumulator_s32f(&sum, normBuffer, count);
|
||||||
sum /= (float)count;
|
sum /= (float)count;
|
||||||
|
|
||||||
if (10.0f * log10f(sum) >= _level) {
|
if (10.0f * log10f(sum) >= _level) {
|
||||||
memcpy(out.data, _in->data, count * sizeof(complex_t));
|
memcpy(out.writeBuf, _in->readBuf, count * sizeof(complex_t));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
memset(out.data, 0, count * sizeof(complex_t));
|
memset(out.writeBuf, 0, count * sizeof(complex_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
_in->flush();
|
_in->flush();
|
||||||
out.write(count);
|
if (!out.swap(count)) { return -1; }
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ namespace dsp {
|
|||||||
generic_block<PolyphaseResampler<T>>::stop();
|
generic_block<PolyphaseResampler<T>>::stop();
|
||||||
volk_free(buffer);
|
volk_free(buffer);
|
||||||
volk_free(taps);
|
volk_free(taps);
|
||||||
|
freeTapPhases();
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(stream<T>* in, dsp::filter_window::generic_window* window, float inSampleRate, float outSampleRate) {
|
void init(stream<T>* in, dsp::filter_window::generic_window* window, float inSampleRate, float outSampleRate) {
|
||||||
@ -32,9 +33,10 @@ namespace dsp {
|
|||||||
taps = (float*)volk_malloc(tapCount * sizeof(float), volk_get_alignment());
|
taps = (float*)volk_malloc(tapCount * sizeof(float), volk_get_alignment());
|
||||||
_window->createTaps(taps, tapCount, _interp);
|
_window->createTaps(taps, tapCount, _interp);
|
||||||
|
|
||||||
|
buildTapPhases();
|
||||||
|
|
||||||
buffer = (T*)volk_malloc(STREAM_BUFFER_SIZE * sizeof(T) * 2, volk_get_alignment());
|
buffer = (T*)volk_malloc(STREAM_BUFFER_SIZE * sizeof(T) * 2, volk_get_alignment());
|
||||||
memset(buffer, 0, STREAM_BUFFER_SIZE * sizeof(T) * 2);
|
memset(buffer, 0, STREAM_BUFFER_SIZE * sizeof(T) * 2);
|
||||||
bufStart = &buffer[tapCount];
|
|
||||||
generic_block<PolyphaseResampler<T>>::registerInput(_in);
|
generic_block<PolyphaseResampler<T>>::registerInput(_in);
|
||||||
generic_block<PolyphaseResampler<T>>::registerOutput(&out);
|
generic_block<PolyphaseResampler<T>>::registerOutput(&out);
|
||||||
}
|
}
|
||||||
@ -55,6 +57,7 @@ namespace dsp {
|
|||||||
int _gcd = std::gcd((int)_inSampleRate, (int)_outSampleRate);
|
int _gcd = std::gcd((int)_inSampleRate, (int)_outSampleRate);
|
||||||
_interp = _outSampleRate / _gcd;
|
_interp = _outSampleRate / _gcd;
|
||||||
_decim = _inSampleRate / _gcd;
|
_decim = _inSampleRate / _gcd;
|
||||||
|
buildTapPhases();
|
||||||
generic_block<PolyphaseResampler<T>>::tempStart();
|
generic_block<PolyphaseResampler<T>>::tempStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +68,7 @@ namespace dsp {
|
|||||||
int _gcd = std::gcd((int)_inSampleRate, (int)_outSampleRate);
|
int _gcd = std::gcd((int)_inSampleRate, (int)_outSampleRate);
|
||||||
_interp = _outSampleRate / _gcd;
|
_interp = _outSampleRate / _gcd;
|
||||||
_decim = _inSampleRate / _gcd;
|
_decim = _inSampleRate / _gcd;
|
||||||
|
buildTapPhases();
|
||||||
generic_block<PolyphaseResampler<T>>::tempStart();
|
generic_block<PolyphaseResampler<T>>::tempStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +88,7 @@ namespace dsp {
|
|||||||
tapCount = window->getTapCount();
|
tapCount = window->getTapCount();
|
||||||
taps = (float*)volk_malloc(tapCount * sizeof(float), volk_get_alignment());
|
taps = (float*)volk_malloc(tapCount * sizeof(float), volk_get_alignment());
|
||||||
window->createTaps(taps, tapCount, _interp);
|
window->createTaps(taps, tapCount, _interp);
|
||||||
bufStart = &buffer[tapCount];
|
buildTapPhases();
|
||||||
generic_block<PolyphaseResampler<T>>::tempStart();
|
generic_block<PolyphaseResampler<T>>::tempStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,37 +104,29 @@ namespace dsp {
|
|||||||
|
|
||||||
int outCount = calcOutSize(count);
|
int outCount = calcOutSize(count);
|
||||||
|
|
||||||
memcpy(&buffer[tapCount], _in->data, count * sizeof(T));
|
memcpy(&buffer[tapsPerPhase], _in->readBuf, count * sizeof(T));
|
||||||
_in->flush();
|
_in->flush();
|
||||||
|
|
||||||
// Write to output
|
// Write to output
|
||||||
if (out.aquire() < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int outIndex = 0;
|
int outIndex = 0;
|
||||||
|
int _interp_m_1 = _interp - 1;
|
||||||
if constexpr (std::is_same_v<T, float>) {
|
if constexpr (std::is_same_v<T, float>) {
|
||||||
for (int i = 0; outIndex < outCount; i += _decim) {
|
for (int i = 0; outIndex < outCount; i += _decim) {
|
||||||
out.data[outIndex] = 0;
|
int phase = i % _interp;
|
||||||
for (int j = i % _interp; j < tapCount; j += _interp) {
|
volk_32f_x2_dot_prod_32f(&out.writeBuf[outIndex], &buffer[i / _interp], tapPhases[phase], tapsPerPhase);
|
||||||
out.data[outIndex] += buffer[((i - j) / _interp) + tapCount] * taps[j];
|
|
||||||
}
|
|
||||||
outIndex++;
|
outIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if constexpr (std::is_same_v<T, complex_t>) {
|
if constexpr (std::is_same_v<T, complex_t>) {
|
||||||
for (int i = 0; outIndex < outCount; i += _decim) {
|
for (int i = 0; outIndex < outCount; i += _decim) {
|
||||||
out.data[outIndex].i = 0;
|
int phase = i % _interp;
|
||||||
out.data[outIndex].q = 0;
|
volk_32fc_32f_dot_prod_32fc((lv_32fc_t*)&out.writeBuf[outIndex], (lv_32fc_t*)&buffer[(i / _interp)], tapPhases[phase], tapsPerPhase);
|
||||||
for (int j = i % _interp; j < tapCount; j += _interp) {
|
|
||||||
out.data[outIndex].i += buffer[((i - j) / _interp) + tapCount].i * taps[j];
|
|
||||||
out.data[outIndex].q += buffer[((i - j) / _interp) + tapCount].q * taps[j];
|
|
||||||
}
|
|
||||||
outIndex++;
|
outIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.write(outCount);
|
if (!out.swap(outCount)) { return -1; }
|
||||||
|
|
||||||
memmove(buffer, &buffer[count], tapCount * sizeof(T));
|
memmove(buffer, &buffer[count], tapsPerPhase * sizeof(T));
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@ -138,6 +134,44 @@ namespace dsp {
|
|||||||
stream<T> out;
|
stream<T> out;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void buildTapPhases(){
|
||||||
|
if(!taps){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!tapPhases.empty()){
|
||||||
|
freeTapPhases();
|
||||||
|
}
|
||||||
|
|
||||||
|
int phases = _interp;
|
||||||
|
tapsPerPhase = (tapCount+phases-1)/phases; //Integer division ceiling
|
||||||
|
|
||||||
|
bufStart = &buffer[tapsPerPhase];
|
||||||
|
|
||||||
|
for(int i = 0; i < phases; i++){
|
||||||
|
tapPhases.push_back((float*)volk_malloc(tapsPerPhase * sizeof(float), volk_get_alignment()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int currentTap = 0;
|
||||||
|
for(int tap = 0; tap < tapsPerPhase; tap++) {
|
||||||
|
for (int phase = 0; phase < phases; phase++) {
|
||||||
|
if(currentTap < tapCount) {
|
||||||
|
tapPhases[(_interp - 1) - phase][tap] = taps[currentTap++];
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
tapPhases[(_interp - 1) - phase][tap] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeTapPhases(){
|
||||||
|
for(auto & tapPhase : tapPhases){
|
||||||
|
volk_free(tapPhase);
|
||||||
|
}
|
||||||
|
tapPhases.clear();
|
||||||
|
}
|
||||||
|
|
||||||
int count;
|
int count;
|
||||||
stream<T>* _in;
|
stream<T>* _in;
|
||||||
|
|
||||||
@ -150,5 +184,84 @@ namespace dsp {
|
|||||||
float _inSampleRate, _outSampleRate;
|
float _inSampleRate, _outSampleRate;
|
||||||
float* taps;
|
float* taps;
|
||||||
|
|
||||||
|
int tapsPerPhase;
|
||||||
|
std::vector<float*> tapPhases;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class PowerDecimator : public generic_block<PowerDecimator> {
|
||||||
|
public:
|
||||||
|
PowerDecimator() {}
|
||||||
|
|
||||||
|
PowerDecimator(stream<complex_t>* in, unsigned int power) { init(in, power); }
|
||||||
|
|
||||||
|
~PowerDecimator() {
|
||||||
|
generic_block<PowerDecimator>::stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(stream<complex_t>* in, unsigned int power) {
|
||||||
|
_in = in;
|
||||||
|
_power = power;
|
||||||
|
generic_block<PowerDecimator>::registerInput(_in);
|
||||||
|
generic_block<PowerDecimator>::registerOutput(&out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setInput(stream<complex_t>* in) {
|
||||||
|
std::lock_guard<std::mutex> lck(generic_block<PowerDecimator>::ctrlMtx);
|
||||||
|
generic_block<PowerDecimator>::tempStop();
|
||||||
|
generic_block<PowerDecimator>::unregisterInput(_in);
|
||||||
|
_in = in;
|
||||||
|
generic_block<PowerDecimator>::registerInput(_in);
|
||||||
|
generic_block<PowerDecimator>::tempStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPower(unsigned int power) {
|
||||||
|
std::lock_guard<std::mutex> lck(generic_block<PowerDecimator>::ctrlMtx);
|
||||||
|
generic_block<PowerDecimator>::tempStop();
|
||||||
|
generic_block<PowerDecimator>::unregisterInput(_in);
|
||||||
|
_power = power;
|
||||||
|
generic_block<PowerDecimator>::registerInput(_in);
|
||||||
|
generic_block<PowerDecimator>::tempStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
int run() {
|
||||||
|
count = _in->read();
|
||||||
|
if (count < 0) { return -1; }
|
||||||
|
|
||||||
|
if (_power == 0) {
|
||||||
|
memcpy(out.writeBuf, _in->readBuf, count * sizeof(complex_t));
|
||||||
|
}
|
||||||
|
else if (_power == 1) {
|
||||||
|
for (int j = 0; j < count; j += 2) {
|
||||||
|
out.writeBuf[j / 2].i = (_in->readBuf[j].i + _in->readBuf[j + 1].i) * 0.5f;
|
||||||
|
out.writeBuf[j / 2].q = (_in->readBuf[j].q + _in->readBuf[j + 1].q) * 0.5f;
|
||||||
|
}
|
||||||
|
count /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
_in->flush();
|
||||||
|
|
||||||
|
if (_power > 1) {
|
||||||
|
for (int i = 1; i < _power; i++) {
|
||||||
|
for (int j = 0; j < count; j += 2) {
|
||||||
|
out.writeBuf[j / 2].i = (_in->readBuf[j].i + _in->readBuf[j + 1].i) * 0.5f;
|
||||||
|
out.writeBuf[j / 2].q = (_in->readBuf[j].q + _in->readBuf[j + 1].q) * 0.5f;
|
||||||
|
}
|
||||||
|
count /= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!out.swap(count)) { return -1; }
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream<complex_t> out;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
int count;
|
||||||
|
unsigned int _power = 0;
|
||||||
|
stream<complex_t>* _in;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -51,9 +51,8 @@ namespace dsp {
|
|||||||
int count = _in->read();
|
int count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
for (const auto& stream : out) {
|
for (const auto& stream : out) {
|
||||||
if (stream->aquire() < 0) { return -1; }
|
memcpy(stream->writeBuf, _in->readBuf, count * sizeof(T));
|
||||||
memcpy(stream->data, _in->data, count * sizeof(T));
|
if (!stream->swap(count)) { return -1; }
|
||||||
stream->write(count);
|
|
||||||
}
|
}
|
||||||
_in->flush();
|
_in->flush();
|
||||||
return count;
|
return count;
|
||||||
@ -115,7 +114,7 @@ namespace dsp {
|
|||||||
int run() {
|
int run() {
|
||||||
int count = _in->read();
|
int count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
ringBuf.write(_in->data, count);
|
ringBuf.write(_in->readBuf, count);
|
||||||
_in->flush();
|
_in->flush();
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@ -172,9 +171,8 @@ namespace dsp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ringBuf.readAndSkip(start, readCount, skip) < 0) { break; };
|
if (ringBuf.readAndSkip(start, readCount, skip) < 0) { break; };
|
||||||
if (out.aquire() < 0) { break; }
|
memcpy(out.writeBuf, buf, _keep * sizeof(complex_t));
|
||||||
memcpy(out.data, buf, _keep * sizeof(complex_t));
|
if (!out.swap(_keep)) { break; }
|
||||||
out.write(_keep);
|
|
||||||
}
|
}
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ namespace dsp {
|
|||||||
int run() {
|
int run() {
|
||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
_handler(_in->data, count, _ctx);
|
_handler(_in->readBuf, count, _ctx);
|
||||||
_in->flush();
|
_in->flush();
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ namespace dsp {
|
|||||||
int run() {
|
int run() {
|
||||||
count = _in->read();
|
count = _in->read();
|
||||||
if (count < 0) { return -1; }
|
if (count < 0) { return -1; }
|
||||||
if (data.write(_in->data, count) < 0) { return -1; }
|
if (data.write(_in->readBuf, count) < 0) { return -1; }
|
||||||
_in->flush();
|
_in->flush();
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,8 @@ namespace dsp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int run() {
|
int run() {
|
||||||
if (out.aquire() < 0) { return -1; }
|
volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)out.writeBuf, zeroPhase, phaseDelta, &phase, _blockSize);
|
||||||
volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)out.data, zeroPhase, phaseDelta, &phase, _blockSize);
|
if(!out.swap(_blockSize)) { return -1; }
|
||||||
out.write(_blockSize);
|
|
||||||
return _blockSize;
|
return _blockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,100 +9,118 @@
|
|||||||
namespace dsp {
|
namespace dsp {
|
||||||
class untyped_steam {
|
class untyped_steam {
|
||||||
public:
|
public:
|
||||||
virtual int aquire() { return -1; }
|
virtual bool swap(int size) { return false; }
|
||||||
virtual void write(int size) {}
|
|
||||||
virtual int read() { return -1; }
|
virtual int read() { return -1; }
|
||||||
virtual void flush() {}
|
virtual void flush() {}
|
||||||
virtual void stopReader() {}
|
|
||||||
virtual void clearReadStop() {}
|
|
||||||
virtual void stopWriter() {}
|
virtual void stopWriter() {}
|
||||||
virtual void clearWriteStop() {}
|
virtual void clearWriteStop() {}
|
||||||
|
virtual void stopReader() {}
|
||||||
|
virtual void clearReadStop() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class stream : public untyped_steam {
|
class stream : public untyped_steam {
|
||||||
public:
|
public:
|
||||||
stream() {
|
stream() {
|
||||||
data = (T*)volk_malloc(STREAM_BUFFER_SIZE * sizeof(T), volk_get_alignment());
|
writeBuf = (T*)volk_malloc(STREAM_BUFFER_SIZE * sizeof(T), volk_get_alignment());
|
||||||
|
readBuf = (T*)volk_malloc(STREAM_BUFFER_SIZE * sizeof(T), volk_get_alignment());
|
||||||
}
|
}
|
||||||
|
|
||||||
int aquire() {
|
~stream() {
|
||||||
waitReady();
|
volk_free(writeBuf);
|
||||||
if (writerStop) {
|
volk_free(readBuf);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(int size) {
|
bool swap(int size) {
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lck(sigMtx);
|
// Wait to either swap or stop
|
||||||
contentSize = size;
|
std::unique_lock<std::mutex> lck(swapMtx);
|
||||||
|
swapCV.wait(lck, [this]{ return (canSwap || writerStop); });
|
||||||
|
|
||||||
|
// If writer was stopped, abandon operation
|
||||||
|
if (writerStop) { return false; }
|
||||||
|
|
||||||
|
// Swap buffers
|
||||||
|
dataSize = size;
|
||||||
|
T* temp = writeBuf;
|
||||||
|
writeBuf = readBuf;
|
||||||
|
readBuf = temp;
|
||||||
|
canSwap = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify reader that some data is ready
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lck(rdyMtx);
|
||||||
dataReady = true;
|
dataReady = true;
|
||||||
}
|
}
|
||||||
cv.notify_one();
|
rdyCV.notify_all();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read() {
|
int read() {
|
||||||
waitData();
|
// Wait for data to be ready or to be stopped
|
||||||
if (readerStop) {
|
std::unique_lock<std::mutex> lck(rdyMtx);
|
||||||
return -1;
|
rdyCV.wait(lck, [this]{ return (dataReady || readerStop); });
|
||||||
}
|
|
||||||
return contentSize;
|
return (readerStop ? -1 : dataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() {
|
void flush() {
|
||||||
|
// Clear data ready
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lck(sigMtx);
|
std::lock_guard<std::mutex> lck(rdyMtx);
|
||||||
dataReady = false;
|
dataReady = false;
|
||||||
}
|
}
|
||||||
cv.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void stopReader() {
|
// Notify writer that buffers can be swapped
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lck(sigMtx);
|
std::lock_guard<std::mutex> lck(swapMtx);
|
||||||
readerStop = true;
|
canSwap = true;
|
||||||
}
|
}
|
||||||
cv.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearReadStop() {
|
swapCV.notify_all();
|
||||||
readerStop = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopWriter() {
|
void stopWriter() {
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lck(sigMtx);
|
std::lock_guard<std::mutex> lck(swapMtx);
|
||||||
writerStop = true;
|
writerStop = true;
|
||||||
}
|
}
|
||||||
cv.notify_one();
|
swapCV.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearWriteStop() {
|
void clearWriteStop() {
|
||||||
writerStop = false;
|
writerStop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
T* data;
|
void stopReader() {
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lck(rdyMtx);
|
||||||
|
readerStop = true;
|
||||||
|
}
|
||||||
|
rdyCV.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearReadStop() {
|
||||||
|
readerStop = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* writeBuf;
|
||||||
|
T* readBuf;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void waitReady() {
|
std::mutex swapMtx;
|
||||||
std::unique_lock<std::mutex> lck(sigMtx);
|
std::condition_variable swapCV;
|
||||||
cv.wait(lck, [this]{ return (!dataReady || writerStop); });
|
bool canSwap = true;
|
||||||
}
|
|
||||||
|
|
||||||
void waitData() {
|
std::mutex rdyMtx;
|
||||||
std::unique_lock<std::mutex> lck(sigMtx);
|
std::condition_variable rdyCV;
|
||||||
cv.wait(lck, [this]{ return (dataReady || readerStop); });
|
|
||||||
}
|
|
||||||
|
|
||||||
std::mutex sigMtx;
|
|
||||||
std::condition_variable cv;
|
|
||||||
bool dataReady = false;
|
bool dataReady = false;
|
||||||
|
|
||||||
bool readerStop = false;
|
bool readerStop = false;
|
||||||
bool writerStop = false;
|
bool writerStop = false;
|
||||||
|
|
||||||
int contentSize = 0;
|
int dataSize = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
49
core/src/gui/colormaps.cpp
Normal file
49
core/src/gui/colormaps.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include <gui/colormaps.h>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <json.hpp>
|
||||||
|
|
||||||
|
using nlohmann::json;
|
||||||
|
|
||||||
|
namespace colormaps {
|
||||||
|
std::map<std::string, Map> maps;
|
||||||
|
|
||||||
|
void loadMap(std::string path) {
|
||||||
|
if (!std::filesystem::is_regular_file(path)) {
|
||||||
|
spdlog::error("Could not load {0}, file doesn't exist", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream file(path.c_str());
|
||||||
|
json data;
|
||||||
|
file >> data;
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
Map map;
|
||||||
|
std::vector<std::string> mapTxt;
|
||||||
|
|
||||||
|
try {
|
||||||
|
map.name = data["name"];
|
||||||
|
map.author = data["author"];
|
||||||
|
mapTxt = data["map"].get<std::vector<std::string>>();
|
||||||
|
}
|
||||||
|
catch (const std::exception&) {
|
||||||
|
spdlog::error("Could not load {0}", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
map.entryCount = mapTxt.size();
|
||||||
|
map.map = new float[mapTxt.size() * 3];
|
||||||
|
int i = 0;
|
||||||
|
for(auto const& col : mapTxt) {
|
||||||
|
uint8_t r, g, b, a;
|
||||||
|
map.map[i * 3] = std::stoi(col.substr(1, 2), NULL, 16);
|
||||||
|
map.map[(i * 3) + 1] = std::stoi(col.substr(3, 2), NULL, 16);
|
||||||
|
map.map[(i * 3) + 2] = std::stoi(col.substr(5, 2), NULL, 16);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
maps[map.name] = map;
|
||||||
|
}
|
||||||
|
}
|
18
core/src/gui/colormaps.h
Normal file
18
core/src/gui/colormaps.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <module.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace colormaps {
|
||||||
|
struct Map {
|
||||||
|
std::string name;
|
||||||
|
std::string author;
|
||||||
|
float* map;
|
||||||
|
int entryCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
void loadMap(std::string path);
|
||||||
|
|
||||||
|
SDRPP_EXPORT std::map<std::string, Map> maps;
|
||||||
|
}
|
@ -33,19 +33,19 @@ namespace credits {
|
|||||||
|
|
||||||
ImGui::Text("Contributors");
|
ImGui::Text("Contributors");
|
||||||
for (int i = 0; i < sdrpp_credits::contributorCount; i++) {
|
for (int i = 0; i < sdrpp_credits::contributorCount; i++) {
|
||||||
ImGui::BulletText(sdrpp_credits::contributors[i]);
|
ImGui::BulletText("%s", sdrpp_credits::contributors[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
ImGui::Text("Libraries");
|
ImGui::Text("Libraries");
|
||||||
for (int i = 0; i < sdrpp_credits::libraryCount; i++) {
|
for (int i = 0; i < sdrpp_credits::libraryCount; i++) {
|
||||||
ImGui::BulletText(sdrpp_credits::libraries[i]);
|
ImGui::BulletText("%s", sdrpp_credits::libraries[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
ImGui::Text("Patrons");
|
ImGui::Text("Patrons");
|
||||||
for (int i = 0; i < sdrpp_credits::patronCount; i++) {
|
for (int i = 0; i < sdrpp_credits::patronCount; i++) {
|
||||||
ImGui::BulletText(sdrpp_credits::patrons[i]);
|
ImGui::BulletText("%s", sdrpp_credits::patrons[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Columns(1, "CreditColumnsEnd", true);
|
ImGui::Columns(1, "CreditColumnsEnd", true);
|
||||||
|
@ -44,19 +44,19 @@ namespace LoadingScreen {
|
|||||||
|
|
||||||
ImGui::Text("Contributors");
|
ImGui::Text("Contributors");
|
||||||
for (int i = 0; i < sdrpp_credits::contributorCount; i++) {
|
for (int i = 0; i < sdrpp_credits::contributorCount; i++) {
|
||||||
ImGui::BulletText(sdrpp_credits::contributors[i]);
|
ImGui::BulletText("%s", sdrpp_credits::contributors[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
ImGui::Text("Libraries");
|
ImGui::Text("Libraries");
|
||||||
for (int i = 0; i < sdrpp_credits::libraryCount; i++) {
|
for (int i = 0; i < sdrpp_credits::libraryCount; i++) {
|
||||||
ImGui::BulletText(sdrpp_credits::libraries[i]);
|
ImGui::BulletText("%s", sdrpp_credits::libraries[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
ImGui::Text("Patrons");
|
ImGui::Text("Patrons");
|
||||||
for (int i = 0; i < sdrpp_credits::patronCount; i++) {
|
for (int i = 0; i < sdrpp_credits::patronCount; i++) {
|
||||||
ImGui::BulletText(sdrpp_credits::patrons[i]);
|
ImGui::BulletText("%s", sdrpp_credits::patrons[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Columns(1, "CreditColumnsEnd", true);
|
ImGui::Columns(1, "CreditColumnsEnd", true);
|
||||||
@ -64,7 +64,7 @@ namespace LoadingScreen {
|
|||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
ImGui::Text(msg.c_str());
|
ImGui::Text("%s", msg.c_str());
|
||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
ImGui::PopStyleVar(1);
|
ImGui::PopStyleVar(1);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <gui/widgets/frequency_select.h>
|
#include <gui/widgets/frequency_select.h>
|
||||||
#include <gui/widgets/menu.h>
|
#include <gui/widgets/menu.h>
|
||||||
#include <gui/dialogs/loading_screen.h>
|
#include <gui/dialogs/loading_screen.h>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
SDRPP_EXPORT ImGui::WaterFall waterfall;
|
SDRPP_EXPORT ImGui::WaterFall waterfall;
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include <imgui/stb_image.h>
|
#include <imgui/stb_image.h>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
namespace icons {
|
namespace icons {
|
||||||
ImTextureID LOGO;
|
ImTextureID LOGO;
|
||||||
@ -31,14 +33,21 @@ namespace icons {
|
|||||||
return texId;
|
return texId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load() {
|
bool load(std::string resDir) {
|
||||||
LOGO = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/sdrpp.png");
|
if (!std::filesystem::is_directory(resDir)) {
|
||||||
PLAY = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/play.png");
|
spdlog::error("Inavlid resource directory: {0}", resDir);
|
||||||
STOP = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/stop.png");
|
return false;
|
||||||
MENU = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/menu.png");
|
}
|
||||||
MUTED = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/muted.png");
|
|
||||||
UNMUTED = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/unmuted.png");
|
LOGO = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/sdrpp.png");
|
||||||
NORMAL_TUNING = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/normal_tuning.png");
|
PLAY = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/play.png");
|
||||||
CENTER_TUNING = (ImTextureID)(uintptr_t)loadTexture(options::opts.root + "/res/icons/center_tuning.png");
|
STOP = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/stop.png");
|
||||||
|
MENU = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/menu.png");
|
||||||
|
MUTED = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/muted.png");
|
||||||
|
UNMUTED = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/unmuted.png");
|
||||||
|
NORMAL_TUNING = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/normal_tuning.png");
|
||||||
|
CENTER_TUNING = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/center_tuning.png");
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,5 +14,5 @@ namespace icons {
|
|||||||
extern ImTextureID CENTER_TUNING;
|
extern ImTextureID CENTER_TUNING;
|
||||||
|
|
||||||
GLuint loadTexture(std::string path);
|
GLuint loadTexture(std::string path);
|
||||||
void load();
|
bool load(std::string resDir);
|
||||||
}
|
}
|
@ -31,6 +31,7 @@
|
|||||||
#include <signal_path/source.h>
|
#include <signal_path/source.h>
|
||||||
#include <gui/dialogs/loading_screen.h>
|
#include <gui/dialogs/loading_screen.h>
|
||||||
#include <options.h>
|
#include <options.h>
|
||||||
|
#include <gui/colormaps.h>
|
||||||
|
|
||||||
// const int FFTSizes[] = {
|
// const int FFTSizes[] = {
|
||||||
// 65536,
|
// 65536,
|
||||||
@ -60,6 +61,7 @@ fftwf_plan p;
|
|||||||
float* tempFFT;
|
float* tempFFT;
|
||||||
float* FFTdata;
|
float* FFTdata;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
|
bool experimentalZoom = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -120,6 +122,8 @@ void windowInit() {
|
|||||||
|
|
||||||
core::configManager.aquire();
|
core::configManager.aquire();
|
||||||
gui::menu.order = core::configManager.conf["menuOrder"].get<std::vector<std::string>>();
|
gui::menu.order = core::configManager.conf["menuOrder"].get<std::vector<std::string>>();
|
||||||
|
std::string modulesDir = core::configManager.conf["modulesDirectory"];
|
||||||
|
std::string resourcesDir = core::configManager.conf["resourcesDirectory"];
|
||||||
core::configManager.release();
|
core::configManager.release();
|
||||||
|
|
||||||
gui::menu.registerEntry("Source", sourecmenu::draw, NULL);
|
gui::menu.registerEntry("Source", sourecmenu::draw, NULL);
|
||||||
@ -144,8 +148,8 @@ void windowInit() {
|
|||||||
spdlog::info("Loading modules");
|
spdlog::info("Loading modules");
|
||||||
|
|
||||||
// Load modules from /module directory
|
// Load modules from /module directory
|
||||||
if (std::filesystem::is_directory(options::opts.root + "/modules")) {
|
if (std::filesystem::is_directory(modulesDir)) {
|
||||||
for (const auto & file : std::filesystem::directory_iterator(options::opts.root + "/modules")) {
|
for (const auto & file : std::filesystem::directory_iterator(modulesDir)) {
|
||||||
std::string path = file.path().generic_string();
|
std::string path = file.path().generic_string();
|
||||||
if (file.path().extension().generic_string() != SDRPP_MOD_EXTENTSION) {
|
if (file.path().extension().generic_string() != SDRPP_MOD_EXTENTSION) {
|
||||||
continue;
|
continue;
|
||||||
@ -157,7 +161,7 @@ void windowInit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
spdlog::warn("Module directory {0} does not exist, not loading modules from directory");
|
spdlog::warn("Module directory {0} does not exist, not loading modules from directory", modulesDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read module config
|
// Read module config
|
||||||
@ -180,6 +184,27 @@ void windowInit() {
|
|||||||
core::moduleManager.createInstance(name, module);
|
core::moduleManager.createInstance(name, module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load color maps
|
||||||
|
LoadingScreen::show("Loading color maps");
|
||||||
|
spdlog::info("Loading color maps");
|
||||||
|
if (std::filesystem::is_directory(resourcesDir + "/colormaps")) {
|
||||||
|
for (const auto & file : std::filesystem::directory_iterator(resourcesDir + "/colormaps")) {
|
||||||
|
std::string path = file.path().generic_string();
|
||||||
|
LoadingScreen::show("Loading " + path);
|
||||||
|
spdlog::info("Loading {0}", path);
|
||||||
|
if (file.path().extension().generic_string() != ".json") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!file.is_regular_file()) { continue; }
|
||||||
|
colormaps::loadMap(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
spdlog::warn("Color map directory {0} does not exist, not loading modules from directory", modulesDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
gui::waterfall.updatePalletteFromArray(colormaps::maps["Turbo"].map, colormaps::maps["Turbo"].entryCount);
|
||||||
|
|
||||||
sourecmenu::init();
|
sourecmenu::init();
|
||||||
sinkmenu::init();
|
sinkmenu::init();
|
||||||
scriptingmenu::init();
|
scriptingmenu::init();
|
||||||
@ -275,7 +300,7 @@ void setVFO(double freq) {
|
|||||||
if (vfoBottom < bottom) {
|
if (vfoBottom < bottom) {
|
||||||
gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0));
|
gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0));
|
||||||
double newVFOOffset = (BW / 2.0) - (vfoBW / 2.0) - (viewBW / 10.0);
|
double newVFOOffset = (BW / 2.0) - (vfoBW / 2.0) - (viewBW / 10.0);
|
||||||
sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset);
|
sigpath::vfoManager.setOffset(gui::waterfall.selectedVFO, newVFOOffset);
|
||||||
gui::waterfall.setCenterFrequency(freq - newVFOOffset);
|
gui::waterfall.setCenterFrequency(freq - newVFOOffset);
|
||||||
sigpath::sourceManager.tune(freq - newVFOOffset);
|
sigpath::sourceManager.tune(freq - newVFOOffset);
|
||||||
return;
|
return;
|
||||||
@ -285,7 +310,7 @@ void setVFO(double freq) {
|
|||||||
if (vfoTop > top) {
|
if (vfoTop > top) {
|
||||||
gui::waterfall.setViewOffset((viewBW / 2.0) - (BW / 2.0));
|
gui::waterfall.setViewOffset((viewBW / 2.0) - (BW / 2.0));
|
||||||
double newVFOOffset = (vfoBW / 2.0) - (BW / 2.0) + (viewBW / 10.0);
|
double newVFOOffset = (vfoBW / 2.0) - (BW / 2.0) + (viewBW / 10.0);
|
||||||
sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset);
|
sigpath::vfoManager.setOffset(gui::waterfall.selectedVFO, newVFOOffset);
|
||||||
gui::waterfall.setCenterFrequency(freq - newVFOOffset);
|
gui::waterfall.setCenterFrequency(freq - newVFOOffset);
|
||||||
sigpath::sourceManager.tune(freq - newVFOOffset);
|
sigpath::sourceManager.tune(freq - newVFOOffset);
|
||||||
return;
|
return;
|
||||||
@ -438,7 +463,7 @@ void drawWindow() {
|
|||||||
|
|
||||||
gui::freqSelect.draw();
|
gui::freqSelect.draw();
|
||||||
|
|
||||||
//ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 9);
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 9);
|
||||||
if (centerTuning) {
|
if (centerTuning) {
|
||||||
@ -527,6 +552,7 @@ void drawWindow() {
|
|||||||
//sigpath::signalPath.setDCBiasCorrection(dcbias.val);
|
//sigpath::signalPath.setDCBiasCorrection(dcbias.val);
|
||||||
}
|
}
|
||||||
ImGui::Checkbox("Show demo window", &demoWindow);
|
ImGui::Checkbox("Show demo window", &demoWindow);
|
||||||
|
ImGui::Checkbox("Experimental zoom", &experimentalZoom);
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,7 +584,7 @@ void drawWindow() {
|
|||||||
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - (ImGui::CalcTextSize("Zoom").x / 2.0));
|
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - (ImGui::CalcTextSize("Zoom").x / 2.0));
|
||||||
ImGui::Text("Zoom");
|
ImGui::Text("Zoom");
|
||||||
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - 10);
|
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.0) - 10);
|
||||||
if (ImGui::VSliderFloat("##_7_", ImVec2(20.0, 150.0), &bw, gui::waterfall.getBandwidth(), 1000.0, "")) {
|
if (ImGui::VSliderFloat("##_7_", ImVec2(20.0, 150.0), &bw, gui::waterfall.getBandwidth(), 1000.0, "", (experimentalZoom ? 2.0 : 1.0))) {
|
||||||
gui::waterfall.setViewBandwidth(bw);
|
gui::waterfall.setViewBandwidth(bw);
|
||||||
if (vfo != NULL) {
|
if (vfo != NULL) {
|
||||||
gui::waterfall.setViewOffset(vfo->centerOffset); // center vfo on screen
|
gui::waterfall.setViewOffset(vfo->centerOffset); // center vfo on screen
|
||||||
@ -609,4 +635,8 @@ void drawWindow() {
|
|||||||
|
|
||||||
void setViewBandwidthSlider(float bandwidth) {
|
void setViewBandwidthSlider(float bandwidth) {
|
||||||
bw = bandwidth;
|
bw = bandwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sdrIsRunning() {
|
||||||
|
return playing;
|
||||||
}
|
}
|
@ -5,4 +5,5 @@
|
|||||||
|
|
||||||
void windowInit();
|
void windowInit();
|
||||||
void drawWindow();
|
void drawWindow();
|
||||||
void setViewBandwidthSlider(float bandwidth);
|
void setViewBandwidthSlider(float bandwidth);
|
||||||
|
bool sdrIsRunning();
|
@ -2,21 +2,58 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <core.h>
|
#include <core.h>
|
||||||
|
#include <gui/colormaps.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
|
||||||
namespace displaymenu {
|
namespace displaymenu {
|
||||||
bool showWaterfall;
|
bool showWaterfall;
|
||||||
|
int colorMapId = 0;
|
||||||
|
std::vector<std::string> colorMapNames;
|
||||||
|
std::string colorMapNamesTxt = "";
|
||||||
|
std::string colorMapAuthor = "";
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
showWaterfall = core::configManager.conf["showWaterfall"];
|
showWaterfall = core::configManager.conf["showWaterfall"];
|
||||||
showWaterfall ? gui::waterfall.showWaterfall() : gui::waterfall.hideWaterfall();
|
showWaterfall ? gui::waterfall.showWaterfall() : gui::waterfall.hideWaterfall();
|
||||||
|
std::string colormapName = core::configManager.conf["colorMap"];
|
||||||
|
if (colormaps::maps.find(colormapName) != colormaps::maps.end()) {
|
||||||
|
colormaps::Map map = colormaps::maps[colormapName];
|
||||||
|
gui::waterfall.updatePalletteFromArray(map.map, map.entryCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& [name, map] : colormaps::maps) {
|
||||||
|
colorMapNames.push_back(name);
|
||||||
|
colorMapNamesTxt += name;
|
||||||
|
colorMapNamesTxt += '\0';
|
||||||
|
if (name == colormapName) {
|
||||||
|
colorMapId = (colorMapNames.size() - 1);
|
||||||
|
colorMapAuthor = map.author;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(void* ctx) {
|
void draw(void* ctx) {
|
||||||
|
float menuWidth = ImGui::GetContentRegionAvailWidth();
|
||||||
if (ImGui::Checkbox("Show Waterfall", &showWaterfall)) {
|
if (ImGui::Checkbox("Show Waterfall", &showWaterfall)) {
|
||||||
showWaterfall ? gui::waterfall.showWaterfall() : gui::waterfall.hideWaterfall();
|
showWaterfall ? gui::waterfall.showWaterfall() : gui::waterfall.hideWaterfall();
|
||||||
core::configManager.aquire();
|
core::configManager.aquire();
|
||||||
core::configManager.conf["showWaterfall"] = showWaterfall;
|
core::configManager.conf["showWaterfall"] = showWaterfall;
|
||||||
core::configManager.release(true);
|
core::configManager.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (colorMapNames.size() > 0) {
|
||||||
|
ImGui::Text("Color Map");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
|
if (ImGui::Combo("##_sdrpp_color_map_sel", &colorMapId, colorMapNamesTxt.c_str())) {
|
||||||
|
colormaps::Map map = colormaps::maps[colorMapNames[colorMapId]];
|
||||||
|
gui::waterfall.updatePalletteFromArray(map.map, map.entryCount);
|
||||||
|
core::configManager.aquire();
|
||||||
|
core::configManager.conf["colorMap"] = colorMapNames[colorMapId];
|
||||||
|
core::configManager.release(true);
|
||||||
|
colorMapAuthor = map.author;
|
||||||
|
}
|
||||||
|
ImGui::Text("Color map Author: %s", colorMapAuthor.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,8 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <core.h>
|
#include <core.h>
|
||||||
|
#include <gui/main_window.h>
|
||||||
|
#include <gui/style.h>
|
||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
|
|
||||||
namespace sourecmenu {
|
namespace sourecmenu {
|
||||||
@ -33,6 +35,8 @@ namespace sourecmenu {
|
|||||||
items += '\0';
|
items += '\0';
|
||||||
}
|
}
|
||||||
float itemWidth = ImGui::GetContentRegionAvailWidth();
|
float itemWidth = ImGui::GetContentRegionAvailWidth();
|
||||||
|
|
||||||
|
if (sdrIsRunning()) { style::beginDisabled(); }
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(itemWidth);
|
ImGui::SetNextItemWidth(itemWidth);
|
||||||
if (ImGui::Combo("##source", &sourceId, items.c_str())) {
|
if (ImGui::Combo("##source", &sourceId, items.c_str())) {
|
||||||
@ -42,7 +46,10 @@ namespace sourecmenu {
|
|||||||
core::configManager.release(true);
|
core::configManager.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sdrIsRunning()) { style::endDisabled(); }
|
||||||
|
|
||||||
sigpath::sourceManager.showSelectedMenu();
|
sigpath::sourceManager.showSelectedMenu();
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(itemWidth - ImGui::CalcTextSize("Offset (Hz)").x - 10);
|
ImGui::SetNextItemWidth(itemWidth - ImGui::CalcTextSize("Offset (Hz)").x - 10);
|
||||||
if (ImGui::InputDouble("Offset (Hz)##freq_offset", &freqOffset, 1.0, 100.0)) {
|
if (ImGui::InputDouble("Offset (Hz)##freq_offset", &freqOffset, 1.0, 100.0)) {
|
||||||
sigpath::sourceManager.setTuningOffset(freqOffset);
|
sigpath::sourceManager.setTuningOffset(freqOffset);
|
||||||
|
@ -3,13 +3,20 @@
|
|||||||
#include <imgui_internal.h>
|
#include <imgui_internal.h>
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <options.h>
|
#include <options.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
namespace style {
|
namespace style {
|
||||||
ImFont* baseFont;
|
ImFont* baseFont;
|
||||||
ImFont* bigFont;
|
ImFont* bigFont;
|
||||||
ImFont* hugeFont;
|
ImFont* hugeFont;
|
||||||
|
|
||||||
void setDefaultStyle() {
|
bool setDefaultStyle(std::string resDir) {
|
||||||
|
if (!std::filesystem::is_directory(resDir)) {
|
||||||
|
spdlog::error("Inavlid resource directory: {0}", resDir);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::GetStyle().WindowRounding = 0.0f;
|
ImGui::GetStyle().WindowRounding = 0.0f;
|
||||||
ImGui::GetStyle().ChildRounding = 0.0f;
|
ImGui::GetStyle().ChildRounding = 0.0f;
|
||||||
ImGui::GetStyle().FrameRounding = 0.0f;
|
ImGui::GetStyle().FrameRounding = 0.0f;
|
||||||
@ -17,19 +24,26 @@ namespace style {
|
|||||||
ImGui::GetStyle().PopupRounding = 0.0f;
|
ImGui::GetStyle().PopupRounding = 0.0f;
|
||||||
ImGui::GetStyle().ScrollbarRounding = 0.0f;
|
ImGui::GetStyle().ScrollbarRounding = 0.0f;
|
||||||
|
|
||||||
baseFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(options::opts.root + "/res/fonts/Roboto-Medium.ttf")).c_str(), 16.0f);
|
baseFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(resDir + "/fonts/Roboto-Medium.ttf")).c_str(), 16.0f);
|
||||||
bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(options::opts.root + "/res/fonts/Roboto-Medium.ttf")).c_str(), 42.0f);
|
bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(resDir + "/fonts/Roboto-Medium.ttf")).c_str(), 45.0f);
|
||||||
hugeFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(options::opts.root + "/res/fonts/Roboto-Medium.ttf")).c_str(), 128.0f);
|
hugeFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(resDir + "/fonts/Roboto-Medium.ttf")).c_str(), 128.0f);
|
||||||
|
|
||||||
ImGui::StyleColorsDark();
|
ImGui::StyleColorsDark();
|
||||||
//ImGui::StyleColorsLight();
|
//ImGui::StyleColorsLight();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void testtt() {
|
void testtt() {
|
||||||
ImGui::StyleColorsLight();
|
ImGui::StyleColorsLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDarkStyle() {
|
bool setDarkStyle(std::string resDir) {
|
||||||
|
if (!std::filesystem::is_directory(resDir)) {
|
||||||
|
spdlog::error("Inavlid resource directory: {0}", resDir);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::GetStyle().WindowRounding = 0.0f;
|
ImGui::GetStyle().WindowRounding = 0.0f;
|
||||||
ImGui::GetStyle().ChildRounding = 0.0f;
|
ImGui::GetStyle().ChildRounding = 0.0f;
|
||||||
ImGui::GetStyle().FrameRounding = 0.0f;
|
ImGui::GetStyle().FrameRounding = 0.0f;
|
||||||
@ -37,9 +51,9 @@ namespace style {
|
|||||||
ImGui::GetStyle().PopupRounding = 0.0f;
|
ImGui::GetStyle().PopupRounding = 0.0f;
|
||||||
ImGui::GetStyle().ScrollbarRounding = 0.0f;
|
ImGui::GetStyle().ScrollbarRounding = 0.0f;
|
||||||
|
|
||||||
baseFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(options::opts.root + "/res/fonts/Roboto-Medium.ttf")).c_str(), 16.0f);
|
baseFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(resDir + "/fonts/Roboto-Medium.ttf")).c_str(), 16.0f);
|
||||||
bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(options::opts.root + "/res/fonts/Roboto-Medium.ttf")).c_str(), 42.0f);
|
bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(resDir + "/fonts/Roboto-Medium.ttf")).c_str(), 45.0f);
|
||||||
hugeFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(options::opts.root + "/res/fonts/Roboto-Medium.ttf")).c_str(), 128.0f);
|
hugeFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(((std::string)(resDir + "/fonts/Roboto-Medium.ttf")).c_str(), 128.0f);
|
||||||
|
|
||||||
ImGui::StyleColorsDark();
|
ImGui::StyleColorsDark();
|
||||||
|
|
||||||
@ -89,6 +103,8 @@ namespace style {
|
|||||||
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
|
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
|
||||||
colors[ImGuiCol_NavHighlight] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
|
colors[ImGuiCol_NavHighlight] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
|
||||||
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
|
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void beginDisabled() {
|
void beginDisabled() {
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace style {
|
namespace style {
|
||||||
extern ImFont* baseFont;
|
extern ImFont* baseFont;
|
||||||
extern ImFont* bigFont;
|
extern ImFont* bigFont;
|
||||||
extern ImFont* hugeFont;
|
extern ImFont* hugeFont;
|
||||||
|
|
||||||
void setDefaultStyle();
|
bool setDefaultStyle(std::string resDir);
|
||||||
void setDarkStyle();
|
bool setDarkStyle(std::string resDir);
|
||||||
void beginDisabled();
|
void beginDisabled();
|
||||||
void endDisabled();
|
void endDisabled();
|
||||||
void testtt();
|
void testtt();
|
||||||
|
@ -108,20 +108,7 @@ namespace bandplan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadColorTable(std::string path) {
|
void loadColorTable(json table) {
|
||||||
if (!std::filesystem::exists(path)) {
|
colorTable = table.get<std::map<std::string, BandPlanColor_t>>();
|
||||||
spdlog::error("Band Plan Color Table file does not exist");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!std::filesystem::is_regular_file(path)) {
|
|
||||||
spdlog::error("Band Plan Color Table file isn't a file...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::ifstream file(path.c_str());
|
|
||||||
json data;
|
|
||||||
file >> data;
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
colorTable = data.get<std::map<std::string, BandPlanColor_t>>();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -38,7 +38,7 @@ namespace bandplan {
|
|||||||
|
|
||||||
void loadBandPlan(std::string path);
|
void loadBandPlan(std::string path);
|
||||||
void loadFromDir(std::string path);
|
void loadFromDir(std::string path);
|
||||||
void loadColorTable(std::string path);
|
void loadColorTable(json table);
|
||||||
|
|
||||||
extern std::map<std::string, BandPlan_t> bandplans;
|
extern std::map<std::string, BandPlan_t> bandplans;
|
||||||
extern std::vector<std::string> bandplanNames;
|
extern std::vector<std::string> bandplanNames;
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <gui/style.h>
|
#include <gui/style.h>
|
||||||
|
|
||||||
|
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
#endif
|
||||||
|
#include <imgui/imgui_internal.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;
|
||||||
}
|
}
|
||||||
@ -18,17 +23,20 @@ void FrequencySelect::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FrequencySelect::onPosChange() {
|
void FrequencySelect::onPosChange() {
|
||||||
int digitHeight = ImGui::CalcTextSize("0").y;
|
ImVec2 digitSz = ImGui::CalcTextSize("0");
|
||||||
|
ImVec2 commaSz = ImGui::CalcTextSize(".");
|
||||||
|
int digitHeight = digitSz.y;
|
||||||
|
int digitWidth = digitSz.x;
|
||||||
int commaOffset = 0;
|
int commaOffset = 0;
|
||||||
for (int i = 0; i < 12; i++) {
|
for (int i = 0; i < 12; i++) {
|
||||||
digitTopMins[i] = ImVec2(widgetPos.x + (i * 22) + commaOffset, widgetPos.y);
|
digitTopMins[i] = ImVec2(widgetPos.x + (i * digitWidth) + commaOffset, widgetPos.y);
|
||||||
digitBottomMins[i] = ImVec2(widgetPos.x + (i * 22) + commaOffset, widgetPos.y + (digitHeight / 2));
|
digitBottomMins[i] = ImVec2(widgetPos.x + (i * digitWidth) + commaOffset, widgetPos.y + (digitHeight / 2));
|
||||||
|
|
||||||
digitTopMaxs[i] = ImVec2(widgetPos.x + (i * 22) + commaOffset + 22, widgetPos.y + (digitHeight / 2));
|
digitTopMaxs[i] = ImVec2(widgetPos.x + (i * digitWidth) + commaOffset + digitWidth, widgetPos.y + (digitHeight / 2));
|
||||||
digitBottomMaxs[i] = ImVec2(widgetPos.x + (i * 22) + commaOffset + 22, widgetPos.y + digitHeight);
|
digitBottomMaxs[i] = ImVec2(widgetPos.x + (i * digitWidth) + commaOffset + digitWidth, widgetPos.y + digitHeight);
|
||||||
|
|
||||||
if ((i + 1) % 3 == 0 && i < 11) {
|
if ((i + 1) % 3 == 0 && i < 11) {
|
||||||
commaOffset += 12;
|
commaOffset += commaSz.x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,18 +98,25 @@ void FrequencySelect::draw() {
|
|||||||
ImU32 disabledColor = ImGui::GetColorU32(ImGuiCol_Text, 0.3f);
|
ImU32 disabledColor = ImGui::GetColorU32(ImGuiCol_Text, 0.3f);
|
||||||
ImU32 textColor = ImGui::GetColorU32(ImGuiCol_Text);
|
ImU32 textColor = ImGui::GetColorU32(ImGuiCol_Text);
|
||||||
|
|
||||||
|
ImVec2 digitSz = ImGui::CalcTextSize("0");
|
||||||
|
ImVec2 commaSz = ImGui::CalcTextSize(".");
|
||||||
|
int digitHeight = digitSz.y;
|
||||||
|
int digitWidth = digitSz.x;
|
||||||
int commaOffset = 0;
|
int commaOffset = 0;
|
||||||
bool zeros = true;
|
bool zeros = true;
|
||||||
|
|
||||||
|
ImGui::ItemSize(ImRect(digitTopMins[0], ImVec2(digitBottomMaxs[11].x + 15, digitBottomMaxs[11].y)));
|
||||||
|
|
||||||
for (int i = 0; i < 12; i++) {
|
for (int i = 0; i < 12; i++) {
|
||||||
if (digits[i] != 0) {
|
if (digits[i] != 0) {
|
||||||
zeros = false;
|
zeros = false;
|
||||||
}
|
}
|
||||||
sprintf(buf, "%d", digits[i]);
|
sprintf(buf, "%d", digits[i]);
|
||||||
window->DrawList->AddText(ImVec2(widgetPos.x + (i * 22) + commaOffset, widgetPos.y),
|
window->DrawList->AddText(ImVec2(widgetPos.x + (i * digitWidth) + commaOffset, widgetPos.y),
|
||||||
zeros ? disabledColor : textColor, buf);
|
zeros ? disabledColor : textColor, buf);
|
||||||
if ((i + 1) % 3 == 0 && i < 11) {
|
if ((i + 1) % 3 == 0 && i < 11) {
|
||||||
commaOffset += 12;
|
commaOffset += commaSz.x;
|
||||||
window->DrawList->AddText(ImVec2(widgetPos.x + (i * 22) + commaOffset + 10, widgetPos.y),
|
window->DrawList->AddText(ImVec2(widgetPos.x + (i * digitWidth) + commaOffset + 11, widgetPos.y),
|
||||||
zeros ? disabledColor : textColor, ".");
|
zeros ? disabledColor : textColor, ".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
|
|
||||||
class Menu {
|
class Menu {
|
||||||
public:
|
public:
|
||||||
|
23
core/src/gui/widgets/stepped_slider.cpp
Normal file
23
core/src/gui/widgets/stepped_slider.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include <gui/widgets/stepped_slider.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <imgui_internal.h>
|
||||||
|
|
||||||
|
namespace ImGui {
|
||||||
|
bool SliderFloatWithSteps(const char* label, float* v, float v_min, float v_max, float v_step, const char* display_format) {
|
||||||
|
if (!display_format) {
|
||||||
|
display_format = "%.3f";
|
||||||
|
}
|
||||||
|
|
||||||
|
char text_buf[64] = {};
|
||||||
|
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), display_format, *v);
|
||||||
|
|
||||||
|
// Map from [v_min,v_max] to [0,N]
|
||||||
|
const int countValues = int((v_max-v_min)/v_step);
|
||||||
|
int v_i = int((*v - v_min)/v_step);
|
||||||
|
const bool value_changed = ImGui::SliderInt(label, &v_i, 0, countValues, text_buf);
|
||||||
|
|
||||||
|
// Remap from [0,N] to [v_min,v_max]
|
||||||
|
*v = v_min + float(v_i) * v_step;
|
||||||
|
return value_changed;
|
||||||
|
}
|
||||||
|
}
|
5
core/src/gui/widgets/stepped_slider.h
Normal file
5
core/src/gui/widgets/stepped_slider.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ImGui {
|
||||||
|
bool SliderFloatWithSteps(const char* label, float* v, float v_min, float v_max, float v_step, const char* display_format = "%.3f");
|
||||||
|
}
|
53
core/src/gui/widgets/volume_meter.cpp
Normal file
53
core/src/gui/widgets/volume_meter.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include <gui/widgets/volume_meter.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
#endif
|
||||||
|
#include <imgui/imgui_internal.h>
|
||||||
|
|
||||||
|
namespace ImGui {
|
||||||
|
void VolumeMeter(float avg, float peak, float val_min, float val_max, const ImVec2& size_arg) {
|
||||||
|
ImGuiWindow* window = GetCurrentWindow();
|
||||||
|
ImGuiStyle& style = GImGui->Style;
|
||||||
|
|
||||||
|
avg = std::clamp<float>(avg, val_min, val_max);
|
||||||
|
peak = std::clamp<float>(peak, val_min, val_max);
|
||||||
|
|
||||||
|
float pad = style.FramePadding.y;
|
||||||
|
|
||||||
|
ImVec2 min = window->DC.CursorPos;
|
||||||
|
ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (GImGui->FontSize / 2) + style.FramePadding.y);
|
||||||
|
ImRect bb(min, min + size);
|
||||||
|
|
||||||
|
float lineHeight = size.y;
|
||||||
|
|
||||||
|
ItemSize(size, style.FramePadding.y);
|
||||||
|
if (!ItemAdd(bb, 0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float zeroDb = roundf(((-val_min) / (val_max - val_min)) * size.x);
|
||||||
|
|
||||||
|
window->DrawList->AddRectFilled(min, min + ImVec2(zeroDb, lineHeight), IM_COL32( 0, 255, 0, 127 ));
|
||||||
|
window->DrawList->AddRectFilled(min + ImVec2(zeroDb, 0), min + ImVec2(size.x, lineHeight), IM_COL32( 255, 0, 0, 127 ));
|
||||||
|
|
||||||
|
float end = roundf(((avg - val_min) / (val_max - val_min)) * size.x);
|
||||||
|
float endP = roundf(((peak - val_min) / (val_max - val_min)) * size.x);
|
||||||
|
|
||||||
|
if (avg <= 0) {
|
||||||
|
window->DrawList->AddRectFilled(min, min + ImVec2(end, lineHeight), IM_COL32( 0, 255, 0, 255 ));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window->DrawList->AddRectFilled(min, min + ImVec2(zeroDb, lineHeight), IM_COL32( 0, 255, 0, 255 ));
|
||||||
|
window->DrawList->AddRectFilled(min + ImVec2(zeroDb, 0), min + ImVec2(end, lineHeight), IM_COL32( 255, 0, 0, 255 ));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peak <= 0) {
|
||||||
|
window->DrawList->AddLine(min + ImVec2(endP, -1), min + ImVec2(endP, lineHeight - 1), IM_COL32( 127, 255, 127, 255 ));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window->DrawList->AddLine(min + ImVec2(endP, -1), min + ImVec2(endP, lineHeight - 1), IM_COL32( 255, 127, 127, 255 ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
core/src/gui/widgets/volume_meter.h
Normal file
6
core/src/gui/widgets/volume_meter.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <imgui/imgui.h>
|
||||||
|
|
||||||
|
namespace ImGui {
|
||||||
|
void VolumeMeter(float avg, float peak, float val_min, float val_max, const ImVec2& size_arg = ImVec2(0, 0));
|
||||||
|
}
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
float COLOR_MAP[][3] = {
|
float DEFAULT_COLOR_MAP[][3] = {
|
||||||
{0x00, 0x00, 0x20},
|
{0x00, 0x00, 0x20},
|
||||||
{0x00, 0x00, 0x30},
|
{0x00, 0x00, 0x30},
|
||||||
{0x00, 0x00, 0x50},
|
{0x00, 0x00, 0x50},
|
||||||
@ -106,7 +106,7 @@ namespace ImGui {
|
|||||||
viewBandwidth = 1.0;
|
viewBandwidth = 1.0;
|
||||||
wholeBandwidth = 1.0;
|
wholeBandwidth = 1.0;
|
||||||
|
|
||||||
updatePallette(COLOR_MAP, 13);
|
updatePallette(DEFAULT_COLOR_MAP, 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::init() {
|
void WaterFall::init() {
|
||||||
@ -347,6 +347,7 @@ namespace ImGui {
|
|||||||
cPos = widgetPos.x + 50 + ((center - lowerFreq) * horizScale);
|
cPos = widgetPos.x + 50 + ((center - lowerFreq) * horizScale);
|
||||||
width = bPos - aPos;
|
width = bPos - aPos;
|
||||||
txtSz = ImGui::CalcTextSize(bandplan->bands[i].name.c_str());
|
txtSz = ImGui::CalcTextSize(bandplan->bands[i].name.c_str());
|
||||||
|
float height = txtSz.y * 2.5f;
|
||||||
if (bandplan::colorTable.find(bandplan->bands[i].type.c_str()) != bandplan::colorTable.end()) {
|
if (bandplan::colorTable.find(bandplan->bands[i].type.c_str()) != bandplan::colorTable.end()) {
|
||||||
color = bandplan::colorTable[bandplan->bands[i].type].colorValue;
|
color = bandplan::colorTable[bandplan->bands[i].type].colorValue;
|
||||||
colorTrans = bandplan::colorTable[bandplan->bands[i].type].transColorValue;
|
colorTrans = bandplan::colorTable[bandplan->bands[i].type].transColorValue;
|
||||||
@ -362,19 +363,19 @@ namespace ImGui {
|
|||||||
bPos = widgetPos.x + 51;
|
bPos = widgetPos.x + 51;
|
||||||
}
|
}
|
||||||
if (width >= 1.0) {
|
if (width >= 1.0) {
|
||||||
window->DrawList->AddRectFilled(ImVec2(roundf(aPos), widgetPos.y + fftHeight - 25),
|
window->DrawList->AddRectFilled(ImVec2(roundf(aPos), widgetPos.y + fftHeight + 10 - height),
|
||||||
ImVec2(roundf(bPos), widgetPos.y + fftHeight + 10), colorTrans);
|
ImVec2(roundf(bPos), widgetPos.y + fftHeight + 10), colorTrans);
|
||||||
if (startVis) {
|
if (startVis) {
|
||||||
window->DrawList->AddLine(ImVec2(roundf(aPos), widgetPos.y + fftHeight - 26),
|
window->DrawList->AddLine(ImVec2(roundf(aPos), widgetPos.y + fftHeight + 10 - height - 1),
|
||||||
ImVec2(roundf(aPos), widgetPos.y + fftHeight + 9), color);
|
ImVec2(roundf(aPos), widgetPos.y + fftHeight + 9), color);
|
||||||
}
|
}
|
||||||
if (endVis) {
|
if (endVis) {
|
||||||
window->DrawList->AddLine(ImVec2(roundf(bPos), widgetPos.y + fftHeight - 26),
|
window->DrawList->AddLine(ImVec2(roundf(bPos), widgetPos.y + fftHeight + 10 - height - 1),
|
||||||
ImVec2(roundf(bPos), widgetPos.y + fftHeight + 9), color);
|
ImVec2(roundf(bPos), widgetPos.y + fftHeight + 9), color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (txtSz.x <= width) {
|
if (txtSz.x <= width) {
|
||||||
window->DrawList->AddText(ImVec2(cPos - (txtSz.x / 2.0), widgetPos.y + fftHeight - 17),
|
window->DrawList->AddText(ImVec2(cPos - (txtSz.x / 2.0), widgetPos.y + fftHeight + 10 - (height / 2.0f) - (txtSz.y / 2.0f)),
|
||||||
IM_COL32(255, 255, 255, 255), bandplan->bands[i].name.c_str());
|
IM_COL32(255, 255, 255, 255), bandplan->bands[i].name.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -537,11 +538,14 @@ namespace ImGui {
|
|||||||
float* WaterFall::getFFTBuffer() {
|
float* WaterFall::getFFTBuffer() {
|
||||||
if (rawFFTs == NULL) { return NULL; }
|
if (rawFFTs == NULL) { return NULL; }
|
||||||
buf_mtx.lock();
|
buf_mtx.lock();
|
||||||
currentFFTLine--;
|
if (waterfallVisible) {
|
||||||
fftLines++;
|
currentFFTLine--;
|
||||||
currentFFTLine = ((currentFFTLine + waterfallHeight) % waterfallHeight);
|
fftLines++;
|
||||||
fftLines = std::min<float>(fftLines, waterfallHeight);
|
currentFFTLine = ((currentFFTLine + waterfallHeight) % waterfallHeight);
|
||||||
return &rawFFTs[currentFFTLine * rawFFTSize];
|
fftLines = std::min<float>(fftLines, waterfallHeight);
|
||||||
|
return &rawFFTs[currentFFTLine * rawFFTSize];
|
||||||
|
}
|
||||||
|
return rawFFTs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::pushFFT() {
|
void WaterFall::pushFFT() {
|
||||||
@ -550,9 +554,10 @@ namespace ImGui {
|
|||||||
int drawDataSize = (viewBandwidth / wholeBandwidth) * rawFFTSize;
|
int drawDataSize = (viewBandwidth / wholeBandwidth) * rawFFTSize;
|
||||||
int drawDataStart = (((double)rawFFTSize / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2);
|
int drawDataStart = (((double)rawFFTSize / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2);
|
||||||
|
|
||||||
doZoom(drawDataStart, drawDataSize, dataWidth, &rawFFTs[currentFFTLine * rawFFTSize], latestFFT);
|
|
||||||
|
|
||||||
if (waterfallVisible) {
|
if (waterfallVisible) {
|
||||||
|
doZoom(drawDataStart, drawDataSize, dataWidth, &rawFFTs[currentFFTLine * rawFFTSize], latestFFT);
|
||||||
memmove(&waterfallFb[dataWidth], waterfallFb, dataWidth * (waterfallHeight - 1) * sizeof(uint32_t));
|
memmove(&waterfallFb[dataWidth], waterfallFb, dataWidth * (waterfallHeight - 1) * sizeof(uint32_t));
|
||||||
float pixel;
|
float pixel;
|
||||||
float dataRange = waterfallMax - waterfallMin;
|
float dataRange = waterfallMax - waterfallMin;
|
||||||
@ -563,11 +568,16 @@ namespace ImGui {
|
|||||||
}
|
}
|
||||||
waterfallUpdate = true;
|
waterfallUpdate = true;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
doZoom(drawDataStart, drawDataSize, dataWidth, rawFFTs, latestFFT);
|
||||||
|
fftLines = 1;
|
||||||
|
}
|
||||||
|
|
||||||
buf_mtx.unlock();
|
buf_mtx.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::updatePallette(float colors[][3], int colorCount) {
|
void WaterFall::updatePallette(float colors[][3], int colorCount) {
|
||||||
|
std::lock_guard<std::mutex> lck(buf_mtx);
|
||||||
for (int i = 0; i < WATERFALL_RESOLUTION; i++) {
|
for (int i = 0; i < WATERFALL_RESOLUTION; i++) {
|
||||||
int lowerId = floorf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount);
|
int lowerId = floorf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount);
|
||||||
int upperId = ceilf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount);
|
int upperId = ceilf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount);
|
||||||
@ -579,6 +589,23 @@ namespace ImGui {
|
|||||||
float b = (colors[lowerId][2] * (1.0 - ratio)) + (colors[upperId][2] * (ratio));
|
float b = (colors[lowerId][2] * (1.0 - ratio)) + (colors[upperId][2] * (ratio));
|
||||||
waterfallPallet[i] = ((uint32_t)255 << 24) | ((uint32_t)b << 16) | ((uint32_t)g << 8) | (uint32_t)r;
|
waterfallPallet[i] = ((uint32_t)255 << 24) | ((uint32_t)b << 16) | ((uint32_t)g << 8) | (uint32_t)r;
|
||||||
}
|
}
|
||||||
|
updateWaterfallFb();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaterFall::updatePalletteFromArray(float* colors, int colorCount) {
|
||||||
|
std::lock_guard<std::mutex> lck(buf_mtx);
|
||||||
|
for (int i = 0; i < WATERFALL_RESOLUTION; i++) {
|
||||||
|
int lowerId = floorf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount);
|
||||||
|
int upperId = ceilf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount);
|
||||||
|
lowerId = std::clamp<int>(lowerId, 0, colorCount - 1);
|
||||||
|
upperId = std::clamp<int>(upperId, 0, colorCount - 1);
|
||||||
|
float ratio = (((float)i / (float)WATERFALL_RESOLUTION) * colorCount) - lowerId;
|
||||||
|
float r = (colors[(lowerId * 3) + 0] * (1.0 - ratio)) + (colors[(upperId * 3) + 0] * (ratio));
|
||||||
|
float g = (colors[(lowerId * 3) + 1] * (1.0 - ratio)) + (colors[(upperId * 3) + 1] * (ratio));
|
||||||
|
float b = (colors[(lowerId * 3) + 2] * (1.0 - ratio)) + (colors[(upperId * 3) + 2] * (ratio));
|
||||||
|
waterfallPallet[i] = ((uint32_t)255 << 24) | ((uint32_t)b << 16) | ((uint32_t)g << 8) | (uint32_t)r;
|
||||||
|
}
|
||||||
|
updateWaterfallFb();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::autoRange() {
|
void WaterFall::autoRange() {
|
||||||
@ -627,6 +654,7 @@ namespace ImGui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::setViewBandwidth(double bandWidth) {
|
void WaterFall::setViewBandwidth(double bandWidth) {
|
||||||
|
std::lock_guard<std::mutex> lck(buf_mtx);
|
||||||
if (bandWidth == viewBandwidth) {
|
if (bandWidth == viewBandwidth) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -651,6 +679,7 @@ namespace ImGui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::setViewOffset(double offset) {
|
void WaterFall::setViewOffset(double offset) {
|
||||||
|
std::lock_guard<std::mutex> lck(buf_mtx);
|
||||||
if (offset == viewOffset) {
|
if (offset == viewOffset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -690,6 +719,7 @@ namespace ImGui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::setWaterfallMin(float min) {
|
void WaterFall::setWaterfallMin(float min) {
|
||||||
|
std::lock_guard<std::mutex> lck(buf_mtx);
|
||||||
if (min == waterfallMin) {
|
if (min == waterfallMin) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -702,6 +732,7 @@ namespace ImGui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::setWaterfallMax(float max) {
|
void WaterFall::setWaterfallMax(float max) {
|
||||||
|
std::lock_guard<std::mutex> lck(buf_mtx);
|
||||||
if (max == waterfallMax) {
|
if (max == waterfallMax) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -720,16 +751,17 @@ namespace ImGui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::setRawFFTSize(int size, bool lock) {
|
void WaterFall::setRawFFTSize(int size, bool lock) {
|
||||||
if (lock) { buf_mtx.lock(); }
|
std::lock_guard<std::mutex> lck(buf_mtx);
|
||||||
rawFFTSize = size;
|
rawFFTSize = size;
|
||||||
if (rawFFTs != NULL) {
|
if (rawFFTs != NULL) {
|
||||||
rawFFTs = (float*)realloc(rawFFTs, rawFFTSize * waterfallHeight * sizeof(float));
|
int wfSize = std::max<int>(1, waterfallHeight);
|
||||||
|
rawFFTs = (float*)realloc(rawFFTs, rawFFTSize * wfSize * sizeof(float));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rawFFTs = (float*)malloc(rawFFTSize * waterfallHeight * sizeof(float));
|
int wfSize = std::max<int>(1, waterfallHeight);
|
||||||
|
rawFFTs = (float*)malloc(rawFFTSize * wfSize * sizeof(float));
|
||||||
}
|
}
|
||||||
memset(rawFFTs, 0, rawFFTSize * waterfallHeight * sizeof(float));
|
memset(rawFFTs, 0, rawFFTSize * waterfallHeight * sizeof(float));
|
||||||
if (lock) { buf_mtx.unlock(); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterfallVFO::setOffset(double offset) {
|
void WaterfallVFO::setOffset(double offset) {
|
||||||
@ -845,15 +877,17 @@ namespace ImGui {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void WaterFall::showWaterfall() {
|
void WaterFall::showWaterfall() {
|
||||||
waterfallVisible = true;
|
|
||||||
buf_mtx.lock();
|
buf_mtx.lock();
|
||||||
|
waterfallVisible = true;
|
||||||
onResize();
|
onResize();
|
||||||
|
memset(rawFFTs, 0, waterfallHeight * rawFFTSize * sizeof(float));
|
||||||
|
updateWaterfallFb();
|
||||||
buf_mtx.unlock();
|
buf_mtx.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::hideWaterfall() {
|
void WaterFall::hideWaterfall() {
|
||||||
waterfallVisible = false;
|
|
||||||
buf_mtx.lock();
|
buf_mtx.lock();
|
||||||
|
waterfallVisible = false;
|
||||||
onResize();
|
onResize();
|
||||||
buf_mtx.unlock();
|
buf_mtx.unlock();
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,7 @@ namespace ImGui {
|
|||||||
void pushFFT();
|
void pushFFT();
|
||||||
|
|
||||||
void updatePallette(float colors[][3], int colorCount);
|
void updatePallette(float colors[][3], int colorCount);
|
||||||
|
void updatePalletteFromArray(float* colors, int colorCount);
|
||||||
|
|
||||||
void setCenterFrequency(double freq);
|
void setCenterFrequency(double freq);
|
||||||
double getCenterFrequency();
|
double getCenterFrequency();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
@ -1,5 +1,6 @@
|
|||||||
#include <options.h>
|
#include <options.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
namespace options {
|
namespace options {
|
||||||
CMDLineOptions opts;
|
CMDLineOptions opts;
|
||||||
@ -8,7 +9,8 @@ namespace options {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
opts.root = ".";
|
opts.root = ".";
|
||||||
#else
|
#else
|
||||||
opts.root = "~/.sdrpp/";
|
std::string homedir = getenv("HOME");
|
||||||
|
opts.root = homedir + "/.config/sdrpp";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
|
|
||||||
namespace options {
|
namespace options {
|
||||||
struct CMDLineOptions {
|
struct CMDLineOptions {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <signal_path/vfo_manager.h>
|
#include <signal_path/vfo_manager.h>
|
||||||
#include <signal_path/source.h>
|
#include <signal_path/source.h>
|
||||||
#include <signal_path/sink.h>
|
#include <signal_path/sink.h>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
|
|
||||||
namespace sigpath {
|
namespace sigpath {
|
||||||
SDRPP_EXPORT SignalPath signalPath;
|
SDRPP_EXPORT SignalPath signalPath;
|
||||||
|
@ -16,6 +16,7 @@ public:
|
|||||||
|
|
||||||
class Sink {
|
class Sink {
|
||||||
public:
|
public:
|
||||||
|
virtual ~Sink() {}
|
||||||
virtual void start() = 0;
|
virtual void start() = 0;
|
||||||
virtual void stop() = 0;
|
virtual void stop() = 0;
|
||||||
virtual void menuHandler() = 0;
|
virtual void menuHandler() = 0;
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define VERSION_STR "0.2.5_alpha"
|
#define VERSION_STR "0.2.5_beta"
|
@ -80,7 +80,7 @@ private:
|
|||||||
static void worker(void* ctx) {
|
static void worker(void* ctx) {
|
||||||
FileSourceModule* _this = (FileSourceModule*)ctx;
|
FileSourceModule* _this = (FileSourceModule*)ctx;
|
||||||
double sampleRate = _this->reader->getSampleRate();
|
double sampleRate = _this->reader->getSampleRate();
|
||||||
int blockSize = sampleRate / 200.0;
|
int blockSize = sampleRate / 200.0f;
|
||||||
int16_t* inBuf = new int16_t[blockSize * 2];
|
int16_t* inBuf = new int16_t[blockSize * 2];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
31
hackrf_source/CMakeLists.txt
Normal file
31
hackrf_source/CMakeLists.txt
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
project(hackrf_source)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
|
||||||
|
else()
|
||||||
|
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
|
||||||
|
endif (MSVC)
|
||||||
|
|
||||||
|
include_directories("src/")
|
||||||
|
|
||||||
|
file(GLOB SRC "src/*.cpp")
|
||||||
|
|
||||||
|
add_library(hackrf_source SHARED ${SRC})
|
||||||
|
target_link_libraries(hackrf_source PRIVATE sdrpp_core)
|
||||||
|
set_target_properties(hackrf_source PROPERTIES PREFIX "")
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
# Lib path
|
||||||
|
target_link_directories(sdrpp_core PUBLIC "C:/Program Files/PothosSDR/bin/")
|
||||||
|
|
||||||
|
target_link_libraries(hackrf_source PUBLIC hackrf)
|
||||||
|
else (MSVC)
|
||||||
|
find_package(PkgConfig)
|
||||||
|
|
||||||
|
pkg_check_modules(LIBHACKRF REQUIRED libhackrf)
|
||||||
|
|
||||||
|
target_include_directories(hackrf_source PUBLIC ${LIBHACKRF_INCLUDE_DIRS})
|
||||||
|
target_link_directories(hackrf_source PUBLIC ${LIBHACKRF_LIBRARY_DIRS})
|
||||||
|
target_link_libraries(hackrf_source PUBLIC ${LIBHACKRF_LIBRARIES})
|
||||||
|
endif (MSVC)
|
277
hackrf_source/src/main.cpp
Normal file
277
hackrf_source/src/main.cpp
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
#include <imgui.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <module.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <signal_path/signal_path.h>
|
||||||
|
#include <core.h>
|
||||||
|
#include <gui/style.h>
|
||||||
|
#include <config.h>
|
||||||
|
#include <libhackrf/hackrf.h>
|
||||||
|
|
||||||
|
#pragma optimize( "", off )
|
||||||
|
|
||||||
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
|
|
||||||
|
SDRPP_MOD_INFO {
|
||||||
|
/* Name: */ "hackrf_source",
|
||||||
|
/* Description: */ "HackRF source module for SDR++",
|
||||||
|
/* Author: */ "Ryzerth",
|
||||||
|
/* Version: */ 0, 1, 0,
|
||||||
|
/* Max instances */ 1
|
||||||
|
};
|
||||||
|
|
||||||
|
//ConfigManager config;
|
||||||
|
|
||||||
|
const char* AGG_MODES_STR = "Off\0Low\0High\0";
|
||||||
|
|
||||||
|
const char* sampleRatesTxt = "20MHz\00016MHz\00010MHz\0008MHz\0005MHz\0004MHz\0002MHz\000";
|
||||||
|
|
||||||
|
const int sampleRates[] = {
|
||||||
|
20000000,
|
||||||
|
16000000,
|
||||||
|
10000000,
|
||||||
|
8000000,
|
||||||
|
5000000,
|
||||||
|
4000000,
|
||||||
|
2000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
class HackRFSourceModule : public ModuleManager::Instance {
|
||||||
|
public:
|
||||||
|
HackRFSourceModule(std::string name) {
|
||||||
|
this->name = name;
|
||||||
|
|
||||||
|
hackrf_init();
|
||||||
|
|
||||||
|
sampleRate = 2000000;
|
||||||
|
|
||||||
|
handler.ctx = this;
|
||||||
|
handler.selectHandler = menuSelected;
|
||||||
|
handler.deselectHandler = menuDeselected;
|
||||||
|
handler.menuHandler = menuHandler;
|
||||||
|
handler.startHandler = start;
|
||||||
|
handler.stopHandler = stop;
|
||||||
|
handler.tuneHandler = tune;
|
||||||
|
handler.stream = &stream;
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
selectFirst();
|
||||||
|
|
||||||
|
// config.aquire();
|
||||||
|
// std::string serString = config.conf["device"];
|
||||||
|
// config.release();
|
||||||
|
|
||||||
|
sigpath::sourceManager.registerSource("HackRF", &handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
~HackRFSourceModule() {
|
||||||
|
hackrf_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void enable() {
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable() {
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() {
|
||||||
|
devList.clear();
|
||||||
|
devListTxt = "";
|
||||||
|
|
||||||
|
uint64_t serials[256];
|
||||||
|
hackrf_device_list_t* _devList = hackrf_device_list();
|
||||||
|
|
||||||
|
for (int i = 0; i < _devList->devicecount; i++) {
|
||||||
|
devList.push_back(_devList->serial_numbers[i]);
|
||||||
|
devListTxt += (char*)(_devList->serial_numbers[i] + 16);
|
||||||
|
devListTxt += '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
hackrf_device_list_free(_devList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectFirst() {
|
||||||
|
if (devList.size() != 0) {
|
||||||
|
selectedSerial = devList[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void menuSelected(void* ctx) {
|
||||||
|
HackRFSourceModule* _this = (HackRFSourceModule*)ctx;
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
spdlog::info("HackRFSourceModule '{0}': Menu Select!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menuDeselected(void* ctx) {
|
||||||
|
HackRFSourceModule* _this = (HackRFSourceModule*)ctx;
|
||||||
|
spdlog::info("HackRFSourceModule '{0}': Menu Deselect!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void start(void* ctx) {
|
||||||
|
HackRFSourceModule* _this = (HackRFSourceModule*)ctx;
|
||||||
|
if (_this->running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_this->selectedSerial == "") {
|
||||||
|
spdlog::error("Tried to start HackRF source with empty serial");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int err = hackrf_open_by_serial(_this->selectedSerial.c_str(), &_this->openDev);
|
||||||
|
if (err != 0) {
|
||||||
|
spdlog::error("Could not open HackRF {0}", _this->selectedSerial);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hackrf_set_sample_rate(_this->openDev, _this->sampleRate);
|
||||||
|
hackrf_set_baseband_filter_bandwidth(_this->openDev, hackrf_compute_baseband_filter_bw(_this->sampleRate));
|
||||||
|
hackrf_set_freq(_this->openDev, _this->freq);
|
||||||
|
|
||||||
|
hackrf_set_amp_enable(_this->openDev, _this->amp);
|
||||||
|
hackrf_set_lna_gain(_this->openDev, _this->lna);
|
||||||
|
hackrf_set_vga_gain(_this->openDev, _this->lna);
|
||||||
|
|
||||||
|
hackrf_start_rx(_this->openDev, callback, _this);
|
||||||
|
|
||||||
|
_this->running = true;
|
||||||
|
spdlog::info("HackRFSourceModule '{0}': Start!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stop(void* ctx) {
|
||||||
|
HackRFSourceModule* _this = (HackRFSourceModule*)ctx;
|
||||||
|
if (!_this->running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_this->running = false;
|
||||||
|
_this->stream.stopWriter();
|
||||||
|
// TODO: Stream stop
|
||||||
|
hackrf_close(_this->openDev);
|
||||||
|
_this->stream.clearWriteStop();
|
||||||
|
spdlog::info("HackRFSourceModule '{0}': Stop!", _this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tune(double freq, void* ctx) {
|
||||||
|
HackRFSourceModule* _this = (HackRFSourceModule*)ctx;
|
||||||
|
if (_this->running) {
|
||||||
|
hackrf_set_freq(_this->openDev, freq);
|
||||||
|
}
|
||||||
|
_this->freq = freq;
|
||||||
|
spdlog::info("HackRFSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menuHandler(void* ctx) {
|
||||||
|
HackRFSourceModule* _this = (HackRFSourceModule*)ctx;
|
||||||
|
float menuWidth = ImGui::GetContentRegionAvailWidth();
|
||||||
|
|
||||||
|
if (_this->running) { style::beginDisabled(); }
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(menuWidth);
|
||||||
|
if (ImGui::Combo(CONCAT("##_hackrf_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) {
|
||||||
|
_this->selectedSerial = _this->devList[_this->devId];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Combo(CONCAT("##_hackrf_sr_sel_", _this->name), &_this->srId, sampleRatesTxt)) {
|
||||||
|
_this->sampleRate = sampleRates[_this->srId];
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX();
|
||||||
|
if (ImGui::Button(CONCAT("Refresh##_hackrf_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) {
|
||||||
|
_this->refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_this->running) { style::endDisabled(); }
|
||||||
|
|
||||||
|
ImGui::Text("Amp Enabled");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Checkbox(CONCAT("##_hackrf_amp_", _this->name), &_this->amp)) {
|
||||||
|
if (_this->running) {
|
||||||
|
hackrf_set_amp_enable(_this->openDev, _this->amp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Text("LNA Gain");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::SliderInt(CONCAT("##_hackrf_lna_", _this->name), &_this->lna, 0, 40)) {
|
||||||
|
_this->lna = (_this->lna / 8) * 8;
|
||||||
|
if (_this->running) {
|
||||||
|
hackrf_set_lna_gain(_this->openDev, _this->lna);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Text("LNA Gain");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::SliderInt(CONCAT("##_hackrf_vga_", _this->name), &_this->vga, 0, 62)) {
|
||||||
|
_this->vga = (_this->vga / 2) * 2;
|
||||||
|
if (_this->running) {
|
||||||
|
hackrf_set_vga_gain(_this->openDev, _this->lna);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int callback(hackrf_transfer* transfer) {
|
||||||
|
HackRFSourceModule* _this = (HackRFSourceModule*)transfer->rx_ctx;
|
||||||
|
int count = transfer->valid_length / 2;
|
||||||
|
int8_t* buffer = (int8_t*)transfer->buffer;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
_this->stream.writeBuf[i].i = (float)buffer[i * 2] / 128.0f;
|
||||||
|
_this->stream.writeBuf[i].q = (float)buffer[(i * 2) + 1] / 128.0f;
|
||||||
|
}
|
||||||
|
if (!_this->stream.swap(count)) { return -1; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
hackrf_device* openDev;
|
||||||
|
bool enabled = true;
|
||||||
|
dsp::stream<dsp::complex_t> stream;
|
||||||
|
int sampleRate;
|
||||||
|
SourceManager::SourceHandler handler;
|
||||||
|
bool running = false;
|
||||||
|
double freq;
|
||||||
|
std::string selectedSerial = "";
|
||||||
|
int devId = 0;
|
||||||
|
int srId = 0;
|
||||||
|
bool amp = false;
|
||||||
|
int lna = 0;
|
||||||
|
int vga = 0;
|
||||||
|
|
||||||
|
std::vector<std::string> devList;
|
||||||
|
std::string devListTxt;
|
||||||
|
};
|
||||||
|
|
||||||
|
MOD_EXPORT void _INIT_() {
|
||||||
|
// config.setPath(ROOT_DIR "/airspyhf_config.json");
|
||||||
|
// json defConf;
|
||||||
|
// defConf["device"] = "";
|
||||||
|
// defConf["devices"] = json::object();
|
||||||
|
// config.load(defConf);
|
||||||
|
// config.enableAutoSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
||||||
|
return new HackRFSourceModule(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
|
||||||
|
delete (HackRFSourceModule*)instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD_EXPORT void _END_() {
|
||||||
|
// config.disableAutoSave();
|
||||||
|
// config.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma optimize( "", on )
|
49
make_debian_package.sh
Normal file
49
make_debian_package.sh
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Create directory structure
|
||||||
|
echo Create directory structure
|
||||||
|
mkdir sdrpp_debian_amd64
|
||||||
|
mkdir sdrpp_debian_amd64/DEBIAN
|
||||||
|
mkdir sdrpp_debian_amd64/usr
|
||||||
|
mkdir sdrpp_debian_amd64/usr/bin
|
||||||
|
mkdir sdrpp_debian_amd64/usr/share
|
||||||
|
mkdir sdrpp_debian_amd64/usr/share/sdrpp
|
||||||
|
mkdir sdrpp_debian_amd64/usr/lib
|
||||||
|
mkdir sdrpp_debian_amd64/usr/lib/sdrpp
|
||||||
|
mkdir sdrpp_debian_amd64/usr/lib/sdrpp/plugins
|
||||||
|
|
||||||
|
# Create package info
|
||||||
|
echo Create package info
|
||||||
|
echo Package: sdrpp >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
|
echo Version: 0.2.5 >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
|
echo Maintainer: Ryzerth >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
|
echo Architecture: all >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
|
echo Description: Bloat-free SDR receiver software >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
|
|
||||||
|
# Copy core files
|
||||||
|
echo Copy core files
|
||||||
|
cp $1/sdrpp sdrpp_debian_amd64/usr/bin/
|
||||||
|
cp $1/libsdrpp_core.so sdrpp_debian_amd64/usr/lib/
|
||||||
|
|
||||||
|
# Copy reasources
|
||||||
|
echo Copy reasources
|
||||||
|
cp -r root/res/* sdrpp_debian_amd64/usr/share/sdrpp/
|
||||||
|
|
||||||
|
# Copy module
|
||||||
|
echo Copy modules
|
||||||
|
cp $1/radio/radio.so sdrpp_debian_amd64/usr/lib/sdrpp/plugins/
|
||||||
|
cp $1/recorder/recorder.so sdrpp_debian_amd64/usr/lib/sdrpp/plugins/
|
||||||
|
cp $1/airspyhf_source/airspyhf_source.so sdrpp_debian_amd64/usr/lib/sdrpp/plugins/
|
||||||
|
cp $1/airspy_source/airspy_source.so sdrpp_debian_amd64/usr/lib/sdrpp/plugins/
|
||||||
|
cp $1/plutosdr_source/plutosdr_source.so sdrpp_debian_amd64/usr/lib/sdrpp/plugins/
|
||||||
|
cp $1/rtl_tcp_source/rtl_tcp_source.so sdrpp_debian_amd64/usr/lib/sdrpp/plugins/
|
||||||
|
cp $1/soapy_source/soapy_source.so sdrpp_debian_amd64/usr/lib/sdrpp/plugins/
|
||||||
|
cp $1/audio_sink/audio_sink.so sdrpp_debian_amd64/usr/lib/sdrpp/plugins/
|
||||||
|
|
||||||
|
# Create package
|
||||||
|
echo Create packagesudo
|
||||||
|
dpkg-deb --build sdrpp_debian_amd64
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
echo Cleanup
|
||||||
|
rm -rf sdrpp_debian_amd64
|
34
make_windows_package.ps1
Normal file
34
make_windows_package.ps1
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
mkdir sdrpp_windows_x64
|
||||||
|
|
||||||
|
# Copy root
|
||||||
|
cp -Recurse root/* sdrpp_windows_x64/
|
||||||
|
|
||||||
|
# Copy core
|
||||||
|
cp build/Release/* sdrpp_windows_x64/
|
||||||
|
cp 'C:/Program Files/PothosSDR/bin/volk.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
|
# Copy modules
|
||||||
|
cp build/radio/Release/radio.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
|
cp build/recorder/Release/recorder.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
|
cp build/airspyhf_source/Release/airspyhf_source.dll sdrpp_windows_x64/modules/
|
||||||
|
cp 'C:/Program Files/PothosSDR/bin/airspyhf.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
|
cp build/airspy_source/Release/airspy_source.dll sdrpp_windows_x64/modules/
|
||||||
|
cp 'C:/Program Files/PothosSDR/bin/airspy.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
|
cp build/plutosdr_source/Release/plutosdr_source.dll sdrpp_windows_x64/modules/
|
||||||
|
cp 'C:/Program Files/PothosSDR/bin/libiio.dll' sdrpp_windows_x64/
|
||||||
|
cp 'C:/Program Files/PothosSDR/bin/libad9361.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
|
cp build/rtl_tcp_source/Release/rtl_tcp_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
|
cp build/soapy_source/Release/soapy_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
|
cp build/audio_sink/Release/audio_sink.dll sdrpp_windows_x64/modules/
|
||||||
|
cp build/audio_sink/Release/portaudio.dll sdrpp_windows_x64/
|
||||||
|
|
||||||
|
Compress-Archive -Path sdrpp_windows_x64/ -DestinationPath sdrpp_windows_x64.zip
|
||||||
|
|
||||||
|
rm -Force -Recurse sdrpp_windows_x64
|
@ -25,8 +25,8 @@ if (MSVC)
|
|||||||
else (MSVC)
|
else (MSVC)
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
|
|
||||||
pkg_check_modules(SOAPY REQUIRED libiio)
|
pkg_check_modules(LIBIIO REQUIRED libiio)
|
||||||
pkg_check_modules(SOAPY REQUIRED libad9361)
|
pkg_check_modules(LIBAD9361 REQUIRED libad9361)
|
||||||
|
|
||||||
target_include_directories(plutosdr_source PUBLIC ${LIBIIO_INCLUDE_DIRS})
|
target_include_directories(plutosdr_source PUBLIC ${LIBIIO_INCLUDE_DIRS})
|
||||||
target_link_directories(plutosdr_source PUBLIC ${LIBIIO_LIBRARY_DIRS})
|
target_link_directories(plutosdr_source PUBLIC ${LIBIIO_LIBRARY_DIRS})
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <core.h>
|
#include <core.h>
|
||||||
@ -205,7 +205,7 @@ private:
|
|||||||
|
|
||||||
static void worker(void* ctx) {
|
static void worker(void* ctx) {
|
||||||
PlutoSDRSourceModule* _this = (PlutoSDRSourceModule*)ctx;
|
PlutoSDRSourceModule* _this = (PlutoSDRSourceModule*)ctx;
|
||||||
int blockSize = _this->sampleRate / 200.0;
|
int blockSize = _this->sampleRate / 200.0f;
|
||||||
|
|
||||||
struct iio_channel *rx0_i, *rx0_q;
|
struct iio_channel *rx0_i, *rx0_q;
|
||||||
struct iio_buffer *rxbuf;
|
struct iio_buffer *rxbuf;
|
||||||
@ -229,12 +229,11 @@ private:
|
|||||||
|
|
||||||
int16_t* buf = (int16_t*)iio_buffer_first(rxbuf, rx0_i);
|
int16_t* buf = (int16_t*)iio_buffer_first(rxbuf, rx0_i);
|
||||||
|
|
||||||
if (_this->stream.aquire() < 0) { break; }
|
|
||||||
for (int i = 0; i < blockSize; i++) {
|
for (int i = 0; i < blockSize; i++) {
|
||||||
_this->stream.data[i].q = (float)buf[i * 2] / 32768.0f;
|
_this->stream.writeBuf[i].q = (float)buf[i * 2] / 32768.0f;
|
||||||
_this->stream.data[i].i = (float)buf[(i * 2) + 1] / 32768.0f;
|
_this->stream.writeBuf[i].i = (float)buf[(i * 2) + 1] / 32768.0f;
|
||||||
}
|
}
|
||||||
_this->stream.write(blockSize);
|
if (!_this->stream.swap(blockSize)) { break; };
|
||||||
}
|
}
|
||||||
|
|
||||||
iio_buffer_destroy(rxbuf);
|
iio_buffer_destroy(rxbuf);
|
||||||
|
@ -42,7 +42,7 @@ public:
|
|||||||
|
|
||||||
demod.init(&squelch.out);
|
demod.init(&squelch.out);
|
||||||
|
|
||||||
agc.init(&demod.out, 1.0f / 125.0f);
|
agc.init(&demod.out, 20.0f, bbSampRate);
|
||||||
|
|
||||||
float audioBW = std::min<float>(audioSampRate / 2.0f, bw / 2.0f);
|
float audioBW = std::min<float>(audioSampRate / 2.0f, bw / 2.0f);
|
||||||
win.init(audioBW, audioBW, bbSampRate);
|
win.init(audioBW, audioBW, bbSampRate);
|
||||||
@ -151,6 +151,11 @@ private:
|
|||||||
void setBandwidth(float bandWidth) {
|
void setBandwidth(float bandWidth) {
|
||||||
bw = bandWidth;
|
bw = bandWidth;
|
||||||
_vfo->setBandwidth(bw);
|
_vfo->setBandwidth(bw);
|
||||||
|
float audioBW = std::min<float>(audioSampRate / 2.0f, bw / 2.0f);
|
||||||
|
win.setSampleRate(bbSampRate * resamp.getInterpolation());
|
||||||
|
win.setCutoff(audioBW);
|
||||||
|
win.setTransWidth(audioBW);
|
||||||
|
resamp.updateWindow(&win);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSnapInterval(float snapInt) {
|
void setSnapInterval(float snapInt) {
|
||||||
|
@ -53,7 +53,7 @@ public:
|
|||||||
|
|
||||||
c2r.init(&xlator.out);
|
c2r.init(&xlator.out);
|
||||||
|
|
||||||
agc.init(&c2r.out, 1.0f / 125.0f);
|
agc.init(&c2r.out, 20.0f, audioSampRate);
|
||||||
|
|
||||||
m2s.init(&agc.out);
|
m2s.init(&agc.out);
|
||||||
}
|
}
|
||||||
@ -103,11 +103,9 @@ public:
|
|||||||
xlator.stop();
|
xlator.stop();
|
||||||
}
|
}
|
||||||
audioSampRate = sampleRate;
|
audioSampRate = sampleRate;
|
||||||
float audioBW = std::min<float>(audioSampRate / 2.0f, bw / 2.0f);
|
agc.setSampleRate(audioSampRate);
|
||||||
resamp.setOutSampleRate(audioSampRate);
|
resamp.setOutSampleRate(audioSampRate);
|
||||||
win.setSampleRate(bbSampRate * resamp.getInterpolation());
|
win.setSampleRate(bbSampRate * resamp.getInterpolation());
|
||||||
win.setCutoff(audioBW);
|
|
||||||
win.setTransWidth(audioBW);
|
|
||||||
resamp.updateWindow(&win);
|
resamp.updateWindow(&win);
|
||||||
xlator.setSampleRate(audioSampRate);
|
xlator.setSampleRate(audioSampRate);
|
||||||
if (running) {
|
if (running) {
|
||||||
|
@ -42,7 +42,7 @@ public:
|
|||||||
|
|
||||||
demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_DSB);
|
demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_DSB);
|
||||||
|
|
||||||
agc.init(&demod.out, 1.0f / 125.0f);
|
agc.init(&demod.out, 20.0f, bbSampRate);
|
||||||
|
|
||||||
float audioBW = std::min<float>(audioSampRate / 2.0f, bw / 2.0f);
|
float audioBW = std::min<float>(audioSampRate / 2.0f, bw / 2.0f);
|
||||||
win.init(audioBW, audioBW, bbSampRate);
|
win.init(audioBW, audioBW, bbSampRate);
|
||||||
|
@ -42,7 +42,7 @@ public:
|
|||||||
|
|
||||||
demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_LSB);
|
demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_LSB);
|
||||||
|
|
||||||
agc.init(&demod.out, 1.0f / 125.0f);
|
agc.init(&demod.out, 20.0f, bbSampRate);
|
||||||
|
|
||||||
float audioBW = std::min<float>(audioSampRate / 2.0f, bw);
|
float audioBW = std::min<float>(audioSampRate / 2.0f, bw);
|
||||||
win.init(audioBW, audioBW, bbSampRate);
|
win.init(audioBW, audioBW, bbSampRate);
|
||||||
@ -151,6 +151,12 @@ private:
|
|||||||
void setBandwidth(float bandWidth) {
|
void setBandwidth(float bandWidth) {
|
||||||
bw = bandWidth;
|
bw = bandWidth;
|
||||||
_vfo->setBandwidth(bw);
|
_vfo->setBandwidth(bw);
|
||||||
|
demod.setBandWidth(bw);
|
||||||
|
float audioBW = std::min<float>(audioSampRate / 2.0f, bw);
|
||||||
|
win.setSampleRate(bbSampRate * resamp.getInterpolation());
|
||||||
|
win.setCutoff(audioBW);
|
||||||
|
win.setTransWidth(audioBW);
|
||||||
|
resamp.updateWindow(&win);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSnapInterval(float snapInt) {
|
void setSnapInterval(float snapInt) {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include <gui/style.h>
|
#include <gui/style.h>
|
||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <radio_demod.h>
|
#include <radio_demod.h>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
#include <wfm_demod.h>
|
#include <wfm_demod.h>
|
||||||
#include <fm_demod.h>
|
#include <fm_demod.h>
|
||||||
#include <am_demod.h>
|
#include <am_demod.h>
|
||||||
|
@ -42,7 +42,7 @@ public:
|
|||||||
|
|
||||||
demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_USB);
|
demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_USB);
|
||||||
|
|
||||||
agc.init(&demod.out, 1.0f / 125.0f);
|
agc.init(&demod.out, 20.0f, bbSampRate);
|
||||||
|
|
||||||
float audioBW = std::min<float>(audioSampRate / 2.0f, bw);
|
float audioBW = std::min<float>(audioSampRate / 2.0f, bw);
|
||||||
win.init(audioBW, audioBW, bbSampRate);
|
win.init(audioBW, audioBW, bbSampRate);
|
||||||
@ -151,6 +151,12 @@ private:
|
|||||||
void setBandwidth(float bandWidth) {
|
void setBandwidth(float bandWidth) {
|
||||||
bw = bandWidth;
|
bw = bandWidth;
|
||||||
_vfo->setBandwidth(bw);
|
_vfo->setBandwidth(bw);
|
||||||
|
demod.setBandWidth(bw);
|
||||||
|
float audioBW = std::min<float>(audioSampRate / 2.0f, bw);
|
||||||
|
win.setSampleRate(bbSampRate * resamp.getInterpolation());
|
||||||
|
win.setCutoff(audioBW);
|
||||||
|
win.setTransWidth(audioBW);
|
||||||
|
resamp.updateWindow(&win);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSnapInterval(float snapInt) {
|
void setSnapInterval(float snapInt) {
|
||||||
|
56
readme.md
56
readme.md
@ -3,6 +3,8 @@
|
|||||||

|

|
||||||
SDR++ is a cross-platform and open source SDR software with the aim of being bloat free and simple to use.
|
SDR++ is a cross-platform and open source SDR software with the aim of being bloat free and simple to use.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
* [Patreon](https://patreon.com/ryzerth)
|
* [Patreon](https://patreon.com/ryzerth)
|
||||||
* [Discord Server](https://discord.gg/aFgWjyD)
|
* [Discord Server](https://discord.gg/aFgWjyD)
|
||||||
|
|
||||||
@ -29,7 +31,15 @@ Download the latest release from [the Releases page](https://github.com/Alexandr
|
|||||||
To create a desktop short, rightclick the exe and select `Send to -> Desktop (create shortcut)`, then, rename the shortcut on the desktop to whatever you want.
|
To create a desktop short, rightclick the exe and select `Send to -> Desktop (create shortcut)`, then, rename the shortcut on the desktop to whatever you want.
|
||||||
|
|
||||||
## Linux
|
## Linux
|
||||||
TODO
|
Download the latest release from [the Releases page](https://github.com/AlexandreRouma/SDRPlusPlus/releases) and extract to the directory of your choice.
|
||||||
|
|
||||||
|
Then, run:
|
||||||
|
```sh
|
||||||
|
sudo apt install libfftw3-dev libglfw3-dev libglew-dev libvolk2-dev libsoapysdr-dev libairspyhf-dev libiio-dev libad9361-dev portaudio19-dev libhackrf-dev
|
||||||
|
sudo dpkg -i sdrpp_debian_amd64.deb
|
||||||
|
```
|
||||||
|
|
||||||
|
If `libvolk2-dev` is not available, use `libvolk1-dev`.
|
||||||
|
|
||||||
## MacOS
|
## MacOS
|
||||||
TODO
|
TODO
|
||||||
@ -79,6 +89,15 @@ You will first need to edit the `root_dev/config` file to point to the modules t
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You also need to change the location of the resource and module directories, for development, I recommend:
|
||||||
|
```json
|
||||||
|
...
|
||||||
|
"modulesDirectory": "../root_dev/modules",
|
||||||
|
...
|
||||||
|
"resourcesDirectory": "../root_dev/res",
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
Remember that these paths will be relative to the run directory.
|
Remember that these paths will be relative to the run directory.
|
||||||
|
|
||||||
Off cours, remember to add entries for all modules that were built and that you wish to use.
|
Off cours, remember to add entries for all modules that were built and that you wish to use.
|
||||||
@ -115,7 +134,6 @@ The modules built will be some of the following (Repeat the instructions above f
|
|||||||
# Building on Linux / BSD
|
# Building on Linux / BSD
|
||||||
## Install dependencies
|
## Install dependencies
|
||||||
* cmake
|
* cmake
|
||||||
* vcpkg
|
|
||||||
* fftw3
|
* fftw3
|
||||||
* glfw
|
* glfw
|
||||||
* glew
|
* glew
|
||||||
@ -127,6 +145,8 @@ Next install dependencies based on the modules you wish to build:
|
|||||||
* plutosdr_source: libiio, libad9361
|
* plutosdr_source: libiio, libad9361
|
||||||
* audio_sink: portaudio
|
* audio_sink: portaudio
|
||||||
|
|
||||||
|
Note: make sure you're using GCC 8 or later as older versions do not have `std::filesystem` built-in.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
replace `<N>` with the number of threads you wish to use to build
|
replace `<N>` with the number of threads you wish to use to build
|
||||||
```sh
|
```sh
|
||||||
@ -144,7 +164,12 @@ sh ./create_root.sh
|
|||||||
## Running for development
|
## Running for development
|
||||||
If you wish to install SDR++, skip to the next step
|
If you wish to install SDR++, skip to the next step
|
||||||
|
|
||||||
You will first need to edit the `root_dev/config` file to point to the modules that were built. Here us a sample if what it would look like:
|
First run SDR++ from the build directory to generate a default config file
|
||||||
|
```
|
||||||
|
./sdrpp -r ../root_dev/
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, you need to edit the `root_dev/config` file to point to the modules that were built. Here us a sample if what it would look like:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
...
|
...
|
||||||
@ -158,18 +183,27 @@ You will first need to edit the `root_dev/config` file to point to the modules t
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You also need to change the location of the resource and module directories, for development, I recommend:
|
||||||
|
```json
|
||||||
|
...
|
||||||
|
"modulesDirectory": "./root_dev/modules",
|
||||||
|
...
|
||||||
|
"resourcesDirectory": "./root_dev/res",
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
Remember that these paths will be relative to the run directory.
|
Remember that these paths will be relative to the run directory.
|
||||||
|
|
||||||
Off cours, remember to add entries for all modules that were built and that you wish to use.
|
Off cours, remember to add entries for all modules that were built and that you wish to use.
|
||||||
|
|
||||||
Next, from the top directory, you can simply run:
|
Next, from the top directory, you can simply run:
|
||||||
```
|
```
|
||||||
./build/Release/sdrpp.exe -r root_dev
|
./build/sdrpp -r root_dev
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, if you wish to run from the build directory:
|
Or, if you wish to run from the build directory, you need to correct directories in config.json, and:
|
||||||
```
|
```
|
||||||
./Release/sdrpp.exe -r ../root_dev
|
./sdrpp -r ../root_dev
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installing SDR++
|
## Installing SDR++
|
||||||
@ -190,13 +224,17 @@ I will soon publish a contributing.md listing the code style to use.
|
|||||||
* [aosync](https://github.com/aosync)
|
* [aosync](https://github.com/aosync)
|
||||||
* [Alexsey Shestacov](https://github.com/wingrime)
|
* [Alexsey Shestacov](https://github.com/wingrime)
|
||||||
* [Benjamin Kyd](https://github.com/benkyd)
|
* [Benjamin Kyd](https://github.com/benkyd)
|
||||||
* [Tobias Mädel](https://github.com/Manawyrm)
|
* [cropinghigh](https://github.com/cropinghigh)
|
||||||
* [Raov](https://twitter.com/raov_birbtog)
|
|
||||||
* [Howard0su](https://github.com/howard0su)
|
* [Howard0su](https://github.com/howard0su)
|
||||||
|
* [Martin Hauke](https://github.com/mnhauke)
|
||||||
|
* [Raov](https://twitter.com/raov_birbtog)
|
||||||
|
* [Szymon Zakrent](https://github.com/zakrent)
|
||||||
|
* [Tobias Mädel](https://github.com/Manawyrm)
|
||||||
|
|
||||||
|
|
||||||
## Libaries used
|
## Libaries used
|
||||||
* [SoapySDR (PothosWare)](https://github.com/pothosware/SoapySDR)
|
* [SoapySDR (PothosWare)](https://github.com/pothosware/SoapySDR)
|
||||||
* [Dear ImGui (ocornut)](https://github.com/ocornut/imgui)
|
* [Dear ImGui (ocornut)](https://github.com/ocornut/imgui)
|
||||||
* [spdlog (gabime)](https://github.com/gabime/spdlog)
|
* [spdlog (gabime)](https://github.com/gabime/spdlog)
|
||||||
* [json (nlohmann)](https://github.com/nlohmann/json)
|
* [json (nlohmann)](https://github.com/nlohmann/json)
|
||||||
* [portaudio (PortAudio community)](http://www.portaudio.com/)
|
* [portaudio (PortAudio community)](http://www.portaudio.com/)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
#include <watcher.h>
|
#include <watcher.h>
|
||||||
#include <wav.h>
|
#include <wav.h>
|
||||||
#include <dsp/types.h>
|
#include <dsp/types.h>
|
||||||
@ -13,7 +13,6 @@
|
|||||||
#include <gui/style.h>
|
#include <gui/style.h>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <options.h>
|
#include <options.h>
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
|
|
||||||
SDRPP_MOD_INFO {
|
SDRPP_MOD_INFO {
|
||||||
@ -254,8 +253,8 @@ private:
|
|||||||
int count = _this->audioStream->read();
|
int count = _this->audioStream->read();
|
||||||
if (count < 0) { break; }
|
if (count < 0) { break; }
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
sampleBuf[(i * 2) + 0] = _this->audioStream->data[i].l * 0x7FFF;
|
sampleBuf[(i * 2) + 0] = _this->audioStream->readBuf[i].l * 512;
|
||||||
sampleBuf[(i * 2) + 1] = _this->audioStream->data[i].r * 0x7FFF;
|
sampleBuf[(i * 2) + 1] = _this->audioStream->readBuf[i].r * 512;
|
||||||
}
|
}
|
||||||
_this->audioStream->flush();
|
_this->audioStream->flush();
|
||||||
_this->samplesWritten += count;
|
_this->samplesWritten += count;
|
||||||
@ -270,8 +269,8 @@ private:
|
|||||||
int count = _this->iqStream->read();
|
int count = _this->iqStream->read();
|
||||||
if (count < 0) { break; }
|
if (count < 0) { break; }
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
sampleBuf[(i * 2) + 0] = _this->iqStream->data[i].q * 0x7FFF;
|
sampleBuf[(i * 2) + 0] = _this->iqStream->readBuf[i].q * 0x7FFF;
|
||||||
sampleBuf[(i * 2) + 1] = _this->iqStream->data[i].i * 0x7FFF;
|
sampleBuf[(i * 2) + 1] = _this->iqStream->readBuf[i].i * 0x7FFF;
|
||||||
}
|
}
|
||||||
_this->iqStream->flush();
|
_this->iqStream->flush();
|
||||||
_this->samplesWritten += count;
|
_this->samplesWritten += count;
|
||||||
@ -310,6 +309,14 @@ MOD_EXPORT void _INIT_() {
|
|||||||
config.setPath(options::opts.root + "/recorder_config.json");
|
config.setPath(options::opts.root + "/recorder_config.json");
|
||||||
config.load(def);
|
config.load(def);
|
||||||
config.enableAutoSave();
|
config.enableAutoSave();
|
||||||
|
|
||||||
|
// Create default recording directory
|
||||||
|
if (!std::filesystem::exists(options::opts.root + "/recordings")) {
|
||||||
|
spdlog::warn("Recordings directory does not exist, creating it");
|
||||||
|
if (!std::filesystem::create_directory(options::opts.root + "/recordings")) {
|
||||||
|
spdlog::error("Could not create recordings directory");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"broadcast": "#0000FFFF",
|
|
||||||
"amateur": "#FF0000FF",
|
|
||||||
"aviation": "#00FF00FF",
|
|
||||||
"marine": "#00FFFFFF",
|
|
||||||
"military": "#FFFF00FF"
|
|
||||||
}
|
|
87
root/res/bandplans/germany-mobile-lte-bands.json
Normal file
87
root/res/bandplans/germany-mobile-lte-bands.json
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
{
|
||||||
|
"name": "German LTE bands",
|
||||||
|
"country_name": "Germany",
|
||||||
|
"country_code": "DE",
|
||||||
|
"author_name": "Martin Hauke",
|
||||||
|
"author_url": "none",
|
||||||
|
"bands": [
|
||||||
|
{
|
||||||
|
"name": "LTE band 1 (IMT) FDD uplink",
|
||||||
|
"type": "LTE.FDD.uplink",
|
||||||
|
"start": 1920000000,
|
||||||
|
"end": 1980000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LTE band 1 (IMT) FDD downlink",
|
||||||
|
"type": "LTE.FDD.downlink",
|
||||||
|
"start": 2110000000,
|
||||||
|
"end": 2170000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LTE band 3 (DCS) FDD uplink",
|
||||||
|
"type": "LTE.FDD.uplink",
|
||||||
|
"start": 1710000000,
|
||||||
|
"end": 1785000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LTE band 3 (DCS) FDD downlink",
|
||||||
|
"type": "LTE.FDD.downlink",
|
||||||
|
"start": 1805000000,
|
||||||
|
"end": 1880000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LTE band 7 (IMT-E) FDD uplink",
|
||||||
|
"type": "LTE.FDD.uplink",
|
||||||
|
"start": 2500000000,
|
||||||
|
"end": 2570000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LTE band 7 (IMT-E) FDD downlink",
|
||||||
|
"type": "LTE.FDD.downlink",
|
||||||
|
"start": 2620000000,
|
||||||
|
"end": 2690000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LTE band 8 (Extended GSM) FDD uplink",
|
||||||
|
"type": "LTE.FDD.uplink",
|
||||||
|
"start": 880000000,
|
||||||
|
"end": 915000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LTE band 8 (Extended GSM) FDD downlink",
|
||||||
|
"type": "LTE.FDD.downlink",
|
||||||
|
"start": 9250000000,
|
||||||
|
"end": 9600000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LTE band 20 (Digital Dividend) FDD uplink",
|
||||||
|
"type": "LTE.FDD.uplink",
|
||||||
|
"start": 832000000,
|
||||||
|
"end": 862000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LTE band 20 (Digital Dividend) FDD downlink",
|
||||||
|
"type": "LTE.FDD.downlink",
|
||||||
|
"start": 7910000000,
|
||||||
|
"end": 8210000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LTE band 28 (APT) FDD uplink",
|
||||||
|
"type": "LTE.FDD.uplink",
|
||||||
|
"start": 703000000,
|
||||||
|
"end": 748000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LTE band 28 (APT) FDD downlink",
|
||||||
|
"type": "LTE.FDD.downlink",
|
||||||
|
"start": 7580000000,
|
||||||
|
"end": 8030000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LTE band 32 (L-Band (EU)) SDL downlink",
|
||||||
|
"type": "LTE.SDL",
|
||||||
|
"start": 14520000000,
|
||||||
|
"end": 14960000000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
321
root/res/bandplans/germany-mobile-networks.json
Normal file
321
root/res/bandplans/germany-mobile-networks.json
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
{
|
||||||
|
"name": "German Mobile Networks",
|
||||||
|
"country_name": "Germany",
|
||||||
|
"country_code": "DE",
|
||||||
|
"author_name": "Martin Hauke",
|
||||||
|
"author_url": "none",
|
||||||
|
"bands": [
|
||||||
|
{
|
||||||
|
"name": "DVB-T2",
|
||||||
|
"type": "broadcast",
|
||||||
|
"start": 470000000,
|
||||||
|
"end": 694000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "703 Telefonica FDD uplink",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 703000000,
|
||||||
|
"end": 713000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "713 Telekom FDD uplink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 713000000,
|
||||||
|
"end": 723000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "723 Vodafone FDD uplink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 723000000,
|
||||||
|
"end": 733000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "758 Telefonica FDD downlink",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 758000000,
|
||||||
|
"end": 768000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "768 Telekom FDD downlink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 768000000,
|
||||||
|
"end": 778000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "778 Vodafone FDD downlink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 778000000,
|
||||||
|
"end": 788000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "791 Telefonica FDD downlink",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 791000000,
|
||||||
|
"end": 801000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "801 Vodafone FDD downlink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 801000000,
|
||||||
|
"end": 811000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "811 Telekom FDD downlink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 811000000,
|
||||||
|
"end": 821000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "832 Telefonica FDD uplink",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 832000000,
|
||||||
|
"end": 842000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "842 Vodafone FDD uplink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 842000000,
|
||||||
|
"end": 852000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "852 Telekom FDD uplink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 852000000,
|
||||||
|
"end": 862000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "GSM-R FDD uplink",
|
||||||
|
"type": "mobile.gsm-r",
|
||||||
|
"start": 873100000,
|
||||||
|
"end": 880000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "880 Telefonica FDD uplink",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 880000000,
|
||||||
|
"end": 890000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "890 Vodafone FDD uplink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 890000000,
|
||||||
|
"end": 900000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "900 Telekom FDD uplink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 900000000,
|
||||||
|
"end": 915000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "GSM-R FDD downlink",
|
||||||
|
"type": "mobile.gsm-r",
|
||||||
|
"start": 918100000,
|
||||||
|
"end": 925000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "925 Telefonica FDD downlink",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 925000000,
|
||||||
|
"end": 935000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "935 Vodafone FDD downlink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 935000000,
|
||||||
|
"end": 945000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "945 Telekom FDD downlink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 945000000,
|
||||||
|
"end": 960000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1452 Telekom SDL downlink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 1452000000,
|
||||||
|
"end": 1472000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1472 Vodafone SDL downlink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 1472000000,
|
||||||
|
"end": 1492000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1710 Telekom FDD uplink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 1710000000,
|
||||||
|
"end": 1740000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1740 Telefonica FDD uplink",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 1740000000,
|
||||||
|
"end": 1760000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1760 Vodafone FDD uplink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 1760000000,
|
||||||
|
"end": 1785000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1805 Telekom FDD downlink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 1805000000,
|
||||||
|
"end": 1835000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1835 Telefonica FDD downlink",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 1835000000,
|
||||||
|
"end": 1855000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1855 Vodafone FDD downlink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 1855000000,
|
||||||
|
"end": 1880000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DECT",
|
||||||
|
"type": "broadcast",
|
||||||
|
"start": 1880000000,
|
||||||
|
"end": 1900000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1900.1 Telefonica",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 1900100000,
|
||||||
|
"end": 1905100000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1920 Vodafone FDD uplink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 1920000000,
|
||||||
|
"end": 1940000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1940 Telefonica FDD uplink",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 1940000000,
|
||||||
|
"end": 1960000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "1960 Telekom FDD uplink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 1960000000,
|
||||||
|
"end": 1980000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2010.5 Telefonica",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 2010500000,
|
||||||
|
"end": 2024700000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2110 Vodafone FDD downlink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 2110000000,
|
||||||
|
"end": 2130000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2130 Telefonica FDD downlink",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 2130000000,
|
||||||
|
"end": 2150000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2150 Telekom FDD downlink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 2150000000,
|
||||||
|
"end": 2170000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2500 Vodafone FDD uplink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 2500000000,
|
||||||
|
"end": 2520000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2520 Telekom FDD uplink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 2520000000,
|
||||||
|
"end": 2540000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2540 Telefonica FDD uplink",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 2540000000,
|
||||||
|
"end": 2570000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2570 Telefonica TDD",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 2570000000,
|
||||||
|
"end": 2580000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2580 Vodafone TDD",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 2580000000,
|
||||||
|
"end": 2605000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2605 Telekom TDD",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 2605000000,
|
||||||
|
"end": 2610000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2610 Telefonica TDD",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 2610000000,
|
||||||
|
"end": 2620000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2620 Vodafone FDD downlink",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 2620000000,
|
||||||
|
"end": 2640000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2640 Telekom FDD downlink",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 2640000000,
|
||||||
|
"end": 2660000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "2660 Telefonica FDD downlink",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 2660000000,
|
||||||
|
"end": 2690000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "3400 Vodafone",
|
||||||
|
"type": "mobile.mno.vodafone",
|
||||||
|
"start": 3400000000,
|
||||||
|
"end": 3490000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "3490 Drillisch",
|
||||||
|
"type": "mobile.mno.drillisch",
|
||||||
|
"start": 3490000000,
|
||||||
|
"end": 3540000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "3540 Telefonica",
|
||||||
|
"type": "mobile.mno.telefonica",
|
||||||
|
"start": 3540000000,
|
||||||
|
"end": 3610000000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "3610 Telekom",
|
||||||
|
"type": "mobile.mno.telekom",
|
||||||
|
"start": 3610000000,
|
||||||
|
"end": 3700000000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
21
root/res/colormaps/classic.json
Normal file
21
root/res/colormaps/classic.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "Classic",
|
||||||
|
"author": "Youssef Touil",
|
||||||
|
"map": [
|
||||||
|
"#000020",
|
||||||
|
"#000030",
|
||||||
|
"#000050",
|
||||||
|
"#000091",
|
||||||
|
"#1E90FF",
|
||||||
|
"#FFFFFF",
|
||||||
|
"#FFFF00",
|
||||||
|
"#FE6D16",
|
||||||
|
"#FE6D16",
|
||||||
|
"#FF0000",
|
||||||
|
"#FF0000",
|
||||||
|
"#C60000",
|
||||||
|
"#9F0000",
|
||||||
|
"#750000",
|
||||||
|
"#4A0000"
|
||||||
|
]
|
||||||
|
}
|
8
root/res/colormaps/greyscale.json
Normal file
8
root/res/colormaps/greyscale.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "Grey Scale",
|
||||||
|
"author": "Ryzerth",
|
||||||
|
"map": [
|
||||||
|
"#000000",
|
||||||
|
"#FFFFFF"
|
||||||
|
]
|
||||||
|
}
|
262
root/res/colormaps/inferno.json
Normal file
262
root/res/colormaps/inferno.json
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
{
|
||||||
|
"name": "Inferno",
|
||||||
|
"author": "B.I.D.S.",
|
||||||
|
"map": [
|
||||||
|
"#000004",
|
||||||
|
"#010005",
|
||||||
|
"#010106",
|
||||||
|
"#010108",
|
||||||
|
"#02010A",
|
||||||
|
"#02020C",
|
||||||
|
"#02020E",
|
||||||
|
"#030210",
|
||||||
|
"#040312",
|
||||||
|
"#040314",
|
||||||
|
"#050417",
|
||||||
|
"#060419",
|
||||||
|
"#07051B",
|
||||||
|
"#08051D",
|
||||||
|
"#09061F",
|
||||||
|
"#0A0722",
|
||||||
|
"#0B0724",
|
||||||
|
"#0C0826",
|
||||||
|
"#0D0829",
|
||||||
|
"#0E092B",
|
||||||
|
"#10092D",
|
||||||
|
"#110A30",
|
||||||
|
"#120A32",
|
||||||
|
"#140B34",
|
||||||
|
"#150B37",
|
||||||
|
"#160B39",
|
||||||
|
"#180C3C",
|
||||||
|
"#190C3E",
|
||||||
|
"#1B0C41",
|
||||||
|
"#1C0C43",
|
||||||
|
"#1E0C45",
|
||||||
|
"#1F0C48",
|
||||||
|
"#210C4A",
|
||||||
|
"#230C4C",
|
||||||
|
"#240C4F",
|
||||||
|
"#260C51",
|
||||||
|
"#280B53",
|
||||||
|
"#290B55",
|
||||||
|
"#2B0B57",
|
||||||
|
"#2D0B59",
|
||||||
|
"#2F0A5B",
|
||||||
|
"#310A5C",
|
||||||
|
"#320A5E",
|
||||||
|
"#340A5F",
|
||||||
|
"#360961",
|
||||||
|
"#380962",
|
||||||
|
"#390963",
|
||||||
|
"#3B0964",
|
||||||
|
"#3D0965",
|
||||||
|
"#3E0966",
|
||||||
|
"#400A67",
|
||||||
|
"#420A68",
|
||||||
|
"#440A68",
|
||||||
|
"#450A69",
|
||||||
|
"#470B6A",
|
||||||
|
"#490B6A",
|
||||||
|
"#4A0C6B",
|
||||||
|
"#4C0C6B",
|
||||||
|
"#4D0D6C",
|
||||||
|
"#4F0D6C",
|
||||||
|
"#510E6C",
|
||||||
|
"#520E6D",
|
||||||
|
"#540F6D",
|
||||||
|
"#550F6D",
|
||||||
|
"#57106E",
|
||||||
|
"#59106E",
|
||||||
|
"#5A116E",
|
||||||
|
"#5C126E",
|
||||||
|
"#5D126E",
|
||||||
|
"#5F136E",
|
||||||
|
"#61136E",
|
||||||
|
"#62146E",
|
||||||
|
"#64156E",
|
||||||
|
"#65156E",
|
||||||
|
"#67166E",
|
||||||
|
"#69166E",
|
||||||
|
"#6A176E",
|
||||||
|
"#6C186E",
|
||||||
|
"#6D186E",
|
||||||
|
"#6F196E",
|
||||||
|
"#71196E",
|
||||||
|
"#721A6E",
|
||||||
|
"#741A6E",
|
||||||
|
"#751B6E",
|
||||||
|
"#771C6D",
|
||||||
|
"#781C6D",
|
||||||
|
"#7A1D6D",
|
||||||
|
"#7C1D6D",
|
||||||
|
"#7D1E6D",
|
||||||
|
"#7F1E6C",
|
||||||
|
"#801F6C",
|
||||||
|
"#82206C",
|
||||||
|
"#84206B",
|
||||||
|
"#85216B",
|
||||||
|
"#87216B",
|
||||||
|
"#88226A",
|
||||||
|
"#8A226A",
|
||||||
|
"#8C2369",
|
||||||
|
"#8D2369",
|
||||||
|
"#8F2469",
|
||||||
|
"#902568",
|
||||||
|
"#922568",
|
||||||
|
"#932667",
|
||||||
|
"#952667",
|
||||||
|
"#972766",
|
||||||
|
"#982766",
|
||||||
|
"#9A2865",
|
||||||
|
"#9B2964",
|
||||||
|
"#9D2964",
|
||||||
|
"#9F2A63",
|
||||||
|
"#A02A63",
|
||||||
|
"#A22B62",
|
||||||
|
"#A32C61",
|
||||||
|
"#A52C60",
|
||||||
|
"#A62D60",
|
||||||
|
"#A82E5F",
|
||||||
|
"#A92E5E",
|
||||||
|
"#AB2F5E",
|
||||||
|
"#AD305D",
|
||||||
|
"#AE305C",
|
||||||
|
"#B0315B",
|
||||||
|
"#B1325A",
|
||||||
|
"#B3325A",
|
||||||
|
"#B43359",
|
||||||
|
"#B63458",
|
||||||
|
"#B73557",
|
||||||
|
"#B93556",
|
||||||
|
"#BA3655",
|
||||||
|
"#BC3754",
|
||||||
|
"#BD3853",
|
||||||
|
"#BF3952",
|
||||||
|
"#C03A51",
|
||||||
|
"#C13A50",
|
||||||
|
"#C33B4F",
|
||||||
|
"#C43C4E",
|
||||||
|
"#C63D4D",
|
||||||
|
"#C73E4C",
|
||||||
|
"#C83F4B",
|
||||||
|
"#CA404A",
|
||||||
|
"#CB4149",
|
||||||
|
"#CC4248",
|
||||||
|
"#CE4347",
|
||||||
|
"#CF4446",
|
||||||
|
"#D04545",
|
||||||
|
"#D24644",
|
||||||
|
"#D34743",
|
||||||
|
"#D44842",
|
||||||
|
"#D54A41",
|
||||||
|
"#D74B3F",
|
||||||
|
"#D84C3E",
|
||||||
|
"#D94D3D",
|
||||||
|
"#DA4E3C",
|
||||||
|
"#DB503B",
|
||||||
|
"#DD513A",
|
||||||
|
"#DE5238",
|
||||||
|
"#DF5337",
|
||||||
|
"#E05536",
|
||||||
|
"#E15635",
|
||||||
|
"#E25734",
|
||||||
|
"#E35933",
|
||||||
|
"#E45A31",
|
||||||
|
"#E55C30",
|
||||||
|
"#E65D2F",
|
||||||
|
"#E75E2E",
|
||||||
|
"#E8602D",
|
||||||
|
"#E9612B",
|
||||||
|
"#EA632A",
|
||||||
|
"#EB6429",
|
||||||
|
"#EB6628",
|
||||||
|
"#EC6726",
|
||||||
|
"#ED6925",
|
||||||
|
"#EE6A24",
|
||||||
|
"#EF6C23",
|
||||||
|
"#EF6E21",
|
||||||
|
"#F06F20",
|
||||||
|
"#F1711F",
|
||||||
|
"#F1731D",
|
||||||
|
"#F2741C",
|
||||||
|
"#F3761B",
|
||||||
|
"#F37819",
|
||||||
|
"#F47918",
|
||||||
|
"#F57B17",
|
||||||
|
"#F57D15",
|
||||||
|
"#F67E14",
|
||||||
|
"#F68013",
|
||||||
|
"#F78212",
|
||||||
|
"#F78410",
|
||||||
|
"#F8850F",
|
||||||
|
"#F8870E",
|
||||||
|
"#F8890C",
|
||||||
|
"#F98B0B",
|
||||||
|
"#F98C0A",
|
||||||
|
"#F98E09",
|
||||||
|
"#FA9008",
|
||||||
|
"#FA9207",
|
||||||
|
"#FA9407",
|
||||||
|
"#FB9606",
|
||||||
|
"#FB9706",
|
||||||
|
"#FB9906",
|
||||||
|
"#FB9B06",
|
||||||
|
"#FB9D07",
|
||||||
|
"#FC9F07",
|
||||||
|
"#FCA108",
|
||||||
|
"#FCA309",
|
||||||
|
"#FCA50A",
|
||||||
|
"#FCA60C",
|
||||||
|
"#FCA80D",
|
||||||
|
"#FCAA0F",
|
||||||
|
"#FCAC11",
|
||||||
|
"#FCAE12",
|
||||||
|
"#FCB014",
|
||||||
|
"#FCB216",
|
||||||
|
"#FCB418",
|
||||||
|
"#FBB61A",
|
||||||
|
"#FBB81D",
|
||||||
|
"#FBBA1F",
|
||||||
|
"#FBBC21",
|
||||||
|
"#FBBE23",
|
||||||
|
"#FAC026",
|
||||||
|
"#FAC228",
|
||||||
|
"#FAC42A",
|
||||||
|
"#FAC62D",
|
||||||
|
"#F9C72F",
|
||||||
|
"#F9C932",
|
||||||
|
"#F9CB35",
|
||||||
|
"#F8CD37",
|
||||||
|
"#F8CF3A",
|
||||||
|
"#F7D13D",
|
||||||
|
"#F7D340",
|
||||||
|
"#F6D543",
|
||||||
|
"#F6D746",
|
||||||
|
"#F5D949",
|
||||||
|
"#F5DB4C",
|
||||||
|
"#F4DD4F",
|
||||||
|
"#F4DF53",
|
||||||
|
"#F4E156",
|
||||||
|
"#F3E35A",
|
||||||
|
"#F3E55D",
|
||||||
|
"#F2E661",
|
||||||
|
"#F2E865",
|
||||||
|
"#F2EA69",
|
||||||
|
"#F1EC6D",
|
||||||
|
"#F1ED71",
|
||||||
|
"#F1EF75",
|
||||||
|
"#F1F179",
|
||||||
|
"#F2F27D",
|
||||||
|
"#F2F482",
|
||||||
|
"#F3F586",
|
||||||
|
"#F3F68A",
|
||||||
|
"#F4F88E",
|
||||||
|
"#F5F992",
|
||||||
|
"#F6FA96",
|
||||||
|
"#F8FB9A",
|
||||||
|
"#F9FC9D",
|
||||||
|
"#FAFDA1",
|
||||||
|
"#FCFFA4"
|
||||||
|
]
|
||||||
|
}
|
262
root/res/colormaps/magma.json
Normal file
262
root/res/colormaps/magma.json
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
{
|
||||||
|
"name": "Magma",
|
||||||
|
"author": "B.I.D.S.",
|
||||||
|
"map": [
|
||||||
|
"#000004",
|
||||||
|
"#010005",
|
||||||
|
"#010106",
|
||||||
|
"#010108",
|
||||||
|
"#020109",
|
||||||
|
"#02020B",
|
||||||
|
"#02020D",
|
||||||
|
"#03030F",
|
||||||
|
"#030312",
|
||||||
|
"#040414",
|
||||||
|
"#050416",
|
||||||
|
"#060518",
|
||||||
|
"#06051A",
|
||||||
|
"#07061C",
|
||||||
|
"#08071E",
|
||||||
|
"#090720",
|
||||||
|
"#0A0822",
|
||||||
|
"#0B0924",
|
||||||
|
"#0C0926",
|
||||||
|
"#0D0A29",
|
||||||
|
"#0E0B2B",
|
||||||
|
"#100B2D",
|
||||||
|
"#110C2F",
|
||||||
|
"#120D31",
|
||||||
|
"#130D34",
|
||||||
|
"#140E36",
|
||||||
|
"#150E38",
|
||||||
|
"#160F3B",
|
||||||
|
"#180F3D",
|
||||||
|
"#19103F",
|
||||||
|
"#1A1042",
|
||||||
|
"#1C1044",
|
||||||
|
"#1D1147",
|
||||||
|
"#1E1149",
|
||||||
|
"#20114B",
|
||||||
|
"#21114E",
|
||||||
|
"#221150",
|
||||||
|
"#241253",
|
||||||
|
"#251255",
|
||||||
|
"#271258",
|
||||||
|
"#29115A",
|
||||||
|
"#2A115C",
|
||||||
|
"#2C115F",
|
||||||
|
"#2D1161",
|
||||||
|
"#2F1163",
|
||||||
|
"#311165",
|
||||||
|
"#331067",
|
||||||
|
"#341069",
|
||||||
|
"#36106B",
|
||||||
|
"#38106C",
|
||||||
|
"#390F6E",
|
||||||
|
"#3B0F70",
|
||||||
|
"#3D0F71",
|
||||||
|
"#3F0F72",
|
||||||
|
"#400F74",
|
||||||
|
"#420F75",
|
||||||
|
"#440F76",
|
||||||
|
"#451077",
|
||||||
|
"#471078",
|
||||||
|
"#491078",
|
||||||
|
"#4A1079",
|
||||||
|
"#4C117A",
|
||||||
|
"#4E117B",
|
||||||
|
"#4F127B",
|
||||||
|
"#51127C",
|
||||||
|
"#52137C",
|
||||||
|
"#54137D",
|
||||||
|
"#56147D",
|
||||||
|
"#57157E",
|
||||||
|
"#59157E",
|
||||||
|
"#5A167E",
|
||||||
|
"#5C167F",
|
||||||
|
"#5D177F",
|
||||||
|
"#5F187F",
|
||||||
|
"#601880",
|
||||||
|
"#621980",
|
||||||
|
"#641A80",
|
||||||
|
"#651A80",
|
||||||
|
"#671B80",
|
||||||
|
"#681C81",
|
||||||
|
"#6A1C81",
|
||||||
|
"#6B1D81",
|
||||||
|
"#6D1D81",
|
||||||
|
"#6E1E81",
|
||||||
|
"#701F81",
|
||||||
|
"#721F81",
|
||||||
|
"#732081",
|
||||||
|
"#752181",
|
||||||
|
"#762181",
|
||||||
|
"#782281",
|
||||||
|
"#792282",
|
||||||
|
"#7B2382",
|
||||||
|
"#7C2382",
|
||||||
|
"#7E2482",
|
||||||
|
"#802582",
|
||||||
|
"#812581",
|
||||||
|
"#832681",
|
||||||
|
"#842681",
|
||||||
|
"#862781",
|
||||||
|
"#882781",
|
||||||
|
"#892881",
|
||||||
|
"#8B2981",
|
||||||
|
"#8C2981",
|
||||||
|
"#8E2A81",
|
||||||
|
"#902A81",
|
||||||
|
"#912B81",
|
||||||
|
"#932B80",
|
||||||
|
"#942C80",
|
||||||
|
"#962C80",
|
||||||
|
"#982D80",
|
||||||
|
"#992D80",
|
||||||
|
"#9B2E7F",
|
||||||
|
"#9C2E7F",
|
||||||
|
"#9E2F7F",
|
||||||
|
"#A02F7F",
|
||||||
|
"#A1307E",
|
||||||
|
"#A3307E",
|
||||||
|
"#A5317E",
|
||||||
|
"#A6317D",
|
||||||
|
"#A8327D",
|
||||||
|
"#AA337D",
|
||||||
|
"#AB337C",
|
||||||
|
"#AD347C",
|
||||||
|
"#AE347B",
|
||||||
|
"#B0357B",
|
||||||
|
"#B2357B",
|
||||||
|
"#B3367A",
|
||||||
|
"#B5367A",
|
||||||
|
"#B73779",
|
||||||
|
"#B83779",
|
||||||
|
"#BA3878",
|
||||||
|
"#BC3978",
|
||||||
|
"#BD3977",
|
||||||
|
"#BF3A77",
|
||||||
|
"#C03A76",
|
||||||
|
"#C23B75",
|
||||||
|
"#C43C75",
|
||||||
|
"#C53C74",
|
||||||
|
"#C73D73",
|
||||||
|
"#C83E73",
|
||||||
|
"#CA3E72",
|
||||||
|
"#CC3F71",
|
||||||
|
"#CD4071",
|
||||||
|
"#CF4070",
|
||||||
|
"#D0416F",
|
||||||
|
"#D2426F",
|
||||||
|
"#D3436E",
|
||||||
|
"#D5446D",
|
||||||
|
"#D6456C",
|
||||||
|
"#D8456C",
|
||||||
|
"#D9466B",
|
||||||
|
"#DB476A",
|
||||||
|
"#DC4869",
|
||||||
|
"#DE4968",
|
||||||
|
"#DF4A68",
|
||||||
|
"#E04C67",
|
||||||
|
"#E24D66",
|
||||||
|
"#E34E65",
|
||||||
|
"#E44F64",
|
||||||
|
"#E55064",
|
||||||
|
"#E75263",
|
||||||
|
"#E85362",
|
||||||
|
"#E95462",
|
||||||
|
"#EA5661",
|
||||||
|
"#EB5760",
|
||||||
|
"#EC5860",
|
||||||
|
"#ED5A5F",
|
||||||
|
"#EE5B5E",
|
||||||
|
"#EF5D5E",
|
||||||
|
"#F05F5E",
|
||||||
|
"#F1605D",
|
||||||
|
"#F2625D",
|
||||||
|
"#F2645C",
|
||||||
|
"#F3655C",
|
||||||
|
"#F4675C",
|
||||||
|
"#F4695C",
|
||||||
|
"#F56B5C",
|
||||||
|
"#F66C5C",
|
||||||
|
"#F66E5C",
|
||||||
|
"#F7705C",
|
||||||
|
"#F7725C",
|
||||||
|
"#F8745C",
|
||||||
|
"#F8765C",
|
||||||
|
"#F9785D",
|
||||||
|
"#F9795D",
|
||||||
|
"#F97B5D",
|
||||||
|
"#FA7D5E",
|
||||||
|
"#FA7F5E",
|
||||||
|
"#FA815F",
|
||||||
|
"#FB835F",
|
||||||
|
"#FB8560",
|
||||||
|
"#FB8761",
|
||||||
|
"#FC8961",
|
||||||
|
"#FC8A62",
|
||||||
|
"#FC8C63",
|
||||||
|
"#FC8E64",
|
||||||
|
"#FC9065",
|
||||||
|
"#FD9266",
|
||||||
|
"#FD9467",
|
||||||
|
"#FD9668",
|
||||||
|
"#FD9869",
|
||||||
|
"#FD9A6A",
|
||||||
|
"#FD9B6B",
|
||||||
|
"#FE9D6C",
|
||||||
|
"#FE9F6D",
|
||||||
|
"#FEA16E",
|
||||||
|
"#FEA36F",
|
||||||
|
"#FEA571",
|
||||||
|
"#FEA772",
|
||||||
|
"#FEA973",
|
||||||
|
"#FEAA74",
|
||||||
|
"#FEAC76",
|
||||||
|
"#FEAE77",
|
||||||
|
"#FEB078",
|
||||||
|
"#FEB27A",
|
||||||
|
"#FEB47B",
|
||||||
|
"#FEB67C",
|
||||||
|
"#FEB77E",
|
||||||
|
"#FEB97F",
|
||||||
|
"#FEBB81",
|
||||||
|
"#FEBD82",
|
||||||
|
"#FEBF84",
|
||||||
|
"#FEC185",
|
||||||
|
"#FEC287",
|
||||||
|
"#FEC488",
|
||||||
|
"#FEC68A",
|
||||||
|
"#FEC88C",
|
||||||
|
"#FECA8D",
|
||||||
|
"#FECC8F",
|
||||||
|
"#FECD90",
|
||||||
|
"#FECF92",
|
||||||
|
"#FED194",
|
||||||
|
"#FED395",
|
||||||
|
"#FED597",
|
||||||
|
"#FED799",
|
||||||
|
"#FED89A",
|
||||||
|
"#FDDA9C",
|
||||||
|
"#FDDC9E",
|
||||||
|
"#FDDEA0",
|
||||||
|
"#FDE0A1",
|
||||||
|
"#FDE2A3",
|
||||||
|
"#FDE3A5",
|
||||||
|
"#FDE5A7",
|
||||||
|
"#FDE7A9",
|
||||||
|
"#FDE9AA",
|
||||||
|
"#FDEBAC",
|
||||||
|
"#FCECAE",
|
||||||
|
"#FCEEB0",
|
||||||
|
"#FCF0B2",
|
||||||
|
"#FCF2B4",
|
||||||
|
"#FCF4B6",
|
||||||
|
"#FCF6B8",
|
||||||
|
"#FCF7B9",
|
||||||
|
"#FCF9BB",
|
||||||
|
"#FCFBBD",
|
||||||
|
"#FCFDBF"
|
||||||
|
]
|
||||||
|
}
|
262
root/res/colormaps/plasma.json
Normal file
262
root/res/colormaps/plasma.json
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
{
|
||||||
|
"name": "Plasma",
|
||||||
|
"author": "B.I.D.S.",
|
||||||
|
"map": [
|
||||||
|
"#0D0887",
|
||||||
|
"#100788",
|
||||||
|
"#130789",
|
||||||
|
"#16078A",
|
||||||
|
"#19068C",
|
||||||
|
"#1B068D",
|
||||||
|
"#1D068E",
|
||||||
|
"#20068F",
|
||||||
|
"#220690",
|
||||||
|
"#240691",
|
||||||
|
"#260591",
|
||||||
|
"#280592",
|
||||||
|
"#2A0593",
|
||||||
|
"#2C0594",
|
||||||
|
"#2E0595",
|
||||||
|
"#2F0596",
|
||||||
|
"#310597",
|
||||||
|
"#330597",
|
||||||
|
"#350498",
|
||||||
|
"#370499",
|
||||||
|
"#38049A",
|
||||||
|
"#3A049A",
|
||||||
|
"#3C049B",
|
||||||
|
"#3E049C",
|
||||||
|
"#3F049C",
|
||||||
|
"#41049D",
|
||||||
|
"#43039E",
|
||||||
|
"#44039E",
|
||||||
|
"#46039F",
|
||||||
|
"#48039F",
|
||||||
|
"#4903A0",
|
||||||
|
"#4B03A1",
|
||||||
|
"#4C02A1",
|
||||||
|
"#4E02A2",
|
||||||
|
"#5002A2",
|
||||||
|
"#5102A3",
|
||||||
|
"#5302A3",
|
||||||
|
"#5502A4",
|
||||||
|
"#5601A4",
|
||||||
|
"#5801A4",
|
||||||
|
"#5901A5",
|
||||||
|
"#5B01A5",
|
||||||
|
"#5C01A6",
|
||||||
|
"#5E01A6",
|
||||||
|
"#6001A6",
|
||||||
|
"#6100A7",
|
||||||
|
"#6300A7",
|
||||||
|
"#6400A7",
|
||||||
|
"#6600A7",
|
||||||
|
"#6700A8",
|
||||||
|
"#6900A8",
|
||||||
|
"#6A00A8",
|
||||||
|
"#6C00A8",
|
||||||
|
"#6E00A8",
|
||||||
|
"#6F00A8",
|
||||||
|
"#7100A8",
|
||||||
|
"#7201A8",
|
||||||
|
"#7401A8",
|
||||||
|
"#7501A8",
|
||||||
|
"#7701A8",
|
||||||
|
"#7801A8",
|
||||||
|
"#7A02A8",
|
||||||
|
"#7B02A8",
|
||||||
|
"#7D03A8",
|
||||||
|
"#7E03A8",
|
||||||
|
"#8004A8",
|
||||||
|
"#8104A7",
|
||||||
|
"#8305A7",
|
||||||
|
"#8405A7",
|
||||||
|
"#8606A6",
|
||||||
|
"#8707A6",
|
||||||
|
"#8808A6",
|
||||||
|
"#8A09A5",
|
||||||
|
"#8B0AA5",
|
||||||
|
"#8D0BA5",
|
||||||
|
"#8E0CA4",
|
||||||
|
"#8F0DA4",
|
||||||
|
"#910EA3",
|
||||||
|
"#920FA3",
|
||||||
|
"#9410A2",
|
||||||
|
"#9511A1",
|
||||||
|
"#9613A1",
|
||||||
|
"#9814A0",
|
||||||
|
"#99159F",
|
||||||
|
"#9A169F",
|
||||||
|
"#9C179E",
|
||||||
|
"#9D189D",
|
||||||
|
"#9E199D",
|
||||||
|
"#A01A9C",
|
||||||
|
"#A11B9B",
|
||||||
|
"#A21D9A",
|
||||||
|
"#A31E9A",
|
||||||
|
"#A51F99",
|
||||||
|
"#A62098",
|
||||||
|
"#A72197",
|
||||||
|
"#A82296",
|
||||||
|
"#AA2395",
|
||||||
|
"#AB2494",
|
||||||
|
"#AC2694",
|
||||||
|
"#AD2793",
|
||||||
|
"#AE2892",
|
||||||
|
"#B02991",
|
||||||
|
"#B12A90",
|
||||||
|
"#B22B8F",
|
||||||
|
"#B32C8E",
|
||||||
|
"#B42E8D",
|
||||||
|
"#B52F8C",
|
||||||
|
"#B6308B",
|
||||||
|
"#B7318A",
|
||||||
|
"#B83289",
|
||||||
|
"#BA3388",
|
||||||
|
"#BB3488",
|
||||||
|
"#BC3587",
|
||||||
|
"#BD3786",
|
||||||
|
"#BE3885",
|
||||||
|
"#BF3984",
|
||||||
|
"#C03A83",
|
||||||
|
"#C13B82",
|
||||||
|
"#C23C81",
|
||||||
|
"#C33D80",
|
||||||
|
"#C43E7F",
|
||||||
|
"#C5407E",
|
||||||
|
"#C6417D",
|
||||||
|
"#C7427C",
|
||||||
|
"#C8437B",
|
||||||
|
"#C9447A",
|
||||||
|
"#CA457A",
|
||||||
|
"#CB4679",
|
||||||
|
"#CC4778",
|
||||||
|
"#CC4977",
|
||||||
|
"#CD4A76",
|
||||||
|
"#CE4B75",
|
||||||
|
"#CF4C74",
|
||||||
|
"#D04D73",
|
||||||
|
"#D14E72",
|
||||||
|
"#D24F71",
|
||||||
|
"#D35171",
|
||||||
|
"#D45270",
|
||||||
|
"#D5536F",
|
||||||
|
"#D5546E",
|
||||||
|
"#D6556D",
|
||||||
|
"#D7566C",
|
||||||
|
"#D8576B",
|
||||||
|
"#D9586A",
|
||||||
|
"#DA5A6A",
|
||||||
|
"#DA5B69",
|
||||||
|
"#DB5C68",
|
||||||
|
"#DC5D67",
|
||||||
|
"#DD5E66",
|
||||||
|
"#DE5F65",
|
||||||
|
"#DE6164",
|
||||||
|
"#DF6263",
|
||||||
|
"#E06363",
|
||||||
|
"#E16462",
|
||||||
|
"#E26561",
|
||||||
|
"#E26660",
|
||||||
|
"#E3685F",
|
||||||
|
"#E4695E",
|
||||||
|
"#E56A5D",
|
||||||
|
"#E56B5D",
|
||||||
|
"#E66C5C",
|
||||||
|
"#E76E5B",
|
||||||
|
"#E76F5A",
|
||||||
|
"#E87059",
|
||||||
|
"#E97158",
|
||||||
|
"#E97257",
|
||||||
|
"#EA7457",
|
||||||
|
"#EB7556",
|
||||||
|
"#EB7655",
|
||||||
|
"#EC7754",
|
||||||
|
"#ED7953",
|
||||||
|
"#ED7A52",
|
||||||
|
"#EE7B51",
|
||||||
|
"#EF7C51",
|
||||||
|
"#EF7E50",
|
||||||
|
"#F07F4F",
|
||||||
|
"#F0804E",
|
||||||
|
"#F1814D",
|
||||||
|
"#F1834C",
|
||||||
|
"#F2844B",
|
||||||
|
"#F3854B",
|
||||||
|
"#F3874A",
|
||||||
|
"#F48849",
|
||||||
|
"#F48948",
|
||||||
|
"#F58B47",
|
||||||
|
"#F58C46",
|
||||||
|
"#F68D45",
|
||||||
|
"#F68F44",
|
||||||
|
"#F79044",
|
||||||
|
"#F79143",
|
||||||
|
"#F79342",
|
||||||
|
"#F89441",
|
||||||
|
"#F89540",
|
||||||
|
"#F9973F",
|
||||||
|
"#F9983E",
|
||||||
|
"#F99A3E",
|
||||||
|
"#FA9B3D",
|
||||||
|
"#FA9C3C",
|
||||||
|
"#FA9E3B",
|
||||||
|
"#FB9F3A",
|
||||||
|
"#FBA139",
|
||||||
|
"#FBA238",
|
||||||
|
"#FCA338",
|
||||||
|
"#FCA537",
|
||||||
|
"#FCA636",
|
||||||
|
"#FCA835",
|
||||||
|
"#FCA934",
|
||||||
|
"#FDAB33",
|
||||||
|
"#FDAC33",
|
||||||
|
"#FDAE32",
|
||||||
|
"#FDAF31",
|
||||||
|
"#FDB130",
|
||||||
|
"#FDB22F",
|
||||||
|
"#FDB42F",
|
||||||
|
"#FDB52E",
|
||||||
|
"#FEB72D",
|
||||||
|
"#FEB82C",
|
||||||
|
"#FEBA2C",
|
||||||
|
"#FEBB2B",
|
||||||
|
"#FEBD2A",
|
||||||
|
"#FEBE2A",
|
||||||
|
"#FEC029",
|
||||||
|
"#FDC229",
|
||||||
|
"#FDC328",
|
||||||
|
"#FDC527",
|
||||||
|
"#FDC627",
|
||||||
|
"#FDC827",
|
||||||
|
"#FDCA26",
|
||||||
|
"#FDCB26",
|
||||||
|
"#FCCD25",
|
||||||
|
"#FCCE25",
|
||||||
|
"#FCD025",
|
||||||
|
"#FCD225",
|
||||||
|
"#FBD324",
|
||||||
|
"#FBD524",
|
||||||
|
"#FBD724",
|
||||||
|
"#FAD824",
|
||||||
|
"#FADA24",
|
||||||
|
"#F9DC24",
|
||||||
|
"#F9DD25",
|
||||||
|
"#F8DF25",
|
||||||
|
"#F8E125",
|
||||||
|
"#F7E225",
|
||||||
|
"#F7E425",
|
||||||
|
"#F6E626",
|
||||||
|
"#F6E826",
|
||||||
|
"#F5E926",
|
||||||
|
"#F5EB27",
|
||||||
|
"#F4ED27",
|
||||||
|
"#F3EE27",
|
||||||
|
"#F3F027",
|
||||||
|
"#F2F227",
|
||||||
|
"#F1F426",
|
||||||
|
"#F1F525",
|
||||||
|
"#F0F724",
|
||||||
|
"#F0F921"
|
||||||
|
]
|
||||||
|
}
|
262
root/res/colormaps/turbo.json
Normal file
262
root/res/colormaps/turbo.json
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
{
|
||||||
|
"name": "Turbo",
|
||||||
|
"author": "Google AI",
|
||||||
|
"map": [
|
||||||
|
"#30123B",
|
||||||
|
"#321543",
|
||||||
|
"#33184A",
|
||||||
|
"#341B51",
|
||||||
|
"#351E58",
|
||||||
|
"#36215F",
|
||||||
|
"#372466",
|
||||||
|
"#38276D",
|
||||||
|
"#392A73",
|
||||||
|
"#3A2D79",
|
||||||
|
"#3B2F80",
|
||||||
|
"#3C3286",
|
||||||
|
"#3D358B",
|
||||||
|
"#3E3891",
|
||||||
|
"#3F3B97",
|
||||||
|
"#3F3E9C",
|
||||||
|
"#4040A2",
|
||||||
|
"#4143A7",
|
||||||
|
"#4146AC",
|
||||||
|
"#4249B1",
|
||||||
|
"#424BB5",
|
||||||
|
"#434EBA",
|
||||||
|
"#4451BF",
|
||||||
|
"#4454C3",
|
||||||
|
"#4456C7",
|
||||||
|
"#4559CB",
|
||||||
|
"#455CCF",
|
||||||
|
"#455ED3",
|
||||||
|
"#4661D6",
|
||||||
|
"#4664DA",
|
||||||
|
"#4666DD",
|
||||||
|
"#4669E0",
|
||||||
|
"#466BE3",
|
||||||
|
"#476EE6",
|
||||||
|
"#4771E9",
|
||||||
|
"#4773EB",
|
||||||
|
"#4776EE",
|
||||||
|
"#4778F0",
|
||||||
|
"#477BF2",
|
||||||
|
"#467DF4",
|
||||||
|
"#4680F6",
|
||||||
|
"#4682F8",
|
||||||
|
"#4685FA",
|
||||||
|
"#4687FB",
|
||||||
|
"#458AFC",
|
||||||
|
"#458CFD",
|
||||||
|
"#448FFE",
|
||||||
|
"#4391FE",
|
||||||
|
"#4294FF",
|
||||||
|
"#4196FF",
|
||||||
|
"#4099FF",
|
||||||
|
"#3E9BFE",
|
||||||
|
"#3D9EFE",
|
||||||
|
"#3BA0FD",
|
||||||
|
"#3AA3FC",
|
||||||
|
"#38A5FB",
|
||||||
|
"#37A8FA",
|
||||||
|
"#35ABF8",
|
||||||
|
"#33ADF7",
|
||||||
|
"#31AFF5",
|
||||||
|
"#2FB2F4",
|
||||||
|
"#2EB4F2",
|
||||||
|
"#2CB7F0",
|
||||||
|
"#2AB9EE",
|
||||||
|
"#28BCEB",
|
||||||
|
"#27BEE9",
|
||||||
|
"#25C0E7",
|
||||||
|
"#23C3E4",
|
||||||
|
"#22C5E2",
|
||||||
|
"#20C7DF",
|
||||||
|
"#1FC9DD",
|
||||||
|
"#1ECBDA",
|
||||||
|
"#1CCDD8",
|
||||||
|
"#1BD0D5",
|
||||||
|
"#1AD2D2",
|
||||||
|
"#1AD4D0",
|
||||||
|
"#19D5CD",
|
||||||
|
"#18D7CA",
|
||||||
|
"#18D9C8",
|
||||||
|
"#18DBC5",
|
||||||
|
"#18DDC2",
|
||||||
|
"#18DEC0",
|
||||||
|
"#18E0BD",
|
||||||
|
"#19E2BB",
|
||||||
|
"#19E3B9",
|
||||||
|
"#1AE4B6",
|
||||||
|
"#1CE6B4",
|
||||||
|
"#1DE7B2",
|
||||||
|
"#1FE9AF",
|
||||||
|
"#20EAAC",
|
||||||
|
"#22EBAA",
|
||||||
|
"#25ECA7",
|
||||||
|
"#27EEA4",
|
||||||
|
"#2AEFA1",
|
||||||
|
"#2CF09E",
|
||||||
|
"#2FF19B",
|
||||||
|
"#32F298",
|
||||||
|
"#35F394",
|
||||||
|
"#38F491",
|
||||||
|
"#3CF58E",
|
||||||
|
"#3FF68A",
|
||||||
|
"#43F787",
|
||||||
|
"#46F884",
|
||||||
|
"#4AF880",
|
||||||
|
"#4EF97D",
|
||||||
|
"#52FA7A",
|
||||||
|
"#55FA76",
|
||||||
|
"#59FB73",
|
||||||
|
"#5DFC6F",
|
||||||
|
"#61FC6C",
|
||||||
|
"#65FD69",
|
||||||
|
"#69FD66",
|
||||||
|
"#6DFE62",
|
||||||
|
"#71FE5F",
|
||||||
|
"#75FE5C",
|
||||||
|
"#79FE59",
|
||||||
|
"#7DFF56",
|
||||||
|
"#80FF53",
|
||||||
|
"#84FF51",
|
||||||
|
"#88FF4E",
|
||||||
|
"#8BFF4B",
|
||||||
|
"#8FFF49",
|
||||||
|
"#92FF47",
|
||||||
|
"#96FE44",
|
||||||
|
"#99FE42",
|
||||||
|
"#9CFE40",
|
||||||
|
"#9FFD3F",
|
||||||
|
"#A1FD3D",
|
||||||
|
"#A4FC3C",
|
||||||
|
"#A7FC3A",
|
||||||
|
"#A9FB39",
|
||||||
|
"#ACFB38",
|
||||||
|
"#AFFA37",
|
||||||
|
"#B1F936",
|
||||||
|
"#B4F836",
|
||||||
|
"#B7F735",
|
||||||
|
"#B9F635",
|
||||||
|
"#BCF534",
|
||||||
|
"#BEF434",
|
||||||
|
"#C1F334",
|
||||||
|
"#C3F134",
|
||||||
|
"#C6F034",
|
||||||
|
"#C8EF34",
|
||||||
|
"#CBED34",
|
||||||
|
"#CDEC34",
|
||||||
|
"#D0EA34",
|
||||||
|
"#D2E935",
|
||||||
|
"#D4E735",
|
||||||
|
"#D7E535",
|
||||||
|
"#D9E436",
|
||||||
|
"#DBE236",
|
||||||
|
"#DDE037",
|
||||||
|
"#DFDF37",
|
||||||
|
"#E1DD37",
|
||||||
|
"#E3DB38",
|
||||||
|
"#E5D938",
|
||||||
|
"#E7D739",
|
||||||
|
"#E9D539",
|
||||||
|
"#EBD339",
|
||||||
|
"#ECD13A",
|
||||||
|
"#EECF3A",
|
||||||
|
"#EFCD3A",
|
||||||
|
"#F1CB3A",
|
||||||
|
"#F2C93A",
|
||||||
|
"#F4C73A",
|
||||||
|
"#F5C53A",
|
||||||
|
"#F6C33A",
|
||||||
|
"#F7C13A",
|
||||||
|
"#F8BE39",
|
||||||
|
"#F9BC39",
|
||||||
|
"#FABA39",
|
||||||
|
"#FBB838",
|
||||||
|
"#FBB637",
|
||||||
|
"#FCB336",
|
||||||
|
"#FCB136",
|
||||||
|
"#FDAE35",
|
||||||
|
"#FDAC34",
|
||||||
|
"#FEA933",
|
||||||
|
"#FEA732",
|
||||||
|
"#FEA431",
|
||||||
|
"#FEA130",
|
||||||
|
"#FE9E2F",
|
||||||
|
"#FE9B2D",
|
||||||
|
"#FE992C",
|
||||||
|
"#FE962B",
|
||||||
|
"#FE932A",
|
||||||
|
"#FE9029",
|
||||||
|
"#FD8D27",
|
||||||
|
"#FD8A26",
|
||||||
|
"#FC8725",
|
||||||
|
"#FC8423",
|
||||||
|
"#FB8122",
|
||||||
|
"#FB7E21",
|
||||||
|
"#FA7B1F",
|
||||||
|
"#F9781E",
|
||||||
|
"#F9751D",
|
||||||
|
"#F8721C",
|
||||||
|
"#F76F1A",
|
||||||
|
"#F66C19",
|
||||||
|
"#F56918",
|
||||||
|
"#F46617",
|
||||||
|
"#F36315",
|
||||||
|
"#F26014",
|
||||||
|
"#F15D13",
|
||||||
|
"#F05B12",
|
||||||
|
"#EF5811",
|
||||||
|
"#ED5510",
|
||||||
|
"#EC530F",
|
||||||
|
"#EB500E",
|
||||||
|
"#EA4E0D",
|
||||||
|
"#E84B0C",
|
||||||
|
"#E7490C",
|
||||||
|
"#E5470B",
|
||||||
|
"#E4450A",
|
||||||
|
"#E2430A",
|
||||||
|
"#E14109",
|
||||||
|
"#DF3F08",
|
||||||
|
"#DD3D08",
|
||||||
|
"#DC3B07",
|
||||||
|
"#DA3907",
|
||||||
|
"#D83706",
|
||||||
|
"#D63506",
|
||||||
|
"#D43305",
|
||||||
|
"#D23105",
|
||||||
|
"#D02F05",
|
||||||
|
"#CE2D04",
|
||||||
|
"#CC2B04",
|
||||||
|
"#CA2A04",
|
||||||
|
"#C82803",
|
||||||
|
"#C52603",
|
||||||
|
"#C32503",
|
||||||
|
"#C12302",
|
||||||
|
"#BE2102",
|
||||||
|
"#BC2002",
|
||||||
|
"#B91E02",
|
||||||
|
"#B71D02",
|
||||||
|
"#B41B01",
|
||||||
|
"#B21A01",
|
||||||
|
"#AF1801",
|
||||||
|
"#AC1701",
|
||||||
|
"#A91601",
|
||||||
|
"#A71401",
|
||||||
|
"#A41301",
|
||||||
|
"#A11201",
|
||||||
|
"#9E1001",
|
||||||
|
"#9B0F01",
|
||||||
|
"#980E01",
|
||||||
|
"#950D01",
|
||||||
|
"#920B01",
|
||||||
|
"#8E0A01",
|
||||||
|
"#8B0902",
|
||||||
|
"#880802",
|
||||||
|
"#850702",
|
||||||
|
"#810602",
|
||||||
|
"#7E0502",
|
||||||
|
"#7A0403"
|
||||||
|
]
|
||||||
|
}
|
262
root/res/colormaps/viridis.json
Normal file
262
root/res/colormaps/viridis.json
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
{
|
||||||
|
"name": "Viridis",
|
||||||
|
"author": "B.I.D.S.",
|
||||||
|
"map": [
|
||||||
|
"#440154",
|
||||||
|
"#440256",
|
||||||
|
"#450457",
|
||||||
|
"#450559",
|
||||||
|
"#46075A",
|
||||||
|
"#46085C",
|
||||||
|
"#460A5D",
|
||||||
|
"#460B5E",
|
||||||
|
"#470D60",
|
||||||
|
"#470E61",
|
||||||
|
"#471063",
|
||||||
|
"#471164",
|
||||||
|
"#471365",
|
||||||
|
"#481467",
|
||||||
|
"#481668",
|
||||||
|
"#481769",
|
||||||
|
"#48186A",
|
||||||
|
"#481A6C",
|
||||||
|
"#481B6D",
|
||||||
|
"#481C6E",
|
||||||
|
"#481D6F",
|
||||||
|
"#481F70",
|
||||||
|
"#482071",
|
||||||
|
"#482173",
|
||||||
|
"#482374",
|
||||||
|
"#482475",
|
||||||
|
"#482576",
|
||||||
|
"#482677",
|
||||||
|
"#482878",
|
||||||
|
"#482979",
|
||||||
|
"#472A7A",
|
||||||
|
"#472C7A",
|
||||||
|
"#472D7B",
|
||||||
|
"#472E7C",
|
||||||
|
"#472F7D",
|
||||||
|
"#46307E",
|
||||||
|
"#46327E",
|
||||||
|
"#46337F",
|
||||||
|
"#463480",
|
||||||
|
"#453581",
|
||||||
|
"#453781",
|
||||||
|
"#453882",
|
||||||
|
"#443983",
|
||||||
|
"#443A83",
|
||||||
|
"#443B84",
|
||||||
|
"#433D84",
|
||||||
|
"#433E85",
|
||||||
|
"#423F85",
|
||||||
|
"#424086",
|
||||||
|
"#424186",
|
||||||
|
"#414287",
|
||||||
|
"#414487",
|
||||||
|
"#404588",
|
||||||
|
"#404688",
|
||||||
|
"#3F4788",
|
||||||
|
"#3F4889",
|
||||||
|
"#3E4989",
|
||||||
|
"#3E4A89",
|
||||||
|
"#3E4C8A",
|
||||||
|
"#3D4D8A",
|
||||||
|
"#3D4E8A",
|
||||||
|
"#3C4F8A",
|
||||||
|
"#3C508B",
|
||||||
|
"#3B518B",
|
||||||
|
"#3B528B",
|
||||||
|
"#3A538B",
|
||||||
|
"#3A548C",
|
||||||
|
"#39558C",
|
||||||
|
"#39568C",
|
||||||
|
"#38588C",
|
||||||
|
"#38598C",
|
||||||
|
"#375A8C",
|
||||||
|
"#375B8D",
|
||||||
|
"#365C8D",
|
||||||
|
"#365D8D",
|
||||||
|
"#355E8D",
|
||||||
|
"#355F8D",
|
||||||
|
"#34608D",
|
||||||
|
"#34618D",
|
||||||
|
"#33628D",
|
||||||
|
"#33638D",
|
||||||
|
"#32648E",
|
||||||
|
"#32658E",
|
||||||
|
"#31668E",
|
||||||
|
"#31678E",
|
||||||
|
"#31688E",
|
||||||
|
"#30698E",
|
||||||
|
"#306A8E",
|
||||||
|
"#2F6B8E",
|
||||||
|
"#2F6C8E",
|
||||||
|
"#2E6D8E",
|
||||||
|
"#2E6E8E",
|
||||||
|
"#2E6F8E",
|
||||||
|
"#2D708E",
|
||||||
|
"#2D718E",
|
||||||
|
"#2C718E",
|
||||||
|
"#2C728E",
|
||||||
|
"#2C738E",
|
||||||
|
"#2B748E",
|
||||||
|
"#2B758E",
|
||||||
|
"#2A768E",
|
||||||
|
"#2A778E",
|
||||||
|
"#2A788E",
|
||||||
|
"#29798E",
|
||||||
|
"#297A8E",
|
||||||
|
"#297B8E",
|
||||||
|
"#287C8E",
|
||||||
|
"#287D8E",
|
||||||
|
"#277E8E",
|
||||||
|
"#277F8E",
|
||||||
|
"#27808E",
|
||||||
|
"#26818E",
|
||||||
|
"#26828E",
|
||||||
|
"#26828E",
|
||||||
|
"#25838E",
|
||||||
|
"#25848E",
|
||||||
|
"#25858E",
|
||||||
|
"#24868E",
|
||||||
|
"#24878E",
|
||||||
|
"#23888E",
|
||||||
|
"#23898E",
|
||||||
|
"#238A8D",
|
||||||
|
"#228B8D",
|
||||||
|
"#228C8D",
|
||||||
|
"#228D8D",
|
||||||
|
"#218E8D",
|
||||||
|
"#218F8D",
|
||||||
|
"#21908D",
|
||||||
|
"#21918C",
|
||||||
|
"#20928C",
|
||||||
|
"#20928C",
|
||||||
|
"#20938C",
|
||||||
|
"#1F948C",
|
||||||
|
"#1F958B",
|
||||||
|
"#1F968B",
|
||||||
|
"#1F978B",
|
||||||
|
"#1F988B",
|
||||||
|
"#1F998A",
|
||||||
|
"#1F9A8A",
|
||||||
|
"#1E9B8A",
|
||||||
|
"#1E9C89",
|
||||||
|
"#1E9D89",
|
||||||
|
"#1F9E89",
|
||||||
|
"#1F9F88",
|
||||||
|
"#1FA088",
|
||||||
|
"#1FA188",
|
||||||
|
"#1FA187",
|
||||||
|
"#1FA287",
|
||||||
|
"#20A386",
|
||||||
|
"#20A486",
|
||||||
|
"#21A585",
|
||||||
|
"#21A685",
|
||||||
|
"#22A785",
|
||||||
|
"#22A884",
|
||||||
|
"#23A983",
|
||||||
|
"#24AA83",
|
||||||
|
"#25AB82",
|
||||||
|
"#25AC82",
|
||||||
|
"#26AD81",
|
||||||
|
"#27AD81",
|
||||||
|
"#28AE80",
|
||||||
|
"#29AF7F",
|
||||||
|
"#2AB07F",
|
||||||
|
"#2CB17E",
|
||||||
|
"#2DB27D",
|
||||||
|
"#2EB37C",
|
||||||
|
"#2FB47C",
|
||||||
|
"#31B57B",
|
||||||
|
"#32B67A",
|
||||||
|
"#34B679",
|
||||||
|
"#35B779",
|
||||||
|
"#37B878",
|
||||||
|
"#38B977",
|
||||||
|
"#3ABA76",
|
||||||
|
"#3BBB75",
|
||||||
|
"#3DBC74",
|
||||||
|
"#3FBC73",
|
||||||
|
"#40BD72",
|
||||||
|
"#42BE71",
|
||||||
|
"#44BF70",
|
||||||
|
"#46C06F",
|
||||||
|
"#48C16E",
|
||||||
|
"#4AC16D",
|
||||||
|
"#4CC26C",
|
||||||
|
"#4EC36B",
|
||||||
|
"#50C46A",
|
||||||
|
"#52C569",
|
||||||
|
"#54C568",
|
||||||
|
"#56C667",
|
||||||
|
"#58C765",
|
||||||
|
"#5AC864",
|
||||||
|
"#5CC863",
|
||||||
|
"#5EC962",
|
||||||
|
"#60CA60",
|
||||||
|
"#63CB5F",
|
||||||
|
"#65CB5E",
|
||||||
|
"#67CC5C",
|
||||||
|
"#69CD5B",
|
||||||
|
"#6CCD5A",
|
||||||
|
"#6ECE58",
|
||||||
|
"#70CF57",
|
||||||
|
"#73D056",
|
||||||
|
"#75D054",
|
||||||
|
"#77D153",
|
||||||
|
"#7AD151",
|
||||||
|
"#7CD250",
|
||||||
|
"#7FD34E",
|
||||||
|
"#81D34D",
|
||||||
|
"#84D44B",
|
||||||
|
"#86D549",
|
||||||
|
"#89D548",
|
||||||
|
"#8BD646",
|
||||||
|
"#8ED645",
|
||||||
|
"#90D743",
|
||||||
|
"#93D741",
|
||||||
|
"#95D840",
|
||||||
|
"#98D83E",
|
||||||
|
"#9BD93C",
|
||||||
|
"#9DD93B",
|
||||||
|
"#A0DA39",
|
||||||
|
"#A2DA37",
|
||||||
|
"#A5DB36",
|
||||||
|
"#A8DB34",
|
||||||
|
"#AADC32",
|
||||||
|
"#ADDC30",
|
||||||
|
"#B0DD2F",
|
||||||
|
"#B2DD2D",
|
||||||
|
"#B5DE2B",
|
||||||
|
"#B8DE29",
|
||||||
|
"#BADE28",
|
||||||
|
"#BDDF26",
|
||||||
|
"#C0DF25",
|
||||||
|
"#C2DF23",
|
||||||
|
"#C5E021",
|
||||||
|
"#C8E020",
|
||||||
|
"#CAE11F",
|
||||||
|
"#CDE11D",
|
||||||
|
"#D0E11C",
|
||||||
|
"#D2E21B",
|
||||||
|
"#D5E21A",
|
||||||
|
"#D8E219",
|
||||||
|
"#DAE319",
|
||||||
|
"#DDE318",
|
||||||
|
"#DFE318",
|
||||||
|
"#E2E418",
|
||||||
|
"#E5E419",
|
||||||
|
"#E7E419",
|
||||||
|
"#EAE51A",
|
||||||
|
"#ECE51B",
|
||||||
|
"#EFE51C",
|
||||||
|
"#F1E51D",
|
||||||
|
"#F4E61E",
|
||||||
|
"#F6E620",
|
||||||
|
"#F8E621",
|
||||||
|
"#FBE723",
|
||||||
|
"#FDE725"
|
||||||
|
]
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
#include <rtltcp_client.h>
|
#include <rtltcp_client.h>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <core.h>
|
#include <core.h>
|
||||||
|
#include <options.h>
|
||||||
#include <gui/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())
|
||||||
@ -17,6 +18,34 @@ SDRPP_MOD_INFO {
|
|||||||
/* Max instances */ 1
|
/* Max instances */ 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ConfigManager config;
|
||||||
|
|
||||||
|
const double sampleRates[] = {
|
||||||
|
250000,
|
||||||
|
1024000,
|
||||||
|
1536000,
|
||||||
|
1792000,
|
||||||
|
1920000,
|
||||||
|
2048000,
|
||||||
|
2160000,
|
||||||
|
2560000,
|
||||||
|
2880000,
|
||||||
|
3200000
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* sampleRatesTxt[] = {
|
||||||
|
"250KHz",
|
||||||
|
"1.024MHz",
|
||||||
|
"1.536MHz",
|
||||||
|
"1.792MHz",
|
||||||
|
"1.92MHz",
|
||||||
|
"2.048MHz",
|
||||||
|
"2.16MHz",
|
||||||
|
"2.56MHz",
|
||||||
|
"2.88MHz",
|
||||||
|
"3.2MHz"
|
||||||
|
};
|
||||||
|
|
||||||
class RTLTCPSourceModule : public ModuleManager::Instance {
|
class RTLTCPSourceModule : public ModuleManager::Instance {
|
||||||
public:
|
public:
|
||||||
RTLTCPSourceModule(std::string name) {
|
RTLTCPSourceModule(std::string name) {
|
||||||
@ -24,6 +53,24 @@ public:
|
|||||||
|
|
||||||
sampleRate = 2560000.0;
|
sampleRate = 2560000.0;
|
||||||
|
|
||||||
|
int srCount = sizeof(sampleRatesTxt) / sizeof(char*);
|
||||||
|
for (int i = 0; i < srCount; i++) {
|
||||||
|
srTxt += sampleRatesTxt[i];
|
||||||
|
srTxt += '\0';
|
||||||
|
}
|
||||||
|
srId = 7;
|
||||||
|
|
||||||
|
config.aquire();
|
||||||
|
std::string hostStr = config.conf["host"];
|
||||||
|
port = config.conf["port"];
|
||||||
|
directSamplingMode = config.conf["directSamplingMode"];
|
||||||
|
rtlAGC = config.conf["rtlAGC"];
|
||||||
|
tunerAGC = config.conf["tunerAGC"];
|
||||||
|
gain = config.conf["gainIndex"];
|
||||||
|
hostStr = hostStr.substr(0, 1023);
|
||||||
|
strcpy(ip, hostStr.c_str());
|
||||||
|
config.release();
|
||||||
|
|
||||||
handler.ctx = this;
|
handler.ctx = this;
|
||||||
handler.selectHandler = menuSelected;
|
handler.selectHandler = menuSelected;
|
||||||
handler.deselectHandler = menuDeselected;
|
handler.deselectHandler = menuDeselected;
|
||||||
@ -72,12 +119,13 @@ private:
|
|||||||
spdlog::error("Could not connect to {0}:{1}", _this->ip, _this->port);
|
spdlog::error("Could not connect to {0}:{1}", _this->ip, _this->port);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
spdlog::warn("Setting sample rate to {0}", _this->sampleRate);
|
||||||
_this->client.setFrequency(_this->freq);
|
_this->client.setFrequency(_this->freq);
|
||||||
_this->client.setSampleRate(_this->sampleRate);
|
_this->client.setSampleRate(_this->sampleRate);
|
||||||
_this->client.setGainIndex(_this->gain);
|
|
||||||
_this->client.setGainMode(!_this->tunerAGC);
|
_this->client.setGainMode(!_this->tunerAGC);
|
||||||
_this->client.setDirectSampling(_this->directSamplingMode);
|
_this->client.setDirectSampling(_this->directSamplingMode);
|
||||||
_this->client.setAGCMode(_this->rtlAGC);
|
_this->client.setAGCMode(_this->rtlAGC);
|
||||||
|
_this->client.setGainIndex(_this->gain);
|
||||||
_this->running = true;
|
_this->running = true;
|
||||||
_this->workerThread = std::thread(worker, _this);
|
_this->workerThread = std::thread(worker, _this);
|
||||||
spdlog::info("RTLTCPSourceModule '{0}': Start!", _this->name);
|
spdlog::info("RTLTCPSourceModule '{0}': Start!", _this->name);
|
||||||
@ -110,22 +158,36 @@ private:
|
|||||||
float menuWidth = ImGui::GetContentRegionAvailWidth();
|
float menuWidth = ImGui::GetContentRegionAvailWidth();
|
||||||
float portWidth = ImGui::CalcTextSize("00000").x + 20;
|
float portWidth = ImGui::CalcTextSize("00000").x + 20;
|
||||||
|
|
||||||
|
if (_this->running) { style::beginDisabled(); }
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(menuWidth - portWidth);
|
ImGui::SetNextItemWidth(menuWidth - portWidth);
|
||||||
ImGui::InputText(CONCAT("##_ip_select_", _this->name), _this->ip, 1024);
|
ImGui::InputText(CONCAT("##_ip_select_", _this->name), _this->ip, 1024);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(portWidth);
|
ImGui::SetNextItemWidth(portWidth);
|
||||||
ImGui::InputInt(CONCAT("##_port_select_", _this->name), &_this->port, 0);
|
ImGui::InputInt(CONCAT("##_port_select_", _this->name), &_this->port, 0);
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(menuWidth);
|
||||||
|
if (ImGui::Combo(CONCAT("##_rtltcp_sr_", _this->name), &_this->srId, _this->srTxt.c_str())) {
|
||||||
|
_this->sampleRate = sampleRates[_this->srId];
|
||||||
|
core::setInputSampleRate(_this->sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_this->running) { style::endDisabled(); }
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(ImGui::CalcTextSize("OOOOOOOOOO").x);
|
ImGui::SetNextItemWidth(ImGui::CalcTextSize("OOOOOOOOOO").x);
|
||||||
if (ImGui::Combo("Direct sampling", &_this->directSamplingMode, "Disabled\0I branch\0Q branch\0")) {
|
if (ImGui::Combo(CONCAT("Direct Sampling##_rtltcp_ds_", _this->name), &_this->directSamplingMode, "Disabled\0I branch\0Q branch\0")) {
|
||||||
if (_this->running) {
|
if (_this->running) {
|
||||||
_this->client.setDirectSampling(_this->directSamplingMode);
|
_this->client.setDirectSampling(_this->directSamplingMode);
|
||||||
|
_this->client.setGainIndex(_this->gain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Checkbox("RTL AGC", &_this->rtlAGC)) {
|
if (ImGui::Checkbox("RTL AGC", &_this->rtlAGC)) {
|
||||||
if (_this->running) {
|
if (_this->running) {
|
||||||
_this->client.setAGCMode(_this->rtlAGC);
|
_this->client.setAGCMode(_this->rtlAGC);
|
||||||
|
if (!_this->rtlAGC) {
|
||||||
|
_this->client.setGainIndex(_this->gain);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,18 +212,17 @@ private:
|
|||||||
|
|
||||||
static void worker(void* ctx) {
|
static void worker(void* ctx) {
|
||||||
RTLTCPSourceModule* _this = (RTLTCPSourceModule*)ctx;
|
RTLTCPSourceModule* _this = (RTLTCPSourceModule*)ctx;
|
||||||
int blockSize = _this->sampleRate / 200.0;
|
int blockSize = _this->sampleRate / 200.0f;
|
||||||
uint8_t* inBuf = new uint8_t[blockSize * 2];
|
uint8_t* inBuf = new uint8_t[blockSize * 2];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Read samples here
|
// Read samples here
|
||||||
_this->client.receiveData(inBuf, blockSize * 2);
|
_this->client.receiveData(inBuf, blockSize * 2);
|
||||||
if (_this->stream.aquire() < 0) { break; }
|
|
||||||
for (int i = 0; i < blockSize; i++) {
|
for (int i = 0; i < blockSize; i++) {
|
||||||
_this->stream.data[i].q = ((double)inBuf[i * 2] - 128.0) / 128.0;
|
_this->stream.writeBuf[i].q = ((double)inBuf[i * 2] - 128.0) / 128.0;
|
||||||
_this->stream.data[i].i = ((double)inBuf[(i * 2) + 1] - 128.0) / 128.0;
|
_this->stream.writeBuf[i].i = ((double)inBuf[(i * 2) + 1] - 128.0) / 128.0;
|
||||||
}
|
}
|
||||||
_this->stream.write(blockSize);
|
if (!_this->stream.swap(blockSize)) { break; };
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] inBuf;
|
delete[] inBuf;
|
||||||
@ -182,10 +243,22 @@ private:
|
|||||||
bool rtlAGC = false;
|
bool rtlAGC = false;
|
||||||
bool tunerAGC = false;
|
bool tunerAGC = false;
|
||||||
int directSamplingMode = 0;
|
int directSamplingMode = 0;
|
||||||
|
int srId = 0;
|
||||||
|
|
||||||
|
std::string srTxt = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
MOD_EXPORT void _INIT_() {
|
||||||
// Do your one time init here
|
config.setPath(options::opts.root + "/rtl_tcp_config.json");
|
||||||
|
json defConf;
|
||||||
|
defConf["host"] = "localhost";
|
||||||
|
defConf["port"] = 1234;
|
||||||
|
defConf["directSamplingMode"] = 0;
|
||||||
|
defConf["rtlAGC"] = false;
|
||||||
|
defConf["tunerAGC"] = false;
|
||||||
|
defConf["gainIndex"] = 0;
|
||||||
|
config.load(defConf);
|
||||||
|
config.enableAutoSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
||||||
@ -197,5 +270,6 @@ MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MOD_EXPORT void _END_() {
|
MOD_EXPORT void _END_() {
|
||||||
// Do your one shutdown here
|
config.disableAutoSave();
|
||||||
|
config.save();
|
||||||
}
|
}
|
@ -43,6 +43,9 @@ public:
|
|||||||
struct addrinfo *ptr = NULL;
|
struct addrinfo *ptr = NULL;
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
|
|
||||||
|
WSADATA wsaData;
|
||||||
|
WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||||
|
|
||||||
ZeroMemory( &hints, sizeof(hints) );
|
ZeroMemory( &hints, sizeof(hints) );
|
||||||
hints.ai_family = AF_UNSPEC;
|
hints.ai_family = AF_UNSPEC;
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
@ -54,7 +57,7 @@ public:
|
|||||||
int iResult = getaddrinfo(host, buf, &hints, &result);
|
int iResult = getaddrinfo(host, buf, &hints, &result);
|
||||||
if (iResult != 0) {
|
if (iResult != 0) {
|
||||||
// TODO: log error
|
// TODO: log error
|
||||||
printf("A");
|
printf("\n%s\n", gai_strerror(iResult));
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -11,20 +11,21 @@
|
|||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
|
|
||||||
#define ADC_RATE 128000000
|
#define ADC_RATE 64000000
|
||||||
#define XFER_TIMEOUT 5000
|
#define XFER_TIMEOUT 5000
|
||||||
|
|
||||||
#define SEL0 (8) // SEL0 GPIO26
|
#define SEL0 (8) // SEL0 GPIO26
|
||||||
#define SEL1 (16) // SEL1 GPIO27
|
#define SEL1 (16) // SEL1 GPIO27
|
||||||
|
|
||||||
MOD_INFO {
|
SDRPP_MOD_INFO {
|
||||||
/* Name: */ "rx888_source",
|
/* Name: */ "rx888_source",
|
||||||
/* Description: */ "RX888 input module for SDR++",
|
/* Description: */ "RX888 source module for SDR++",
|
||||||
/* Author: */ "Ryzerth",
|
/* Author: */ "Ryzerth",
|
||||||
/* Version: */ "0.1.0"
|
/* Version: */ 0, 1, 0,
|
||||||
|
/* Max instances */ 1
|
||||||
};
|
};
|
||||||
|
|
||||||
class RX888SourceModule {
|
class RX888SourceModule : public ModuleManager::Instance {
|
||||||
public:
|
public:
|
||||||
RX888SourceModule(std::string name) {
|
RX888SourceModule(std::string name) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
@ -58,6 +59,18 @@ public:
|
|||||||
spdlog::info("RX888SourceModule '{0}': Instance deleted!", name);
|
spdlog::info("RX888SourceModule '{0}': Instance deleted!", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void enable() {
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable() {
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static void menuSelected(void* ctx) {
|
static void menuSelected(void* ctx) {
|
||||||
@ -125,7 +138,7 @@ private:
|
|||||||
|
|
||||||
static void _usbWorker(RX888SourceModule* _this) {
|
static void _usbWorker(RX888SourceModule* _this) {
|
||||||
// Calculate hardware block siz
|
// Calculate hardware block siz
|
||||||
int realBlockSize = ADC_RATE / 200;
|
int realBlockSize = ADC_RATE / 100;
|
||||||
int i;
|
int i;
|
||||||
for (i = 1; i < realBlockSize; i = (i << 1));
|
for (i = 1; i < realBlockSize; i = (i << 1));
|
||||||
realBlockSize = (i >> 1);
|
realBlockSize = (i >> 1);
|
||||||
@ -170,9 +183,8 @@ private:
|
|||||||
// Check if the incomming data is bulk I/Q and end transfer
|
// Check if the incomming data is bulk I/Q and end transfer
|
||||||
if (EndPt->Attributes == 2) {
|
if (EndPt->Attributes == 2) {
|
||||||
if (EndPt->FinishDataXfer((PUCHAR)buffer, rLen, &inOvLap, context)) {
|
if (EndPt->FinishDataXfer((PUCHAR)buffer, rLen, &inOvLap, context)) {
|
||||||
if (_this->realStream.aquire() < 0) { break; }
|
memcpy(_this->realStream.writeBuf, buffer, rLen);
|
||||||
memcpy(_this->realStream.data, buffer, rLen);
|
_this->realStream.swap(rLen / 2);
|
||||||
_this->realStream.write(rLen / 2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +208,7 @@ private:
|
|||||||
|
|
||||||
while (count >= 0) {
|
while (count >= 0) {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
iqbuffer[i].q = (float)_this->realStream.data[i] / 32768.0f;
|
iqbuffer[i].q = (float)_this->realStream.readBuf[i] / 32768.0f;
|
||||||
}
|
}
|
||||||
_this->realStream.flush();
|
_this->realStream.flush();
|
||||||
|
|
||||||
@ -205,21 +217,20 @@ private:
|
|||||||
lv_32fc_t phaseDelta = lv_cmake(std::cos(delta), std::sin(delta));
|
lv_32fc_t phaseDelta = lv_cmake(std::cos(delta), std::sin(delta));
|
||||||
|
|
||||||
// Apply translation
|
// Apply translation
|
||||||
if (_this->stream.aquire() < 0) { break; }
|
volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)_this->stream.writeBuf, (lv_32fc_t*)iqbuffer, phaseDelta, &phase, count);
|
||||||
volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)_this->stream.data, (lv_32fc_t*)iqbuffer, phaseDelta, &phase, count);
|
|
||||||
|
|
||||||
// Decimate
|
// Decimate
|
||||||
blockSize = count;
|
blockSize = count;
|
||||||
for (int d = 0; d < (_this->decimation - 1); d++) {
|
for (int d = 0; d < (_this->decimation - 1); d++) {
|
||||||
blockSize = (blockSize >> 1);
|
blockSize = (blockSize >> 1);
|
||||||
for (int i = 0; i < blockSize; i++) {
|
for (int i = 0; i < blockSize; i++) {
|
||||||
_this->stream.data[i].i = (_this->stream.data[i*2].i + _this->stream.data[(i*2)+1].i) * 0.5f;
|
_this->stream.writeBuf[i].i = (_this->stream.writeBuf[i*2].i + _this->stream.writeBuf[(i*2)+1].i) * 0.5f;
|
||||||
_this->stream.data[i].q = (_this->stream.data[i*2].q + _this->stream.data[(i*2)+1].q) * 0.5f;
|
_this->stream.writeBuf[i].q = (_this->stream.writeBuf[i*2].q + _this->stream.writeBuf[(i*2)+1].q) * 0.5f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to output stream
|
// Write to output stream
|
||||||
_this->stream.write(blockSize);
|
_this->stream.swap(blockSize);
|
||||||
|
|
||||||
// Read from real stream
|
// Read from real stream
|
||||||
count = _this->realStream.read();
|
count = _this->realStream.read();
|
||||||
@ -242,20 +253,20 @@ private:
|
|||||||
double sampleRate;
|
double sampleRate;
|
||||||
int decimation;
|
int decimation;
|
||||||
bool running = false;
|
bool running = false;
|
||||||
|
bool enabled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
MOD_EXPORT void _INIT_() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MOD_EXPORT void* _CREATE_INSTANCE_(std::string name) {
|
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
||||||
return new RX888SourceModule(name);
|
return new RX888SourceModule(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
|
||||||
delete (RX888SourceModule*)instance;
|
delete (RX888SourceModule*)instance;
|
||||||
}
|
}
|
||||||
|
MOD_EXPORT void _END_() {
|
||||||
MOD_EXPORT void _STOP_() {
|
|
||||||
|
|
||||||
}
|
}
|
@ -19,6 +19,8 @@ if (MSVC)
|
|||||||
|
|
||||||
# Misc headers
|
# Misc headers
|
||||||
target_include_directories(sdrpp_core PUBLIC "C:/Program Files/PothosSDR/include/")
|
target_include_directories(sdrpp_core PUBLIC "C:/Program Files/PothosSDR/include/")
|
||||||
|
|
||||||
|
target_link_libraries(sdrpp_core PUBLIC SoapySDR)
|
||||||
else (MSVC)
|
else (MSVC)
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
|
#include <gui/widgets/stepped_slider.h>
|
||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <SoapySDR/Device.hpp>
|
#include <SoapySDR/Device.hpp>
|
||||||
#include <SoapySDR/Modules.hpp>
|
#include <SoapySDR/Modules.hpp>
|
||||||
@ -67,6 +68,14 @@ public:
|
|||||||
bool isEnabled() {
|
bool isEnabled() {
|
||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string to_string_with_precision(const T a_value, const int n = 6) {
|
||||||
|
std::ostringstream out;
|
||||||
|
out.precision(n);
|
||||||
|
out << std::fixed << a_value;
|
||||||
|
return out.str();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void refresh() {
|
void refresh() {
|
||||||
@ -79,6 +88,21 @@ private:
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float selectBwBySr(double samplerate) {
|
||||||
|
float cur = bandwidthList[1];
|
||||||
|
std::vector<float> bwListReversed = bandwidthList;
|
||||||
|
std::reverse(bwListReversed.begin(), bwListReversed.end());
|
||||||
|
for(auto bw : bwListReversed) {
|
||||||
|
if(bw >= samplerate) {
|
||||||
|
cur = bw;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spdlog::info("Bandwidth for samplerate {0} is {1}", samplerate, cur);
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
void selectSampleRate(double samplerate) {
|
void selectSampleRate(double samplerate) {
|
||||||
spdlog::info("Setting sample rate to {0}", samplerate);
|
spdlog::info("Setting sample rate to {0}", samplerate);
|
||||||
@ -131,19 +155,42 @@ private:
|
|||||||
gainList = dev->listGains(SOAPY_SDR_RX, channelId);
|
gainList = dev->listGains(SOAPY_SDR_RX, channelId);
|
||||||
delete[] uiGains;
|
delete[] uiGains;
|
||||||
uiGains = new float[gainList.size()];
|
uiGains = new float[gainList.size()];
|
||||||
|
gainRanges.clear();
|
||||||
|
|
||||||
for (auto gain : gainList) {
|
for (auto gain : gainList) {
|
||||||
gainRanges.push_back(dev->getGainRange(SOAPY_SDR_RX, channelId, gain));
|
gainRanges.push_back(dev->getGainRange(SOAPY_SDR_RX, channelId, gain));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SoapySDR::RangeList bandwidthRange = dev->getBandwidthRange(SOAPY_SDR_RX, channelId);
|
||||||
|
|
||||||
|
txtBwList = "";
|
||||||
|
bandwidthList.clear();
|
||||||
|
bandwidthList.push_back(-1);
|
||||||
|
txtBwList += "Auto";
|
||||||
|
txtBwList += '\0';
|
||||||
|
|
||||||
|
for(auto bwr : bandwidthRange) {
|
||||||
|
float bw = bwr.minimum();
|
||||||
|
bandwidthList.push_back(bw);
|
||||||
|
if (bw > 1.0e3 && bw <= 1.0e6) {
|
||||||
|
txtBwList += to_string_with_precision((bw / 1.0e3), 2) + " kHz";
|
||||||
|
} else if (bw > 1.0e6) {
|
||||||
|
txtBwList += to_string_with_precision((bw / 1.0e6), 2) + " MHz";
|
||||||
|
} else {
|
||||||
|
txtBwList += to_string_with_precision(bw, 0);
|
||||||
|
}
|
||||||
|
txtBwList += '\0';
|
||||||
|
}
|
||||||
|
|
||||||
sampleRates = dev->listSampleRates(SOAPY_SDR_RX, channelId);
|
sampleRates = dev->listSampleRates(SOAPY_SDR_RX, channelId);
|
||||||
txtSrList = "";
|
txtSrList = "";
|
||||||
for (double sr : sampleRates) {
|
for (double sr : sampleRates) {
|
||||||
if (sr > 1.0e3 && sr <= 1.0e6) {
|
if (sr > 1.0e3 && sr <= 1.0e6) {
|
||||||
txtSrList += std::to_string((sr / 1.0e3)) + " kHz";
|
txtSrList += to_string_with_precision((sr / 1.0e3), 2) + " kHz";
|
||||||
} else if (sr > 1.0e6) {
|
} else if (sr > 1.0e6) {
|
||||||
txtSrList += std::to_string((sr / 1.0e6)) + " MHz";
|
txtSrList += to_string_with_precision((sr / 1.0e6), 2) + " MHz";
|
||||||
} else {
|
} else {
|
||||||
txtSrList += std::to_string((int) sr);
|
txtSrList += to_string_with_precision(sr, 0);
|
||||||
}
|
}
|
||||||
txtSrList += '\0';
|
txtSrList += '\0';
|
||||||
}
|
}
|
||||||
@ -164,6 +211,11 @@ private:
|
|||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
if(config.conf["devices"][name].contains("bandwidth")) {
|
||||||
|
uiBandwidthId = config.conf["devices"][name]["bandwidth"];
|
||||||
|
} else if(bandwidthList.size() > 2) {
|
||||||
|
uiBandwidthId = 0;
|
||||||
|
}
|
||||||
if (hasAgc && config.conf["devices"][name].contains("agc")) {
|
if (hasAgc && config.conf["devices"][name].contains("agc")) {
|
||||||
agc = config.conf["devices"][name]["agc"];
|
agc = config.conf["devices"][name]["agc"];
|
||||||
}
|
}
|
||||||
@ -183,6 +235,8 @@ private:
|
|||||||
uiGains[i] = gainRanges[i].minimum();
|
uiGains[i] = gainRanges[i].minimum();
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
if(bandwidthList.size() > 2)
|
||||||
|
uiBandwidthId = 0;
|
||||||
if (hasAgc) {
|
if (hasAgc) {
|
||||||
agc = false;
|
agc = false;
|
||||||
}
|
}
|
||||||
@ -200,6 +254,8 @@ private:
|
|||||||
conf["gains"][gain] = uiGains[i];
|
conf["gains"][gain] = uiGains[i];
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
if(bandwidthList.size() > 2)
|
||||||
|
conf["bandwidth"] = uiBandwidthId;
|
||||||
if (hasAgc) {
|
if (hasAgc) {
|
||||||
conf["agc"] = agc;
|
conf["agc"] = agc;
|
||||||
}
|
}
|
||||||
@ -228,16 +284,23 @@ private:
|
|||||||
|
|
||||||
_this->dev->setSampleRate(SOAPY_SDR_RX, _this->channelId, _this->sampleRate);
|
_this->dev->setSampleRate(SOAPY_SDR_RX, _this->channelId, _this->sampleRate);
|
||||||
|
|
||||||
|
if(_this->bandwidthList.size() > 2) {
|
||||||
|
if(_this->bandwidthList[_this->uiBandwidthId] == -1)
|
||||||
|
_this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->selectBwBySr(_this->sampleRates[_this->srId]));
|
||||||
|
else
|
||||||
|
_this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->bandwidthList[_this->uiBandwidthId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_this->hasAgc) {
|
||||||
|
_this->dev->setGainMode(SOAPY_SDR_RX, _this->channelId, _this->agc);
|
||||||
|
}
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto gain : _this->gainList) {
|
for (auto gain : _this->gainList) {
|
||||||
_this->dev->setGain(SOAPY_SDR_RX, _this->channelId, gain, _this->uiGains[i]);
|
_this->dev->setGain(SOAPY_SDR_RX, _this->channelId, gain, _this->uiGains[i]);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_this->hasAgc) {
|
|
||||||
_this->dev->setGainMode(SOAPY_SDR_RX, _this->channelId, _this->agc);
|
|
||||||
}
|
|
||||||
|
|
||||||
_this->dev->setFrequency(SOAPY_SDR_RX, _this->channelId, _this->freq);
|
_this->dev->setFrequency(SOAPY_SDR_RX, _this->channelId, _this->freq);
|
||||||
|
|
||||||
_this->devStream = _this->dev->setupStream(SOAPY_SDR_RX, "CF32");
|
_this->devStream = _this->dev->setupStream(SOAPY_SDR_RX, "CF32");
|
||||||
@ -291,6 +354,8 @@ private:
|
|||||||
|
|
||||||
if (ImGui::Combo(CONCAT("##_sr_select_", _this->name), &_this->srId, _this->txtSrList.c_str())) {
|
if (ImGui::Combo(CONCAT("##_sr_select_", _this->name), &_this->srId, _this->txtSrList.c_str())) {
|
||||||
_this->selectSampleRate(_this->sampleRates[_this->srId]);
|
_this->selectSampleRate(_this->sampleRates[_this->srId]);
|
||||||
|
if(_this->bandwidthList.size() > 2 && _this->running && _this->bandwidthList[_this->uiBandwidthId] == -1)
|
||||||
|
_this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->selectBwBySr(_this->sampleRates[_this->srId]));
|
||||||
_this->saveCurrent();
|
_this->saveCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,8 +399,14 @@ private:
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetCursorPosX(gainNameLen);
|
ImGui::SetCursorPosX(gainNameLen);
|
||||||
ImGui::SetNextItemWidth(menuWidth - gainNameLen);
|
ImGui::SetNextItemWidth(menuWidth - gainNameLen);
|
||||||
if (ImGui::SliderFloat((gain + std::string("##_gain_sel_") + _this->name).c_str(), &_this->uiGains[i],
|
float step = _this->gainRanges[i].step();
|
||||||
_this->gainRanges[i].minimum(), _this->gainRanges[i].maximum())) {
|
bool res;
|
||||||
|
if(step == 0.0f) {
|
||||||
|
res = ImGui::SliderFloat((std::string("##_gain_sel_") + _this->name + gain).c_str(), &_this->uiGains[i], _this->gainRanges[i].minimum(), _this->gainRanges[i].maximum());
|
||||||
|
} else {
|
||||||
|
res = ImGui::SliderFloatWithSteps((std::string("##_gain_sel_") + _this->name + gain).c_str(), &_this->uiGains[i], _this->gainRanges[i].minimum(), _this->gainRanges[i].maximum(), step);
|
||||||
|
}
|
||||||
|
if(res) {
|
||||||
if (_this->running) {
|
if (_this->running) {
|
||||||
_this->dev->setGain(SOAPY_SDR_RX, _this->channelId, gain, _this->uiGains[i]);
|
_this->dev->setGain(SOAPY_SDR_RX, _this->channelId, gain, _this->uiGains[i]);
|
||||||
}
|
}
|
||||||
@ -343,6 +414,23 @@ private:
|
|||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
if(_this->bandwidthList.size() > 2) {
|
||||||
|
float bwLen = ImGui::CalcTextSize("Bandwidth").x + 5.0f;
|
||||||
|
ImGui::Text("Bandwidth");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetCursorPosX(bwLen);
|
||||||
|
ImGui::SetNextItemWidth(menuWidth - bwLen);
|
||||||
|
|
||||||
|
if (ImGui::Combo(CONCAT("##_bw_select_", _this->name), &_this->uiBandwidthId, _this->txtBwList.c_str())) {
|
||||||
|
if(_this->running) {
|
||||||
|
if(_this->bandwidthList[_this->uiBandwidthId] == -1)
|
||||||
|
_this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->selectBwBySr(_this->sampleRates[_this->srId]));
|
||||||
|
else
|
||||||
|
_this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->bandwidthList[_this->uiBandwidthId]);
|
||||||
|
}
|
||||||
|
_this->saveCurrent();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _worker(SoapyModule* _this) {
|
static void _worker(SoapyModule* _this) {
|
||||||
@ -351,12 +439,11 @@ private:
|
|||||||
long long timeMs = 0;
|
long long timeMs = 0;
|
||||||
|
|
||||||
while (_this->running) {
|
while (_this->running) {
|
||||||
if (_this->stream.aquire() < 0) { break; }
|
int res = _this->dev->readStream(_this->devStream, (void**)&_this->stream.writeBuf, blockSize, flags, timeMs);
|
||||||
int res = _this->dev->readStream(_this->devStream, (void**)&_this->stream.data, blockSize, flags, timeMs);
|
|
||||||
if (res < 1) {
|
if (res < 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_this->stream.write(res);
|
if (!_this->stream.swap(res)) { return; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,6 +471,9 @@ private:
|
|||||||
int channelId = 0;
|
int channelId = 0;
|
||||||
std::vector<std::string> gainList;
|
std::vector<std::string> gainList;
|
||||||
std::vector<SoapySDR::Range> gainRanges;
|
std::vector<SoapySDR::Range> gainRanges;
|
||||||
|
int uiBandwidthId = 0;
|
||||||
|
std::vector<float> bandwidthList;
|
||||||
|
std::string txtBwList;
|
||||||
};
|
};
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
MOD_EXPORT void _INIT_() {
|
||||||
@ -406,4 +496,4 @@ MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
|
|||||||
MOD_EXPORT void _END_() {
|
MOD_EXPORT void _END_() {
|
||||||
config.disableAutoSave();
|
config.disableAutoSave();
|
||||||
config.save();
|
config.save();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include <spyserver_client.h>
|
#include <spyserver_client.h>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <new_module.h>
|
#include <module.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <core.h>
|
#include <core.h>
|
||||||
|
@ -74,7 +74,7 @@ bool SpyServerClient::connectToSpyserver(char* host, int port) {
|
|||||||
unsigned long mode = 1;
|
unsigned long mode = 1;
|
||||||
ioctlsocket(sock, FIONBIO, &mode);
|
ioctlsocket(sock, FIONBIO, &mode);
|
||||||
#else
|
#else
|
||||||
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK)
|
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
connected = true;
|
connected = true;
|
||||||
@ -117,7 +117,7 @@ int SpyServerClient::receive(char* buf, int count) {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return checkError(recv(sock, (char*)buf, count, 0), count);
|
return checkError(recv(sock, (char*)buf, count, 0), count);
|
||||||
#else
|
#else
|
||||||
return checkError(read(sockfd, buf, count));
|
return checkError(read(sockfd, buf, count), count);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user