mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-07-09 10:35:21 +02:00
Compare commits
27 Commits
Author | SHA1 | Date | |
---|---|---|---|
40f1ee5651 | |||
c4b0cb37a6 | |||
cd7dabda51 | |||
139f63ad25 | |||
75800e0ca2 | |||
84da183559 | |||
0144d8e8ce | |||
7ef88f23a8 | |||
c934e41a61 | |||
9dd6c8546d | |||
191f652fc3 | |||
e208511bde | |||
348bf75281 | |||
cbf1d6703e | |||
03c30f202e | |||
25bc9f60ed | |||
2e80882ab5 | |||
4c584847de | |||
2a741932e0 | |||
ff655caf31 | |||
0277232bdb | |||
2e3e2a7dca | |||
271a77e4ce | |||
48e9708d74 | |||
961cd3f133 | |||
2676190d3a | |||
8851735cb8 |
37
.github/workflows/build_all.yml
vendored
37
.github/workflows/build_all.yml
vendored
@ -68,15 +68,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Prepare CMake
|
- name: Prepare CMake
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
run: cmake "$Env:GITHUB_WORKSPACE" "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DCMAKE_BUILD_TYPE=Debug -DCOPY_MSVC_REDISTRIBUTABLES=ON -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
|
run: cmake "$Env:GITHUB_WORKSPACE" "-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake" -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_PERSEUS_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{runner.workspace}}/build
|
working-directory: ${{runner.workspace}}/build
|
||||||
run: cmake --build . --config Debug --verbose
|
run: cmake --build . --config Release --verbose
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
working-directory: ${{runner.workspace}}/build
|
|
||||||
run: ./Debug/min_broken.exe
|
|
||||||
|
|
||||||
- name: Create Archive
|
- name: Create Archive
|
||||||
working-directory: ${{runner.workspace}}
|
working-directory: ${{runner.workspace}}
|
||||||
@ -104,7 +100,7 @@ jobs:
|
|||||||
run: git clone --recursive https://github.com/gnuradio/volk && cd volk && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: git clone --recursive https://github.com/gnuradio/volk && cd volk && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
|
|
||||||
- name: Install SDRplay API
|
- name: Install SDRplay API
|
||||||
run: wget https://www.sdrplay.com/software/SDRplayAPI-macos-installer-universal-3.15.0.pkg && sudo installer -pkg SDRplayAPI-macos-installer-universal-3.15.0.pkg -target /
|
run: wget https://www.sdrplay.com/software/SDRplayAPI-macos-installer-universal-3.14.0.pkg && sudo installer -pkg SDRplayAPI-macos-installer-universal-3.14.0.pkg -target /
|
||||||
|
|
||||||
- name: Install libiio
|
- name: Install libiio
|
||||||
run: wget https://github.com/analogdevicesinc/libiio/archive/refs/tags/v0.25.zip && 7z x v0.25.zip && cd libiio-0.25 && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: wget https://github.com/analogdevicesinc/libiio/archive/refs/tags/v0.25.zip && 7z x v0.25.zip && cd libiio-0.25 && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
@ -155,7 +151,7 @@ jobs:
|
|||||||
run: git clone --recursive https://github.com/gnuradio/volk && cd volk && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: git clone --recursive https://github.com/gnuradio/volk && cd volk && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
|
|
||||||
- name: Install SDRplay API
|
- name: Install SDRplay API
|
||||||
run: wget https://www.sdrplay.com/software/SDRplayAPI-macos-installer-universal-3.15.0.pkg && sudo installer -pkg SDRplayAPI-macos-installer-universal-3.15.0.pkg -target /
|
run: wget https://www.sdrplay.com/software/SDRplayAPI-macos-installer-universal-3.14.0.pkg && sudo installer -pkg SDRplayAPI-macos-installer-universal-3.14.0.pkg -target /
|
||||||
|
|
||||||
- name: Install libiio
|
- name: Install libiio
|
||||||
run: wget https://github.com/analogdevicesinc/libiio/archive/refs/tags/v0.25.zip && 7z x v0.25.zip && cd libiio-0.25 && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
run: wget https://github.com/analogdevicesinc/libiio/archive/refs/tags/v0.25.zip && 7z x v0.25.zip && cd libiio-0.25 && mkdir build && cd build && cmake -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||||
@ -344,28 +340,6 @@ jobs:
|
|||||||
name: sdrpp_ubuntu_mantic_amd64
|
name: sdrpp_ubuntu_mantic_amd64
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
||||||
|
|
||||||
build_ubuntu_noble:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Create Docker Image
|
|
||||||
run: cd $GITHUB_WORKSPACE/docker_builds/ubuntu_noble && docker build . --tag sdrpp_build
|
|
||||||
|
|
||||||
- name: Run Container
|
|
||||||
run: docker run --name build -v $GITHUB_WORKSPACE:/root/SDRPlusPlus --env BUILD_NO="-$GITHUB_RUN_NUMBER" sdrpp_build /root/do_build.sh
|
|
||||||
|
|
||||||
- name: Recover Deb Archive
|
|
||||||
working-directory: ${{runner.workspace}}
|
|
||||||
run: docker cp build:/root/SDRPlusPlus/sdrpp_debian_amd64.deb ./
|
|
||||||
|
|
||||||
- name: Save Deb Archive
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: sdrpp_ubuntu_noble_amd64
|
|
||||||
path: ${{runner.workspace}}/sdrpp_debian_amd64.deb
|
|
||||||
|
|
||||||
build_raspios_bullseye_armhf:
|
build_raspios_bullseye_armhf:
|
||||||
runs-on: ARM
|
runs-on: ARM
|
||||||
|
|
||||||
@ -421,7 +395,7 @@ jobs:
|
|||||||
path: ${{runner.workspace}}/sdrpp.apk
|
path: ${{runner.workspace}}/sdrpp.apk
|
||||||
|
|
||||||
create_full_archive:
|
create_full_archive:
|
||||||
needs: ['build_windows', 'build_macos_intel', 'build_macos_arm', 'build_debian_buster', 'build_debian_bullseye', 'build_debian_bookworm', 'build_debian_sid', 'build_ubuntu_focal', 'build_ubuntu_jammy', 'build_ubuntu_mantic', 'build_ubuntu_noble', 'build_raspios_bullseye_armhf', 'build_android']
|
needs: ['build_windows', 'build_macos_intel', 'build_macos_arm', 'build_debian_buster', 'build_debian_bullseye', 'build_debian_bookworm', 'build_debian_sid', 'build_ubuntu_focal', 'build_ubuntu_jammy', 'build_ubuntu_mantic', 'build_raspios_bullseye_armhf', 'build_android']
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -441,7 +415,6 @@ jobs:
|
|||||||
mv sdrpp_ubuntu_focal_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_focal_amd64.deb &&
|
mv sdrpp_ubuntu_focal_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_focal_amd64.deb &&
|
||||||
mv sdrpp_ubuntu_jammy_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_jammy_amd64.deb &&
|
mv sdrpp_ubuntu_jammy_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_jammy_amd64.deb &&
|
||||||
mv sdrpp_ubuntu_mantic_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_mantic_amd64.deb &&
|
mv sdrpp_ubuntu_mantic_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_mantic_amd64.deb &&
|
||||||
mv sdrpp_ubuntu_noble_amd64/sdrpp_debian_amd64.deb sdrpp_all/sdrpp_ubuntu_noble_amd64.deb &&
|
|
||||||
mv sdrpp_raspios_bullseye_armhf/sdrpp_debian_armhf.deb sdrpp_all/sdrpp_raspios_bullseye_armhf.deb &&
|
mv sdrpp_raspios_bullseye_armhf/sdrpp_debian_armhf.deb sdrpp_all/sdrpp_raspios_bullseye_armhf.deb &&
|
||||||
mv sdrpp_android/sdrpp.apk sdrpp_all/sdrpp.apk
|
mv sdrpp_android/sdrpp.apk sdrpp_all/sdrpp.apk
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ option(OPT_OVERRIDE_STD_FILESYSTEM "Use a local version of std::filesystem on sy
|
|||||||
option(OPT_BUILD_AIRSPY_SOURCE "Build Airspy Source Module (Dependencies: libairspy)" ON)
|
option(OPT_BUILD_AIRSPY_SOURCE "Build Airspy Source Module (Dependencies: libairspy)" ON)
|
||||||
option(OPT_BUILD_AIRSPYHF_SOURCE "Build Airspy HF+ Source Module (Dependencies: libairspyhf)" ON)
|
option(OPT_BUILD_AIRSPYHF_SOURCE "Build Airspy HF+ Source Module (Dependencies: libairspyhf)" ON)
|
||||||
option(OPT_BUILD_AUDIO_SOURCE "Build Audio Source Module (Dependencies: rtaudio)" ON)
|
option(OPT_BUILD_AUDIO_SOURCE "Build Audio Source Module (Dependencies: rtaudio)" ON)
|
||||||
option(OPT_BUILD_BADGESDR_SOURCE "Build BadgeSDR Source Module (Dependencies: libusb)" OFF)
|
|
||||||
option(OPT_BUILD_BLADERF_SOURCE "Build BladeRF Source Module (Dependencies: libbladeRF)" OFF)
|
option(OPT_BUILD_BLADERF_SOURCE "Build BladeRF Source Module (Dependencies: libbladeRF)" OFF)
|
||||||
option(OPT_BUILD_FILE_SOURCE "Wav file source" ON)
|
option(OPT_BUILD_FILE_SOURCE "Wav file source" ON)
|
||||||
option(OPT_BUILD_HACKRF_SOURCE "Build HackRF Source Module (Dependencies: libhackrf)" ON)
|
option(OPT_BUILD_HACKRF_SOURCE "Build HackRF Source Module (Dependencies: libhackrf)" ON)
|
||||||
@ -21,7 +20,6 @@ option(OPT_BUILD_LIMESDR_SOURCE "Build LimeSDR Source Module (Dependencies: libl
|
|||||||
option(OPT_BUILD_NETWORK_SOURCE "Build Network Source Module (no dependencies required)" ON)
|
option(OPT_BUILD_NETWORK_SOURCE "Build Network Source Module (no dependencies required)" ON)
|
||||||
option(OPT_BUILD_PERSEUS_SOURCE "Build Perseus Source Module (Dependencies: libperseus-sdr)" OFF)
|
option(OPT_BUILD_PERSEUS_SOURCE "Build Perseus Source Module (Dependencies: libperseus-sdr)" OFF)
|
||||||
option(OPT_BUILD_PLUTOSDR_SOURCE "Build PlutoSDR Source Module (Dependencies: libiio, libad9361)" ON)
|
option(OPT_BUILD_PLUTOSDR_SOURCE "Build PlutoSDR Source Module (Dependencies: libiio, libad9361)" ON)
|
||||||
option(OPT_BUILD_RFNM_SOURCE "Build RFNM Source Module (Dependencies: librfnm)" OFF)
|
|
||||||
option(OPT_BUILD_RFSPACE_SOURCE "Build RFspace Source Module (no dependencies required)" ON)
|
option(OPT_BUILD_RFSPACE_SOURCE "Build RFspace Source Module (no dependencies required)" ON)
|
||||||
option(OPT_BUILD_RTL_SDR_SOURCE "Build RTL-SDR Source Module (Dependencies: librtlsdr)" ON)
|
option(OPT_BUILD_RTL_SDR_SOURCE "Build RTL-SDR Source Module (Dependencies: librtlsdr)" ON)
|
||||||
option(OPT_BUILD_RTL_TCP_SOURCE "Build RTL-TCP Source Module (no dependencies required)" ON)
|
option(OPT_BUILD_RTL_TCP_SOURCE "Build RTL-TCP Source Module (no dependencies required)" ON)
|
||||||
@ -63,7 +61,6 @@ option(OPT_BUILD_SCHEDULER "Build the scheduler" OFF)
|
|||||||
# Other options
|
# Other options
|
||||||
option(USE_INTERNAL_LIBCORRECT "Use an internal version of libcorrect" ON)
|
option(USE_INTERNAL_LIBCORRECT "Use an internal version of libcorrect" ON)
|
||||||
option(USE_BUNDLE_DEFAULTS "Set the default resource and module directories to the right ones for a MacOS .app" OFF)
|
option(USE_BUNDLE_DEFAULTS "Set the default resource and module directories to the right ones for a MacOS .app" OFF)
|
||||||
option(COPY_MSVC_REDISTRIBUTABLES "Copy over the Visual C++ Redistributable" OFF)
|
|
||||||
|
|
||||||
# Module cmake path
|
# Module cmake path
|
||||||
set(SDRPP_MODULE_CMAKE "${CMAKE_SOURCE_DIR}/sdrpp_module.cmake")
|
set(SDRPP_MODULE_CMAKE "${CMAKE_SOURCE_DIR}/sdrpp_module.cmake")
|
||||||
@ -128,10 +125,6 @@ if (OPT_BUILD_AUDIO_SOURCE)
|
|||||||
add_subdirectory("source_modules/audio_source")
|
add_subdirectory("source_modules/audio_source")
|
||||||
endif (OPT_BUILD_AUDIO_SOURCE)
|
endif (OPT_BUILD_AUDIO_SOURCE)
|
||||||
|
|
||||||
if (OPT_BUILD_BADGESDR_SOURCE)
|
|
||||||
add_subdirectory("source_modules/badgesdr_source")
|
|
||||||
endif (OPT_BUILD_BADGESDR_SOURCE)
|
|
||||||
|
|
||||||
if (OPT_BUILD_BLADERF_SOURCE)
|
if (OPT_BUILD_BLADERF_SOURCE)
|
||||||
add_subdirectory("source_modules/bladerf_source")
|
add_subdirectory("source_modules/bladerf_source")
|
||||||
endif (OPT_BUILD_BLADERF_SOURCE)
|
endif (OPT_BUILD_BLADERF_SOURCE)
|
||||||
@ -164,10 +157,6 @@ if (OPT_BUILD_PLUTOSDR_SOURCE)
|
|||||||
add_subdirectory("source_modules/plutosdr_source")
|
add_subdirectory("source_modules/plutosdr_source")
|
||||||
endif (OPT_BUILD_PLUTOSDR_SOURCE)
|
endif (OPT_BUILD_PLUTOSDR_SOURCE)
|
||||||
|
|
||||||
if (OPT_BUILD_RFNM_SOURCE)
|
|
||||||
add_subdirectory("source_modules/rfnm_source")
|
|
||||||
endif (OPT_BUILD_RFNM_SOURCE)
|
|
||||||
|
|
||||||
if (OPT_BUILD_RFSPACE_SOURCE)
|
if (OPT_BUILD_RFSPACE_SOURCE)
|
||||||
add_subdirectory("source_modules/rfspace_source")
|
add_subdirectory("source_modules/rfspace_source")
|
||||||
endif (OPT_BUILD_RFSPACE_SOURCE)
|
endif (OPT_BUILD_RFSPACE_SOURCE)
|
||||||
@ -300,7 +289,6 @@ endif (OPT_BUILD_SCHEDULER)
|
|||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
add_executable(sdrpp "src/main.cpp" "win32/resources.rc")
|
add_executable(sdrpp "src/main.cpp" "win32/resources.rc")
|
||||||
add_executable(min_broken "min_broken/main.cpp" "win32/resources.rc")
|
|
||||||
else ()
|
else ()
|
||||||
add_executable(sdrpp "src/main.cpp")
|
add_executable(sdrpp "src/main.cpp")
|
||||||
endif ()
|
endif ()
|
||||||
@ -309,29 +297,14 @@ target_link_libraries(sdrpp PRIVATE sdrpp_core)
|
|||||||
|
|
||||||
# Compiler arguments
|
# Compiler arguments
|
||||||
target_compile_options(sdrpp PRIVATE ${SDRPP_COMPILER_FLAGS})
|
target_compile_options(sdrpp PRIVATE ${SDRPP_COMPILER_FLAGS})
|
||||||
target_compile_options(min_broken PRIVATE ${SDRPP_COMPILER_FLAGS})
|
|
||||||
|
|
||||||
# Copy dynamic libs over
|
# Copy dynamic libs over
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
add_custom_target(do_always ALL xcopy /s \"$<TARGET_FILE_DIR:sdrpp_core>\\*.dll\" \"$<TARGET_FILE_DIR:sdrpp>\" /Y)
|
add_custom_target(do_always ALL xcopy /s \"$<TARGET_FILE_DIR:sdrpp_core>\\*.dll\" \"$<TARGET_FILE_DIR:sdrpp>\" /Y)
|
||||||
add_custom_target(do_always_volk ALL xcopy /s \"C:/Program Files/PothosSDR/bin\\volk.dll\" \"$<TARGET_FILE_DIR:sdrpp>\" /Y)
|
add_custom_target(do_always_volk ALL xcopy /s \"C:/Program Files/PothosSDR/bin\\volk.dll\" \"$<TARGET_FILE_DIR:sdrpp>\" /Y)
|
||||||
|
|
||||||
if (COPY_MSVC_REDISTRIBUTABLES)
|
|
||||||
# Get the list of Visual C++ runtime DLLs
|
|
||||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP True)
|
|
||||||
include(InstallRequiredSystemLibraries)
|
|
||||||
|
|
||||||
# Create a space sperated list
|
|
||||||
set(REDIST_DLLS_STR "")
|
|
||||||
foreach(DLL IN LISTS CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)
|
|
||||||
set(REDIST_DLLS_STR COMMAND xcopy /F \"${DLL}\" \"$<TARGET_FILE_DIR:sdrpp>\" /Y ${REDIST_DLLS_STR})
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
# Create target
|
|
||||||
add_custom_target(do_always_msvc ALL ${REDIST_DLLS_STR})
|
|
||||||
endif ()
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
|
if (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
|
||||||
add_custom_target(do_always ALL cp \"$<TARGET_FILE_DIR:sdrpp_core>/libsdrpp_core.so\" \"$<TARGET_FILE_DIR:sdrpp>\")
|
add_custom_target(do_always ALL cp \"$<TARGET_FILE_DIR:sdrpp_core>/libsdrpp_core.so\" \"$<TARGET_FILE_DIR:sdrpp>\")
|
||||||
endif ()
|
endif ()
|
||||||
|
@ -10,7 +10,7 @@ android {
|
|||||||
minSdkVersion 28
|
minSdkVersion 28
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.2.0"
|
versionName "1.1.0"
|
||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
|
@ -42,10 +42,8 @@ namespace sdrpp_credits {
|
|||||||
"Ettus Research",
|
"Ettus Research",
|
||||||
"Howard Su",
|
"Howard Su",
|
||||||
"MicroPhase",
|
"MicroPhase",
|
||||||
"Microtelecom",
|
|
||||||
"MyriadRF",
|
"MyriadRF",
|
||||||
"Nuand",
|
"Nuand",
|
||||||
"RFNM",
|
|
||||||
"RFspace",
|
"RFspace",
|
||||||
"RTL-SDRblog",
|
"RTL-SDRblog",
|
||||||
"SDRplay"
|
"SDRplay"
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
namespace dsp {
|
namespace dsp {
|
||||||
class generic_block {
|
class generic_block {
|
||||||
public:
|
public:
|
||||||
virtual ~generic_block() {}
|
|
||||||
virtual void start() {}
|
virtual void start() {}
|
||||||
virtual void stop() {}
|
virtual void stop() {}
|
||||||
virtual int run() { return -1; }
|
virtual int run() { return -1; }
|
||||||
@ -17,6 +16,8 @@ namespace dsp {
|
|||||||
|
|
||||||
class block : public generic_block {
|
class block : public generic_block {
|
||||||
public:
|
public:
|
||||||
|
virtual void init() {}
|
||||||
|
|
||||||
virtual ~block() {
|
virtual ~block() {
|
||||||
if (!_block_init) { return; }
|
if (!_block_init) { return; }
|
||||||
stop();
|
stop();
|
||||||
|
@ -10,8 +10,6 @@ namespace dsp {
|
|||||||
|
|
||||||
Operator(stream<A>* a, stream<B>* b) { init(a, b); }
|
Operator(stream<A>* a, stream<B>* b) { init(a, b); }
|
||||||
|
|
||||||
virtual ~Operator() {}
|
|
||||||
|
|
||||||
virtual void init(stream<A>* a, stream<B>* b) {
|
virtual void init(stream<A>* a, stream<B>* b) {
|
||||||
_a = a;
|
_a = a;
|
||||||
_b = b;
|
_b = b;
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
namespace dsp {
|
namespace dsp {
|
||||||
class untyped_stream {
|
class untyped_stream {
|
||||||
public:
|
public:
|
||||||
virtual ~untyped_stream() {}
|
|
||||||
virtual bool swap(int size) { return false; }
|
virtual bool swap(int size) { return false; }
|
||||||
virtual int read() { return -1; }
|
virtual int read() { return -1; }
|
||||||
virtual void flush() {}
|
virtual void flush() {}
|
||||||
|
@ -16,6 +16,7 @@ namespace icons {
|
|||||||
ImTextureID UNMUTED;
|
ImTextureID UNMUTED;
|
||||||
ImTextureID NORMAL_TUNING;
|
ImTextureID NORMAL_TUNING;
|
||||||
ImTextureID CENTER_TUNING;
|
ImTextureID CENTER_TUNING;
|
||||||
|
ImTextureID ALIGN_CENTER;
|
||||||
|
|
||||||
GLuint loadTexture(std::string path) {
|
GLuint loadTexture(std::string path) {
|
||||||
int w, h, n;
|
int w, h, n;
|
||||||
@ -45,6 +46,7 @@ namespace icons {
|
|||||||
UNMUTED = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/unmuted.png");
|
UNMUTED = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/unmuted.png");
|
||||||
NORMAL_TUNING = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/normal_tuning.png");
|
NORMAL_TUNING = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/normal_tuning.png");
|
||||||
CENTER_TUNING = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/center_tuning.png");
|
CENTER_TUNING = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/center_tuning.png");
|
||||||
|
ALIGN_CENTER = (ImTextureID)(uintptr_t)loadTexture(resDir + "/icons/align_center.png");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ namespace icons {
|
|||||||
extern ImTextureID UNMUTED;
|
extern ImTextureID UNMUTED;
|
||||||
extern ImTextureID NORMAL_TUNING;
|
extern ImTextureID NORMAL_TUNING;
|
||||||
extern ImTextureID CENTER_TUNING;
|
extern ImTextureID CENTER_TUNING;
|
||||||
|
extern ImTextureID ALIGN_CENTER;
|
||||||
|
|
||||||
GLuint loadTexture(std::string path);
|
GLuint loadTexture(std::string path);
|
||||||
bool load(std::string resDir);
|
bool load(std::string resDir);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <gui/menus/display.h>
|
#include <gui/menus/display.h>
|
||||||
#include <gui/menus/bandplan.h>
|
#include <gui/menus/bandplan.h>
|
||||||
#include <gui/menus/sink.h>
|
#include <gui/menus/sink.h>
|
||||||
|
#include <gui/menus/streams.h>
|
||||||
#include <gui/menus/vfo_color.h>
|
#include <gui/menus/vfo_color.h>
|
||||||
#include <gui/menus/module_manager.h>
|
#include <gui/menus/module_manager.h>
|
||||||
#include <gui/menus/theme.h>
|
#include <gui/menus/theme.h>
|
||||||
@ -72,6 +73,7 @@ void MainWindow::init() {
|
|||||||
|
|
||||||
gui::menu.registerEntry("Source", sourcemenu::draw, NULL);
|
gui::menu.registerEntry("Source", sourcemenu::draw, NULL);
|
||||||
gui::menu.registerEntry("Sinks", sinkmenu::draw, NULL);
|
gui::menu.registerEntry("Sinks", sinkmenu::draw, NULL);
|
||||||
|
gui::menu.registerEntry("Streams", streamsmenu::draw, NULL);
|
||||||
gui::menu.registerEntry("Band Plan", bandplanmenu::draw, NULL);
|
gui::menu.registerEntry("Band Plan", bandplanmenu::draw, NULL);
|
||||||
gui::menu.registerEntry("Display", displaymenu::draw, NULL);
|
gui::menu.registerEntry("Display", displaymenu::draw, NULL);
|
||||||
gui::menu.registerEntry("Theme", thememenu::draw, NULL);
|
gui::menu.registerEntry("Theme", thememenu::draw, NULL);
|
||||||
@ -165,6 +167,7 @@ void MainWindow::init() {
|
|||||||
|
|
||||||
sourcemenu::init();
|
sourcemenu::init();
|
||||||
sinkmenu::init();
|
sinkmenu::init();
|
||||||
|
streamsmenu::init();
|
||||||
bandplanmenu::init();
|
bandplanmenu::init();
|
||||||
displaymenu::init();
|
displaymenu::init();
|
||||||
vfo_color_menu::init();
|
vfo_color_menu::init();
|
||||||
|
@ -19,7 +19,6 @@ namespace displaymenu {
|
|||||||
std::string colorMapAuthor = "";
|
std::string colorMapAuthor = "";
|
||||||
int selectedWindow = 0;
|
int selectedWindow = 0;
|
||||||
int fftRate = 20;
|
int fftRate = 20;
|
||||||
int fftSizeId = 0;
|
|
||||||
int uiScaleId = 0;
|
int uiScaleId = 0;
|
||||||
bool restartRequired = false;
|
bool restartRequired = false;
|
||||||
bool fftHold = false;
|
bool fftHold = false;
|
||||||
@ -29,9 +28,34 @@ namespace displaymenu {
|
|||||||
bool snrSmoothing = false;
|
bool snrSmoothing = false;
|
||||||
int snrSmoothingSpeed = 20;
|
int snrSmoothingSpeed = 20;
|
||||||
|
|
||||||
OptionList<int, int> fftSizes;
|
|
||||||
OptionList<float, float> uiScales;
|
OptionList<float, float> uiScales;
|
||||||
|
|
||||||
|
const int FFTSizes[] = {
|
||||||
|
524288,
|
||||||
|
262144,
|
||||||
|
131072,
|
||||||
|
65536,
|
||||||
|
32768,
|
||||||
|
16384,
|
||||||
|
8192,
|
||||||
|
4096,
|
||||||
|
2048,
|
||||||
|
1024
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* FFTSizesStr = "524288\0"
|
||||||
|
"262144\0"
|
||||||
|
"131072\0"
|
||||||
|
"65536\0"
|
||||||
|
"32768\0"
|
||||||
|
"16384\0"
|
||||||
|
"8192\0"
|
||||||
|
"4096\0"
|
||||||
|
"2048\0"
|
||||||
|
"1024\0";
|
||||||
|
|
||||||
|
int fftSizeId = 0;
|
||||||
|
|
||||||
const IQFrontEnd::FFTWindow fftWindowList[] = {
|
const IQFrontEnd::FFTWindow fftWindowList[] = {
|
||||||
IQFrontEnd::FFTWindow::RECTANGULAR,
|
IQFrontEnd::FFTWindow::RECTANGULAR,
|
||||||
IQFrontEnd::FFTWindow::BLACKMAN,
|
IQFrontEnd::FFTWindow::BLACKMAN,
|
||||||
@ -45,18 +69,6 @@ namespace displaymenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
// Define FFT sizes
|
|
||||||
fftSizes.define(524288, "524288", 524288);
|
|
||||||
fftSizes.define(262144, "262144", 262144);
|
|
||||||
fftSizes.define(131072, "131072", 131072);
|
|
||||||
fftSizes.define(65536, "65536", 65536);
|
|
||||||
fftSizes.define(32768, "32768", 32768);
|
|
||||||
fftSizes.define(16384, "16384", 16384);
|
|
||||||
fftSizes.define(8192, "8192", 8192);
|
|
||||||
fftSizes.define(4096, "4096", 4096);
|
|
||||||
fftSizes.define(2048, "2048", 2048);
|
|
||||||
fftSizes.define(1024, "1024", 1024);
|
|
||||||
|
|
||||||
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"];
|
std::string colormapName = core::configManager.conf["colorMap"];
|
||||||
@ -78,12 +90,15 @@ namespace displaymenu {
|
|||||||
fullWaterfallUpdate = core::configManager.conf["fullWaterfallUpdate"];
|
fullWaterfallUpdate = core::configManager.conf["fullWaterfallUpdate"];
|
||||||
gui::waterfall.setFullWaterfallUpdate(fullWaterfallUpdate);
|
gui::waterfall.setFullWaterfallUpdate(fullWaterfallUpdate);
|
||||||
|
|
||||||
fftSizeId = fftSizes.valueId(65536);
|
fftSizeId = 3;
|
||||||
int size = core::configManager.conf["fftSize"];
|
int fftSize = core::configManager.conf["fftSize"];
|
||||||
if (fftSizes.keyExists(size)) {
|
for (int i = 0; i < 7; i++) {
|
||||||
fftSizeId = fftSizes.keyId(size);
|
if (fftSize == FFTSizes[i]) {
|
||||||
|
fftSizeId = i;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
sigpath::iqFrontEnd.setFFTSize(fftSizes.value(fftSizeId));
|
}
|
||||||
|
sigpath::iqFrontEnd.setFFTSize(FFTSizes[fftSizeId]);
|
||||||
|
|
||||||
fftRate = core::configManager.conf["fftRate"];
|
fftRate = core::configManager.conf["fftRate"];
|
||||||
sigpath::iqFrontEnd.setFFTRate(fftRate);
|
sigpath::iqFrontEnd.setFFTRate(fftRate);
|
||||||
@ -214,10 +229,10 @@ namespace displaymenu {
|
|||||||
|
|
||||||
ImGui::LeftLabel("FFT Size");
|
ImGui::LeftLabel("FFT Size");
|
||||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
if (ImGui::Combo("##sdrpp_fft_size", &fftSizeId, fftSizes.txt)) {
|
if (ImGui::Combo("##sdrpp_fft_size", &fftSizeId, FFTSizesStr)) {
|
||||||
sigpath::iqFrontEnd.setFFTSize(fftSizes.value(fftSizeId));
|
sigpath::iqFrontEnd.setFFTSize(FFTSizes[fftSizeId]);
|
||||||
core::configManager.acquire();
|
core::configManager.acquire();
|
||||||
core::configManager.conf["fftSize"] = fftSizes.key(fftSizeId);
|
core::configManager.conf["fftSize"] = FFTSizes[fftSizeId];
|
||||||
core::configManager.release(true);
|
core::configManager.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
177
core/src/gui/menus/streams.cpp
Normal file
177
core/src/gui/menus/streams.cpp
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
#include "streams.h"
|
||||||
|
#include <signal_path/signal_path.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <utils/flog.h>
|
||||||
|
#include <gui/style.h>
|
||||||
|
#include <gui/icons.h>
|
||||||
|
#include <utils/optionlist.h>
|
||||||
|
|
||||||
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
|
|
||||||
|
namespace streamsmenu {
|
||||||
|
std::vector<SinkID> sinksToBeRemoved;
|
||||||
|
|
||||||
|
std::recursive_mutex sinkTypesMtx;
|
||||||
|
OptionList<std::string, std::string> sinkTypes;
|
||||||
|
|
||||||
|
std::map<std::string, int> selectedSinkTypeId;
|
||||||
|
std::map<std::string, int> addSinkTypeId;
|
||||||
|
|
||||||
|
int addType = 0;
|
||||||
|
|
||||||
|
void updateSinkTypeList(const std::string& removed = "") {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck1(sinkTypesMtx);
|
||||||
|
auto lck2 = sigpath::streamManager.getSinkTypesLock();
|
||||||
|
const auto& types = sigpath::streamManager.getSinkTypes();
|
||||||
|
sinkTypes.clear();
|
||||||
|
for (const auto& type : types) {
|
||||||
|
if (type == removed) { continue; }
|
||||||
|
sinkTypes.define(type, type, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSinkProviderRegistered(const std::string& type) {
|
||||||
|
// Update the list
|
||||||
|
updateSinkTypeList();
|
||||||
|
|
||||||
|
// Update the ID of the Add dropdown
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// Update the selected ID of each drop down
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSinkProviderUnregister(const std::string& type) {
|
||||||
|
// Update the list
|
||||||
|
updateSinkTypeList(type);
|
||||||
|
|
||||||
|
// Update the ID of the Add dropdown
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// Update the selected ID of each drop down
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
sigpath::streamManager.onSinkProviderRegistered.bind(onSinkProviderRegistered);
|
||||||
|
sigpath::streamManager.onSinkProviderUnregister.bind(onSinkProviderUnregister);
|
||||||
|
updateSinkTypeList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(void* ctx) {
|
||||||
|
float menuWidth = ImGui::GetContentRegionAvail().x;
|
||||||
|
auto lck = sigpath::streamManager.getStreamsLock();
|
||||||
|
const auto& streams = sigpath::streamManager.getStreams();
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
int maxCount = streams.size();
|
||||||
|
for (auto& [name, stream] : streams) {
|
||||||
|
// Stream name
|
||||||
|
ImGui::SetCursorPosX((menuWidth / 2.0f) - (ImGui::CalcTextSize(name.c_str()).x / 2.0f));
|
||||||
|
ImGui::Text("%s", name.c_str());
|
||||||
|
|
||||||
|
// Display ever sink
|
||||||
|
if (ImGui::BeginTable(CONCAT("sdrpp_streams_tbl_", name), 1, ImGuiTableFlags_Borders)) {
|
||||||
|
auto lck2 = stream->getSinksLock();
|
||||||
|
auto sinks = stream->getSinks();
|
||||||
|
for (auto& [id, sink] : sinks) {
|
||||||
|
std::string sid = sink->getStringID();
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
float tableWidth = ImGui::GetContentRegionAvail().x;
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
// Sink type
|
||||||
|
int ttttt = 0;
|
||||||
|
ImGui::FillWidth();
|
||||||
|
if (ImGui::Combo(CONCAT("##sdrpp_streams_type_", sid), &ttttt, sinkTypes.txt)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sink->showMenu();
|
||||||
|
float vol = sink->getVolume();
|
||||||
|
bool muted = sink->getMuted();
|
||||||
|
float pan = sink->getPanning();
|
||||||
|
bool linked = true;
|
||||||
|
|
||||||
|
float height = ImGui::GetTextLineHeightWithSpacing() + 2;
|
||||||
|
ImGui::PushID(ImGui::GetID(("sdrpp_streams_center_btn_" + sid).c_str()));
|
||||||
|
if (ImGui::ImageButton(icons::ALIGN_CENTER, ImVec2(height, height), ImVec2(0, 0), ImVec2(1, 1), 0, ImVec4(0, 0, 0, 0), ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
|
||||||
|
sink->setPanning(0.0f);
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::FillWidth();
|
||||||
|
if (ImGui::SliderFloat(CONCAT("##sdrpp_streams_pan_", sid), &pan, -1, 1, "")) {
|
||||||
|
sink->setPanning(pan);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (muted) {
|
||||||
|
ImGui::PushID(ImGui::GetID(("sdrpp_unmute_btn_" + sid).c_str()));
|
||||||
|
if (ImGui::ImageButton(icons::MUTED, ImVec2(height, height), ImVec2(0, 0), ImVec2(1, 1), 0, ImVec4(0, 0, 0, 0), ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
|
||||||
|
sink->setMuted(false);
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ImGui::PushID(ImGui::GetID(("sdrpp_mute_btn_" + sid).c_str()));
|
||||||
|
if (ImGui::ImageButton(icons::UNMUTED, ImVec2(height, height), ImVec2(0, 0), ImVec2(1, 1), 0, ImVec4(0, 0, 0, 0), ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
|
||||||
|
sink->setMuted(true);
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::FillWidth();
|
||||||
|
if (ImGui::SliderFloat(CONCAT("##sdrpp_streams_vol_", sid), &vol, 0, 1, "")) {
|
||||||
|
sink->setVolume(vol);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int startCur = ImGui::GetCursorPosX();
|
||||||
|
if (ImGui::Checkbox(CONCAT("Link volume##sdrpp_streams_vol_", sid), &linked)) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(CONCAT("Remove##sdrpp_streams_remove_type_", sid), ImVec2(tableWidth - (ImGui::GetCursorPosX() - startCur), 0))) {
|
||||||
|
sinksToBeRemoved.push_back(id);
|
||||||
|
}
|
||||||
|
ImGui::Spacing();
|
||||||
|
}
|
||||||
|
lck2.unlock();
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
float tableWidth = ImGui::GetContentRegionAvail().x;
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
int startCur = ImGui::GetCursorPosX();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(sinkTypesMtx);
|
||||||
|
ImGui::Combo(CONCAT("##sdrpp_streams_add_type_", name), &addType, sinkTypes.txt);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(CONCAT("Add##sdrpp_streams_add_btn_", name), ImVec2(tableWidth - (ImGui::GetCursorPosX() - startCur), 0))) {
|
||||||
|
stream->addSink(sinkTypes.value(addType));
|
||||||
|
}
|
||||||
|
ImGui::Spacing();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
|
||||||
|
// Remove sinks that need to be removed
|
||||||
|
if (!sinksToBeRemoved.empty()) {
|
||||||
|
for (auto& id : sinksToBeRemoved) {
|
||||||
|
stream->removeSink(id);
|
||||||
|
}
|
||||||
|
sinksToBeRemoved.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
if (count < maxCount) {
|
||||||
|
ImGui::Spacing();
|
||||||
|
}
|
||||||
|
ImGui::Spacing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
6
core/src/gui/menus/streams.h
Normal file
6
core/src/gui/menus/streams.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace streamsmenu {
|
||||||
|
void init();
|
||||||
|
void draw(void* ctx);
|
||||||
|
};
|
@ -52,15 +52,4 @@ namespace ImGui {
|
|||||||
bufferMtx.unlock();
|
bufferMtx.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SymbolDiagram::setCount(int count) {
|
|
||||||
std::lock_guard<std::mutex> lck(bufferMtx);
|
|
||||||
delete[] buffer;
|
|
||||||
buffer = new float[count];
|
|
||||||
sampleCount = count;
|
|
||||||
memset(buffer, 0, sampleCount * sizeof(float));
|
|
||||||
}
|
|
||||||
|
|
||||||
int SymbolDiagram::getCount() {
|
|
||||||
return sampleCount;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -18,10 +18,6 @@ namespace ImGui {
|
|||||||
|
|
||||||
void releaseBuffer();
|
void releaseBuffer();
|
||||||
|
|
||||||
void setCount(int count);
|
|
||||||
|
|
||||||
int getCount();
|
|
||||||
|
|
||||||
std::vector<float> lines;
|
std::vector<float> lines;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -110,7 +110,7 @@ namespace ImGui {
|
|||||||
viewBandwidth = 1.0;
|
viewBandwidth = 1.0;
|
||||||
wholeBandwidth = 1.0;
|
wholeBandwidth = 1.0;
|
||||||
|
|
||||||
//updatePallette(DEFAULT_COLOR_MAP, 13);
|
updatePallette(DEFAULT_COLOR_MAP, 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterFall::init() {
|
void WaterFall::init() {
|
||||||
|
@ -42,7 +42,6 @@ public:
|
|||||||
|
|
||||||
class Instance {
|
class Instance {
|
||||||
public:
|
public:
|
||||||
virtual ~Instance() {}
|
|
||||||
virtual void postInit() = 0;
|
virtual void postInit() = 0;
|
||||||
virtual void enable() = 0;
|
virtual void enable() = 0;
|
||||||
virtual void disable() = 0;
|
virtual void disable() = 0;
|
||||||
|
@ -5,4 +5,5 @@ namespace sigpath {
|
|||||||
VFOManager vfoManager;
|
VFOManager vfoManager;
|
||||||
SourceManager sourceManager;
|
SourceManager sourceManager;
|
||||||
SinkManager sinkManager;
|
SinkManager sinkManager;
|
||||||
|
StreamManager streamManager;
|
||||||
};
|
};
|
@ -3,6 +3,7 @@
|
|||||||
#include "vfo_manager.h"
|
#include "vfo_manager.h"
|
||||||
#include "source.h"
|
#include "source.h"
|
||||||
#include "sink.h"
|
#include "sink.h"
|
||||||
|
#include "stream.h"
|
||||||
#include <module.h>
|
#include <module.h>
|
||||||
|
|
||||||
namespace sigpath {
|
namespace sigpath {
|
||||||
@ -10,4 +11,5 @@ namespace sigpath {
|
|||||||
SDRPP_EXPORT VFOManager vfoManager;
|
SDRPP_EXPORT VFOManager vfoManager;
|
||||||
SDRPP_EXPORT SourceManager sourceManager;
|
SDRPP_EXPORT SourceManager sourceManager;
|
||||||
SDRPP_EXPORT SinkManager sinkManager;
|
SDRPP_EXPORT SinkManager sinkManager;
|
||||||
|
SDRPP_EXPORT StreamManager streamManager;
|
||||||
};
|
};
|
519
core/src/signal_path/stream.cpp
Normal file
519
core/src/signal_path/stream.cpp
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
#include "stream.h"
|
||||||
|
#include <utils/flog.h>
|
||||||
|
|
||||||
|
Sink::Sink(SinkEntry* entry, dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id, const std::string& stringId) :
|
||||||
|
entry(entry),
|
||||||
|
stream(stream),
|
||||||
|
streamName(name),
|
||||||
|
id(id),
|
||||||
|
stringId(stringId)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Sink::showMenu() {}
|
||||||
|
|
||||||
|
SinkEntry::SinkEntry(StreamManager* manager, Stream* parentStream, const std::string& type, SinkID id, double inputSamplerate) :
|
||||||
|
manager(manager),
|
||||||
|
parentStream(parentStream),
|
||||||
|
id(id)
|
||||||
|
{
|
||||||
|
this->type = type;
|
||||||
|
this->inputSamplerate = inputSamplerate;
|
||||||
|
|
||||||
|
// Generate string ID
|
||||||
|
stringId = parentStream->getName();
|
||||||
|
char buf[16];
|
||||||
|
sprintf(buf, "%d", (int)id);
|
||||||
|
stringId += buf;
|
||||||
|
|
||||||
|
// Initialize DSP
|
||||||
|
resamp.init(&input, inputSamplerate, inputSamplerate);
|
||||||
|
volumeAdjust.init(&resamp.out, 1.0f, false);
|
||||||
|
|
||||||
|
// Initialize the sink
|
||||||
|
setType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SinkEntry::getType() const {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinkEntry::setType(const std::string& type) {
|
||||||
|
// Get unique lock on the entry
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
|
||||||
|
// Delete existing sink
|
||||||
|
if (sink) {
|
||||||
|
provider->destroySink(std::move(sink));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get shared lock on sink types
|
||||||
|
auto lck2 = manager->getSinkTypesLock();
|
||||||
|
|
||||||
|
// Get the provider or throw error
|
||||||
|
const auto& types = manager->getSinkTypes();
|
||||||
|
if (std::find(types.begin(), types.end(), type) == types.end()) {
|
||||||
|
this->type.clear();
|
||||||
|
throw SinkEntryCreateException("Invalid sink type");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create sink
|
||||||
|
this->type = type;
|
||||||
|
provider = manager->providers[type];
|
||||||
|
sink = provider->createSink(this, &volumeAdjust.out, parentStream->getName(), id, stringId);
|
||||||
|
}
|
||||||
|
|
||||||
|
SinkID SinkEntry::getID() const {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SinkEntry::getVolume() const {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinkEntry::setVolume(float volume) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
this->volume = volume;
|
||||||
|
volumeAdjust.setVolume(volume);
|
||||||
|
onVolumeChanged(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SinkEntry::getMuted() const {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
return muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinkEntry::setMuted(bool muted) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
this->muted = muted;
|
||||||
|
volumeAdjust.setMuted(muted);
|
||||||
|
onMutedChanged(muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SinkEntry::getPanning() const {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
return panning;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinkEntry::setPanning(float panning) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
this->panning = panning;
|
||||||
|
// TODO
|
||||||
|
onPanningChanged(panning);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinkEntry::showMenu() {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
sink->showMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinkEntry::startSink() {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
sink->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinkEntry::stopSink() {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
sink->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::recursive_mutex> SinkEntry::getLock() const {
|
||||||
|
return std::lock_guard<std::recursive_mutex>(mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinkEntry::setSamplerate(double samplerate) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
resamp.setOutSamplerate(samplerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinkEntry::startDSP() {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
resamp.start();
|
||||||
|
volumeAdjust.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinkEntry::stopDSP() {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
resamp.stop();
|
||||||
|
volumeAdjust.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinkEntry::destroy(bool forgetSettings) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
if (sink) {
|
||||||
|
provider->destroySink(std::move(sink));
|
||||||
|
}
|
||||||
|
type.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinkEntry::setInputSamplerate(double samplerate) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lck(mtx);
|
||||||
|
resamp.setInSamplerate(samplerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SinkEntry::getStringID() const {
|
||||||
|
return stringId;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream::Stream(StreamManager* manager, const std::string& name, dsp::stream<dsp::stereo_t>* stream, double samplerate) :
|
||||||
|
manager(manager),
|
||||||
|
name(name)
|
||||||
|
{
|
||||||
|
this->samplerate = samplerate;
|
||||||
|
|
||||||
|
// Initialize DSP
|
||||||
|
split.init(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream::~Stream() {
|
||||||
|
// Copy sink IDs
|
||||||
|
std::vector<SinkID> ids;
|
||||||
|
for (auto& [id, sink] : sinks) {
|
||||||
|
ids.push_back(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove them all
|
||||||
|
for (auto& id : ids) {
|
||||||
|
removeSink(id, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& Stream::getName() const {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
SinkID Stream::addSink(const std::string& type, SinkID id) {
|
||||||
|
std::unique_lock<std::shared_mutex> lck(sinksMtx);
|
||||||
|
|
||||||
|
// Find a free ID if not provided
|
||||||
|
if (id < 0) {
|
||||||
|
for (id = 0; sinks.find(id) != sinks.end(); id++);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Check that the provided ID is valid
|
||||||
|
if (sinks.find(id) != sinks.end()) {
|
||||||
|
flog::error("Tried to create sink for stream '{}' with existing ID: {}", name, id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create sink entry
|
||||||
|
std::shared_ptr<SinkEntry> sink;
|
||||||
|
try {
|
||||||
|
sink = std::make_shared<SinkEntry>(manager, this, type, id, samplerate);
|
||||||
|
}
|
||||||
|
catch (SinkEntryCreateException e) {
|
||||||
|
flog::error("Tried to create sink for stream '{}' with ID '{}': {}", name, id, e.what());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the sink and DSP
|
||||||
|
sink->startSink();
|
||||||
|
if (running) { sink->startDSP(); }
|
||||||
|
|
||||||
|
// Bind the sinks's input
|
||||||
|
split.bindStream(&sink->input);
|
||||||
|
|
||||||
|
// Add sink to list
|
||||||
|
sinks[id] = sink;
|
||||||
|
|
||||||
|
// Release lock and emit event
|
||||||
|
lck.unlock();
|
||||||
|
onSinkAdded(sink);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::removeSink(SinkID id, bool forgetSettings) {
|
||||||
|
// Acquire shared lock
|
||||||
|
std::shared_ptr<SinkEntry> sink;
|
||||||
|
{
|
||||||
|
std::shared_lock<std::shared_mutex> lck(sinksMtx);
|
||||||
|
|
||||||
|
// Check that the ID exists
|
||||||
|
if (sinks.find(id) == sinks.end()) {
|
||||||
|
flog::error("Tried to remove sink with unknown ID: {}", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get sink
|
||||||
|
sink = sinks[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit event
|
||||||
|
onSinkRemove(sink);
|
||||||
|
|
||||||
|
// Acquire unique lock
|
||||||
|
{
|
||||||
|
std::unique_lock<std::shared_mutex> lck(sinksMtx);
|
||||||
|
|
||||||
|
// Check that it's still in the list
|
||||||
|
if (sinks.find(id) == sinks.end()) {
|
||||||
|
flog::error("Tried to remove sink with unknown ID: {}", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from list
|
||||||
|
sinks.erase(id);
|
||||||
|
|
||||||
|
// Unbind the sink's steam
|
||||||
|
split.unbindStream(&sink->input);
|
||||||
|
|
||||||
|
// Stop the sink and DSP
|
||||||
|
sink->stopDSP();
|
||||||
|
sink->stopSink();
|
||||||
|
|
||||||
|
// Delete instance
|
||||||
|
sink->destroy(forgetSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_lock<std::shared_mutex> Stream::getSinksLock() {
|
||||||
|
return std::shared_lock<std::shared_mutex>(sinksMtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::map<SinkID, std::shared_ptr<SinkEntry>>& Stream::getSinks() const {
|
||||||
|
return sinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
MasterStream::MasterStream(StreamManager* manager, const std::string& name, dsp::stream<dsp::stereo_t>* stream, double samplerate) :
|
||||||
|
Stream(manager, name, stream, samplerate)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void MasterStream::setInput(dsp::stream<dsp::stereo_t>* stream, double samplerate) {
|
||||||
|
std::unique_lock<std::shared_mutex> lck(sinksMtx);
|
||||||
|
|
||||||
|
// If all that's needed is to set the input, do it and return
|
||||||
|
if (samplerate == 0.0) {
|
||||||
|
split.setInput(stream);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update samplerate
|
||||||
|
this->samplerate = samplerate;
|
||||||
|
|
||||||
|
// Stop DSP
|
||||||
|
if (running) {
|
||||||
|
split.stop();
|
||||||
|
for (auto& [id, sink] : sinks) {
|
||||||
|
sink->stopDSP();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set input and samplerate
|
||||||
|
split.setInput(stream);
|
||||||
|
for (auto& [id, sink] : sinks) {
|
||||||
|
sink->setInputSamplerate(samplerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start DSP
|
||||||
|
if (running) {
|
||||||
|
for (auto& [id, sink] : sinks) {
|
||||||
|
sink->startDSP();
|
||||||
|
}
|
||||||
|
split.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MasterStream::setSamplerate(double samplerate) {
|
||||||
|
std::unique_lock<std::shared_mutex> lck(sinksMtx);
|
||||||
|
|
||||||
|
// Update samplerate
|
||||||
|
this->samplerate = samplerate;
|
||||||
|
|
||||||
|
// TODO: Maybe simply disallow while running?
|
||||||
|
|
||||||
|
// Stop DSP if it was running
|
||||||
|
if (running) {
|
||||||
|
split.stop();
|
||||||
|
for (auto& [id, sink] : sinks) {
|
||||||
|
sink->stopDSP();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set samplerate
|
||||||
|
for (auto& [id, sink] : sinks) {
|
||||||
|
sink->setInputSamplerate(samplerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start DSP if it was running
|
||||||
|
if (running) {
|
||||||
|
for (auto& [id, sink] : sinks) {
|
||||||
|
sink->startDSP();
|
||||||
|
}
|
||||||
|
split.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MasterStream::startDSP() {
|
||||||
|
// TODO: Maybe add a different mutex for the stream?
|
||||||
|
std::unique_lock<std::shared_mutex> lck(sinksMtx);
|
||||||
|
|
||||||
|
// Check if already running
|
||||||
|
if (running) { return; }
|
||||||
|
|
||||||
|
// Start all DSP
|
||||||
|
split.start();
|
||||||
|
for (auto& [id, sink] : sinks) {
|
||||||
|
sink->startDSP();
|
||||||
|
}
|
||||||
|
running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MasterStream::stopDSP() {
|
||||||
|
// TODO: Maybe add a different mutex for the stream?
|
||||||
|
std::unique_lock<std::shared_mutex> lck(sinksMtx);
|
||||||
|
|
||||||
|
// Check if already running
|
||||||
|
if (!running) { return; }
|
||||||
|
|
||||||
|
// Start all DSP
|
||||||
|
split.stop();
|
||||||
|
for (auto& [id, sink] : sinks) {
|
||||||
|
sink->stopDSP();
|
||||||
|
}
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<MasterStream> StreamManager::createStream(const std::string& name, dsp::stream<dsp::stereo_t>* stream, double samplerate) {
|
||||||
|
std::unique_lock<std::shared_mutex> lck(streamsMtx);
|
||||||
|
|
||||||
|
// Check that no stream with that name already exists
|
||||||
|
if (streams.find(name) != streams.end()) {
|
||||||
|
flog::error("Tried to created stream with an existing name: {}", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and save stream
|
||||||
|
std::shared_ptr<MasterStream> newStream(new MasterStream(this, name, stream, samplerate));
|
||||||
|
streams[name] = newStream;
|
||||||
|
|
||||||
|
// Release lock and emit event
|
||||||
|
lck.unlock();
|
||||||
|
onStreamCreated(newStream);
|
||||||
|
|
||||||
|
return newStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamManager::destroyStream(std::shared_ptr<MasterStream>& stream) {
|
||||||
|
// Emit event
|
||||||
|
onStreamDestroy(stream);
|
||||||
|
|
||||||
|
// Aquire complete lock on the stream list
|
||||||
|
{
|
||||||
|
std::unique_lock<std::shared_mutex> lck(streamsMtx);
|
||||||
|
|
||||||
|
// Get iterator of the stream
|
||||||
|
auto it = std::find_if(streams.begin(), streams.end(), [&stream](std::pair<const std::string, std::shared_ptr<Stream>> e) {
|
||||||
|
return e.second == stream;
|
||||||
|
});
|
||||||
|
if (it == streams.end()) {
|
||||||
|
flog::error("Tried to delete a stream using an invalid pointer. Stream not found in list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete entry from list
|
||||||
|
flog::debug("Stream pointer uses, should be 2 and is {}", (int)stream.use_count());
|
||||||
|
streams.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset passed pointer
|
||||||
|
stream.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_lock<std::shared_mutex> StreamManager::getStreamsLock() {
|
||||||
|
return std::shared_lock<std::shared_mutex>(streamsMtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::map<std::string, std::shared_ptr<Stream>>& StreamManager::getStreams() const {
|
||||||
|
return streams;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamManager::registerSinkProvider(const std::string& name, SinkProvider* provider) {
|
||||||
|
std::unique_lock<std::shared_mutex> lck(providersMtx);
|
||||||
|
|
||||||
|
// Check that a provider with that name doesn't already exist
|
||||||
|
if (providers.find(name) != providers.end()) {
|
||||||
|
flog::error("Tried to register a sink provider with an existing name: {}", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add provider to the list and sort name list
|
||||||
|
providers[name] = provider;
|
||||||
|
sinkTypes.push_back(name);
|
||||||
|
std::sort(sinkTypes.begin(), sinkTypes.end());
|
||||||
|
|
||||||
|
// Release lock and emit event
|
||||||
|
lck.unlock();
|
||||||
|
onSinkProviderRegistered(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamManager::unregisterSinkProvider(SinkProvider* provider) {
|
||||||
|
// Get provider name for event
|
||||||
|
std::string type;
|
||||||
|
{
|
||||||
|
std::shared_lock<std::shared_mutex> lck(providersMtx);
|
||||||
|
auto it = std::find_if(providers.begin(), providers.end(), [&provider](std::pair<const std::string, SinkProvider *> e) {
|
||||||
|
return e.second == provider;
|
||||||
|
});
|
||||||
|
if (it == providers.end()) {
|
||||||
|
flog::error("Tried to unregister sink provider using invalid pointer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
type = (*it).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit event
|
||||||
|
onSinkProviderUnregister(type);
|
||||||
|
|
||||||
|
// Acquire shared lock on streams
|
||||||
|
{
|
||||||
|
std::unique_lock<std::shared_mutex> lck1(providersMtx);
|
||||||
|
std::shared_lock<std::shared_mutex> lck2(streamsMtx);
|
||||||
|
for (auto& [name, stream] : streams) {
|
||||||
|
// Aquire lock on sink list
|
||||||
|
auto sLock = stream->getSinksLock();
|
||||||
|
const auto& sinks = stream->getSinks();
|
||||||
|
|
||||||
|
// Find all sinks with the type that is about to be removed
|
||||||
|
std::vector<SinkID> toRemove;
|
||||||
|
for (auto& [id, sink] : sinks) {
|
||||||
|
if (sink->getType() != type) { continue; }
|
||||||
|
toRemove.push_back(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove them all (TODO: THERE IS RACE CONDITION IF A SINK IS CHANGED AFTER LISTING)
|
||||||
|
sLock.unlock();
|
||||||
|
for (auto& id : toRemove) {
|
||||||
|
stream->removeSink(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from the lists
|
||||||
|
if (providers.find(type) != providers.end()) {
|
||||||
|
providers.erase(type);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
flog::error("Could not remove sink provider from list");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = std::find(sinkTypes.begin(), sinkTypes.end(), type);
|
||||||
|
if (it != sinkTypes.end()) {
|
||||||
|
sinkTypes.erase(it);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
flog::error("Could not remove sink provider from sink type list");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_lock<std::shared_mutex> StreamManager::getSinkTypesLock() {
|
||||||
|
return std::shared_lock<std::shared_mutex>(providersMtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string>& StreamManager::getSinkTypes() const {
|
||||||
|
// TODO: This allows code to modify the names...
|
||||||
|
return sinkTypes;
|
||||||
|
}
|
334
core/src/signal_path/stream.h
Normal file
334
core/src/signal_path/stream.h
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <dsp/stream.h>
|
||||||
|
#include <dsp/types.h>
|
||||||
|
#include <dsp/routing/splitter.h>
|
||||||
|
#include <dsp/multirate/rational_resampler.h>
|
||||||
|
#include <dsp/audio/volume.h>
|
||||||
|
#include <utils/new_event.h>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
class SinkEntry;
|
||||||
|
class Stream;
|
||||||
|
class MasterStream;
|
||||||
|
class StreamManager;
|
||||||
|
|
||||||
|
using SinkID = int;
|
||||||
|
|
||||||
|
class Sink {
|
||||||
|
public:
|
||||||
|
Sink(SinkEntry* entry, dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id, const std::string& stringId);
|
||||||
|
virtual ~Sink() {}
|
||||||
|
|
||||||
|
virtual void start() = 0;
|
||||||
|
virtual void stop() = 0;
|
||||||
|
virtual void showMenu();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SinkEntry* const entry;
|
||||||
|
dsp::stream<dsp::stereo_t>* const stream;
|
||||||
|
const std::string streamName;
|
||||||
|
const SinkID id;
|
||||||
|
const std::string stringId;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinkProvider {
|
||||||
|
friend Sink;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create a sink instance.
|
||||||
|
* @param name Name of the audio stream.
|
||||||
|
* @param index Index of the sink in the menu. Should be use to keep settings.
|
||||||
|
*/
|
||||||
|
virtual std::unique_ptr<Sink> createSink(SinkEntry* entry, dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id, const std::string& stringId) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a sink instance. This function is so that the provide knows at all times how many instances there are.
|
||||||
|
* @param sink Instance of the sink.
|
||||||
|
*/
|
||||||
|
virtual void destroySink(std::unique_ptr<Sink> sink) {
|
||||||
|
sink.reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SinkEntryCreateException : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
SinkEntryCreateException(const char* what) : std::runtime_error(what) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Would be cool to have data and audio sinks instead of just audio.
|
||||||
|
class SinkEntry {
|
||||||
|
friend Sink;
|
||||||
|
friend Stream;
|
||||||
|
friend MasterStream;
|
||||||
|
public:
|
||||||
|
SinkEntry(StreamManager* manager, Stream* parentStream, const std::string& type, SinkID id, double inputSamplerate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of the sink.
|
||||||
|
* @return Type of the sink.
|
||||||
|
*/
|
||||||
|
std::string getType() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the type of the sink.
|
||||||
|
* @param type New sink type.
|
||||||
|
*/
|
||||||
|
void setType(const std::string& type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the ID of the sink.
|
||||||
|
* @return ID of the sink.
|
||||||
|
*/
|
||||||
|
SinkID getID() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get sink volume.
|
||||||
|
* @return Volume as value between 0.0 and 1.0.
|
||||||
|
*/
|
||||||
|
float getVolume() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set sink volume.
|
||||||
|
* @param volume Volume as value between 0.0 and 1.0.
|
||||||
|
*/
|
||||||
|
void setVolume(float volume);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the sink is muted.
|
||||||
|
* @return True if muted, false if not.
|
||||||
|
*/
|
||||||
|
bool getMuted() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set wether or not the sink is muted
|
||||||
|
* @param muted True to mute, false to unmute.
|
||||||
|
*/
|
||||||
|
void setMuted(bool muted);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get sink panning.
|
||||||
|
* @return Panning as value between -1.0 and 1.0 meaning panning to the left and right respectively.
|
||||||
|
*/
|
||||||
|
float getPanning() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set sink panning.
|
||||||
|
* @param panning Panning as value between -1.0 and 1.0 meaning panning to the left and right respectively.
|
||||||
|
*/
|
||||||
|
void setPanning(float panning);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the sink type-specific menu.
|
||||||
|
*/
|
||||||
|
void showMenu();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the string form ID unique to both the sink and stream. Be used to reference settings.
|
||||||
|
* @return Unique string ID.
|
||||||
|
*/
|
||||||
|
std::string getStringID() const;
|
||||||
|
|
||||||
|
// Emitted when the type of the sink was changed
|
||||||
|
NewEvent<const std::string&> onTypeChanged;
|
||||||
|
// Emmited when volume of the sink was changed
|
||||||
|
NewEvent<float> onVolumeChanged;
|
||||||
|
// Emitted when the muted state of the sink was changed
|
||||||
|
NewEvent<bool> onMutedChanged;
|
||||||
|
// Emitted when the panning of the sink was changed
|
||||||
|
NewEvent<float> onPanningChanged;
|
||||||
|
|
||||||
|
// TODO: Need to allow the sink to change the entry samplerate and start/stop the DSP
|
||||||
|
// This will also require allowing it to get a lock on the sink so others don't attempt to mess with it.
|
||||||
|
std::lock_guard<std::recursive_mutex> getLock() const;
|
||||||
|
void startDSP();
|
||||||
|
void stopDSP();
|
||||||
|
void setSamplerate(double samplerate);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void startSink();
|
||||||
|
void stopSink();
|
||||||
|
|
||||||
|
void destroy(bool forgetSettings);
|
||||||
|
void setInputSamplerate(double samplerate);
|
||||||
|
|
||||||
|
mutable std::recursive_mutex mtx;
|
||||||
|
dsp::stream<dsp::stereo_t> input;
|
||||||
|
dsp::multirate::RationalResampler<dsp::stereo_t> resamp;
|
||||||
|
dsp::audio::Volume volumeAdjust;
|
||||||
|
|
||||||
|
SinkProvider* provider = NULL;
|
||||||
|
std::unique_ptr<Sink> sink;
|
||||||
|
std::string type;
|
||||||
|
const SinkID id;
|
||||||
|
double inputSamplerate;
|
||||||
|
Stream* const parentStream;
|
||||||
|
StreamManager* const manager;
|
||||||
|
|
||||||
|
std::string stringId;
|
||||||
|
|
||||||
|
float volume = 1.0f;
|
||||||
|
bool muted = false;
|
||||||
|
float panning = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Stream {
|
||||||
|
protected:
|
||||||
|
Stream(StreamManager* manager, const std::string& name, dsp::stream<dsp::stereo_t>* stream, double samplerate);
|
||||||
|
public:
|
||||||
|
~Stream();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the stream.
|
||||||
|
* @return Name of the stream.
|
||||||
|
*/
|
||||||
|
const std::string& getName() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a sink to the stream.
|
||||||
|
* @param type Type of the sink.
|
||||||
|
* @param id ID of the sink. Optional, -1 if automatic.
|
||||||
|
* @return ID of the new sink or -1 on error.
|
||||||
|
*/
|
||||||
|
SinkID addSink(const std::string& type, SinkID id = -1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a sink from a stream.
|
||||||
|
* @param id ID of the sink.
|
||||||
|
* @param forgetSettings Forget the settings for the sink.
|
||||||
|
*/
|
||||||
|
void removeSink(SinkID id, bool forgetSettings = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aquire a lock for the sink list.
|
||||||
|
* @return Shared lock for the sink list.
|
||||||
|
*/
|
||||||
|
std::shared_lock<std::shared_mutex> getSinksLock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of all sinks belonging to this stream.
|
||||||
|
* @return Sink list.
|
||||||
|
*/
|
||||||
|
const std::map<SinkID, std::shared_ptr<SinkEntry>>& getSinks() const;
|
||||||
|
|
||||||
|
// Emitted when the samplerate of the stream was changed
|
||||||
|
NewEvent<double> onSamplerateChanged;
|
||||||
|
// Emitted when a sink was added
|
||||||
|
NewEvent<std::shared_ptr<SinkEntry>> onSinkAdded;
|
||||||
|
// Emitted when a sink is being removed
|
||||||
|
NewEvent<std::shared_ptr<SinkEntry>> onSinkRemove;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StreamManager* const manager;
|
||||||
|
const std::string name;
|
||||||
|
double samplerate;
|
||||||
|
dsp::routing::Splitter<dsp::stereo_t> split;
|
||||||
|
bool running = false;
|
||||||
|
|
||||||
|
std::map<SinkID, std::shared_ptr<SinkEntry>> sinks;
|
||||||
|
std::shared_mutex sinksMtx;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MasterStream : public Stream {
|
||||||
|
friend StreamManager;
|
||||||
|
MasterStream(StreamManager* manager, const std::string& name, dsp::stream<dsp::stereo_t>* stream, double samplerate);
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Set DSP stream input.
|
||||||
|
* @param stream DSP stream.
|
||||||
|
* @param samplerate New samplerate (optional, 0.0 if not used).
|
||||||
|
*/
|
||||||
|
void setInput(dsp::stream<dsp::stereo_t>* stream, double samplerate = 0.0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the samplerate of the input stream.
|
||||||
|
* @param samplerate Samplerate in Hz.
|
||||||
|
*/
|
||||||
|
void setSamplerate(double samplerate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the DSP.
|
||||||
|
*/
|
||||||
|
void startDSP();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the DSP.
|
||||||
|
*/
|
||||||
|
void stopDSP();
|
||||||
|
};
|
||||||
|
|
||||||
|
class StreamManager {
|
||||||
|
friend SinkEntry;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create an audio stream.
|
||||||
|
* @param name Name of the stream.
|
||||||
|
* @param stream DSP stream that outputs the audio.
|
||||||
|
* @param samplerate Samplerate of the audio data.
|
||||||
|
* @return Audio stream instance.
|
||||||
|
*/
|
||||||
|
std::shared_ptr<MasterStream> createStream(const std::string& name, dsp::stream<dsp::stereo_t>* stream, double samplerate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy an audio stream.
|
||||||
|
* @param stream Stream to destroy. The passed shared pointer will be automatically reset.
|
||||||
|
*/
|
||||||
|
void destroyStream(std::shared_ptr<MasterStream>& stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aquire a lock for the stream list.
|
||||||
|
* @return Shared lock for the stream list.
|
||||||
|
*/
|
||||||
|
std::shared_lock<std::shared_mutex> getStreamsLock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of streams and their associated names.
|
||||||
|
* @return Map of names to stream instance.
|
||||||
|
*/
|
||||||
|
const std::map<std::string, std::shared_ptr<Stream>>& getStreams() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a sink provider.
|
||||||
|
* @param name Name of the sink type.
|
||||||
|
* @param provider Sink provider instance.
|
||||||
|
*/
|
||||||
|
void registerSinkProvider(const std::string& name, SinkProvider* provider);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister a sink provider.
|
||||||
|
* @param name Name of the sink type.
|
||||||
|
*/
|
||||||
|
void unregisterSinkProvider(SinkProvider* provider);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aquire a lock for the sink type list.
|
||||||
|
* @return Shared lock for the sink type list.
|
||||||
|
*/
|
||||||
|
std::shared_lock<std::shared_mutex> getSinkTypesLock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of sink types.
|
||||||
|
* @return List of sink type names in alphabetical order.
|
||||||
|
*/
|
||||||
|
const std::vector<std::string>& getSinkTypes() const;
|
||||||
|
|
||||||
|
// Emitted when a stream was created
|
||||||
|
NewEvent<std::shared_ptr<Stream>> onStreamCreated;
|
||||||
|
// Emitted when a stream is about to be destroyed
|
||||||
|
NewEvent<std::shared_ptr<Stream>> onStreamDestroy;
|
||||||
|
// Emitted when a sink provider was registered
|
||||||
|
NewEvent<const std::string&> onSinkProviderRegistered;
|
||||||
|
// Emitted when a sink provider is about to be unregistered
|
||||||
|
NewEvent<const std::string&> onSinkProviderUnregister;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, std::shared_ptr<Stream>> streams;
|
||||||
|
std::shared_mutex streamsMtx;
|
||||||
|
|
||||||
|
std::map<std::string, SinkProvider*> providers;
|
||||||
|
std::vector<std::string> sinkTypes;
|
||||||
|
std::shared_mutex providersMtx;
|
||||||
|
};
|
@ -63,6 +63,7 @@ namespace net::http {
|
|||||||
|
|
||||||
std::string MessageHeader::getField(const std::string name) {
|
std::string MessageHeader::getField(const std::string name) {
|
||||||
// TODO: Check if exists
|
// TODO: Check if exists
|
||||||
|
// TODO: Maybe declare the set/get field functions to do type conversions automatically?
|
||||||
return fields[name];
|
return fields[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define VERSION_STR "1.2.0"
|
#define VERSION_STR "1.1.0"
|
@ -8,15 +8,15 @@
|
|||||||
#include "dsp.h"
|
#include "dsp.h"
|
||||||
#include "pocsag.h"
|
#include "pocsag.h"
|
||||||
|
|
||||||
|
#define BAUDRATE 2400
|
||||||
|
#define SAMPLERATE (BAUDRATE*10)
|
||||||
|
|
||||||
class POCSAGDecoder : public Decoder {
|
class POCSAGDecoder : public Decoder {
|
||||||
public:
|
public:
|
||||||
POCSAGDecoder(const std::string& name, VFOManager::VFO* vfo) : diag(0.6, 2400) {
|
POCSAGDecoder(const std::string& name, VFOManager::VFO* vfo) : diag(0.6, BAUDRATE) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
this->vfo = vfo;
|
this->vfo = vfo;
|
||||||
|
|
||||||
// Default baudrate (TODO: Load from config)
|
|
||||||
baudrate = 2400;
|
|
||||||
|
|
||||||
// Define baudrate options
|
// Define baudrate options
|
||||||
baudrates.define(512, "512 Baud", 512);
|
baudrates.define(512, "512 Baud", 512);
|
||||||
baudrates.define(1200, "1200 Baud", 1200);
|
baudrates.define(1200, "1200 Baud", 1200);
|
||||||
@ -24,9 +24,9 @@ public:
|
|||||||
|
|
||||||
// Init DSP
|
// Init DSP
|
||||||
vfo->setBandwidthLimits(12500, 12500, true);
|
vfo->setBandwidthLimits(12500, 12500, true);
|
||||||
vfo->setSampleRate(baudrate*10.0, 12500);
|
vfo->setSampleRate(SAMPLERATE, 12500);
|
||||||
dsp.init(vfo->output, baudrate*10.0, baudrate);
|
dsp.init(vfo->output, SAMPLERATE, BAUDRATE);
|
||||||
reshape.init(&dsp.soft, baudrate, (baudrate / 30.0) - baudrate);
|
reshape.init(&dsp.soft, BAUDRATE, (BAUDRATE / 30.0) - BAUDRATE);
|
||||||
dataHandler.init(&dsp.out, _dataHandler, this);
|
dataHandler.init(&dsp.out, _dataHandler, this);
|
||||||
diagHandler.init(&reshape.out, _diagHandler, this);
|
diagHandler.init(&reshape.out, _diagHandler, this);
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ public:
|
|||||||
ImGui::LeftLabel("Baudrate");
|
ImGui::LeftLabel("Baudrate");
|
||||||
ImGui::FillWidth();
|
ImGui::FillWidth();
|
||||||
if (ImGui::Combo(("##pager_decoder_pocsag_br_" + name).c_str(), &brId, baudrates.txt)) {
|
if (ImGui::Combo(("##pager_decoder_pocsag_br_" + name).c_str(), &brId, baudrates.txt)) {
|
||||||
setBaudrate(baudrates.value(brId));
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::FillWidth();
|
ImGui::FillWidth();
|
||||||
@ -79,8 +79,7 @@ private:
|
|||||||
static void _diagHandler(float* data, int count, void* ctx) {
|
static void _diagHandler(float* data, int count, void* ctx) {
|
||||||
POCSAGDecoder* _this = (POCSAGDecoder*)ctx;
|
POCSAGDecoder* _this = (POCSAGDecoder*)ctx;
|
||||||
float* buf = _this->diag.acquireBuffer();
|
float* buf = _this->diag.acquireBuffer();
|
||||||
int maxCount = std::min<int>(count, _this->diag.getCount());
|
memcpy(buf, data, count * sizeof(float));
|
||||||
memcpy(buf, data, maxCount * sizeof(float));
|
|
||||||
_this->diag.releaseBuffer();
|
_this->diag.releaseBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,15 +87,6 @@ private:
|
|||||||
flog::debug("[{}]: '{}'", (uint32_t)addr, msg);
|
flog::debug("[{}]: '{}'", (uint32_t)addr, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBaudrate(double baudrate) {
|
|
||||||
vfo->setSampleRate(baudrate*10.0, 12500);
|
|
||||||
stop();
|
|
||||||
reshape.setKeep(baudrate);
|
|
||||||
reshape.setSkip((baudrate / 30.0) - baudrate);
|
|
||||||
diag.setCount(baudrate);
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
VFOManager::VFO* vfo;
|
VFOManager::VFO* vfo;
|
||||||
|
|
||||||
@ -110,7 +100,6 @@ private:
|
|||||||
ImGui::SymbolDiagram diag;
|
ImGui::SymbolDiagram diag;
|
||||||
|
|
||||||
int brId = 2;
|
int brId = 2;
|
||||||
double baudrate = 2400;
|
|
||||||
|
|
||||||
OptionList<int, int> baudrates;
|
OptionList<int, int> baudrates;
|
||||||
};
|
};
|
@ -24,13 +24,12 @@ namespace demod {
|
|||||||
class Demodulator {
|
class Demodulator {
|
||||||
public:
|
public:
|
||||||
virtual ~Demodulator() {}
|
virtual ~Demodulator() {}
|
||||||
virtual void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) = 0;
|
virtual void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) = 0;
|
||||||
virtual void start() = 0;
|
virtual void start() = 0;
|
||||||
virtual void stop() = 0;
|
virtual void stop() = 0;
|
||||||
virtual void showMenu() = 0;
|
virtual void showMenu() = 0;
|
||||||
virtual void setBandwidth(double bandwidth) = 0;
|
virtual void setBandwidth(double bandwidth) = 0;
|
||||||
virtual void setInput(dsp::stream<dsp::complex_t>* input) = 0;
|
virtual void setInput(dsp::stream<dsp::complex_t>* input) = 0;
|
||||||
virtual void AFSampRateChanged(double newSR) = 0;
|
|
||||||
virtual const char* getName() = 0;
|
virtual const char* getName() = 0;
|
||||||
virtual double getIFSampleRate() = 0;
|
virtual double getIFSampleRate() = 0;
|
||||||
virtual double getAFSampleRate() = 0;
|
virtual double getAFSampleRate() = 0;
|
||||||
|
@ -7,13 +7,13 @@ namespace demod {
|
|||||||
public:
|
public:
|
||||||
AM() {}
|
AM() {}
|
||||||
|
|
||||||
AM(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
AM(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
init(name, config, input, bandwidth, audioSR);
|
init(name, config, input, bandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
~AM() { stop(); }
|
~AM() { stop(); }
|
||||||
|
|
||||||
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
@ -68,8 +68,6 @@ namespace demod {
|
|||||||
|
|
||||||
void setInput(dsp::stream<dsp::complex_t>* input) { demod.setInput(input); }
|
void setInput(dsp::stream<dsp::complex_t>* input) { demod.setInput(input); }
|
||||||
|
|
||||||
void AFSampRateChanged(double newSR) {}
|
|
||||||
|
|
||||||
// ============= INFO =============
|
// ============= INFO =============
|
||||||
|
|
||||||
const char* getName() { return "AM"; }
|
const char* getName() { return "AM"; }
|
||||||
|
@ -7,15 +7,15 @@ namespace demod {
|
|||||||
public:
|
public:
|
||||||
CW() {}
|
CW() {}
|
||||||
|
|
||||||
CW(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
CW(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
init(name, config, input, bandwidth, audioSR);
|
init(name, config, input, bandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
~CW() {
|
~CW() {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
this->_config = config;
|
this->_config = config;
|
||||||
this->afbwChangeHandler = afbwChangeHandler;
|
this->afbwChangeHandler = afbwChangeHandler;
|
||||||
@ -74,8 +74,6 @@ namespace demod {
|
|||||||
|
|
||||||
void setInput(dsp::stream<dsp::complex_t>* input) { demod.setInput(input); }
|
void setInput(dsp::stream<dsp::complex_t>* input) { demod.setInput(input); }
|
||||||
|
|
||||||
void AFSampRateChanged(double newSR) {}
|
|
||||||
|
|
||||||
// ============= INFO =============
|
// ============= INFO =============
|
||||||
|
|
||||||
const char* getName() { return "CW"; }
|
const char* getName() { return "CW"; }
|
||||||
|
@ -7,15 +7,15 @@ namespace demod {
|
|||||||
public:
|
public:
|
||||||
DSB() {}
|
DSB() {}
|
||||||
|
|
||||||
DSB(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
DSB(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
init(name, config, input, bandwidth, audioSR);
|
init(name, config, input, bandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
~DSB() {
|
~DSB() {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
@ -61,8 +61,6 @@ namespace demod {
|
|||||||
|
|
||||||
void setInput(dsp::stream<dsp::complex_t>* input) { demod.setInput(input); }
|
void setInput(dsp::stream<dsp::complex_t>* input) { demod.setInput(input); }
|
||||||
|
|
||||||
void AFSampRateChanged(double newSR) {}
|
|
||||||
|
|
||||||
// ============= INFO =============
|
// ============= INFO =============
|
||||||
|
|
||||||
const char* getName() { return "DSB"; }
|
const char* getName() { return "DSB"; }
|
||||||
|
@ -7,15 +7,15 @@ namespace demod {
|
|||||||
public:
|
public:
|
||||||
LSB() {}
|
LSB() {}
|
||||||
|
|
||||||
LSB(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
LSB(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
init(name, config, input, bandwidth, audioSR);
|
init(name, config, input, bandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
~LSB() {
|
~LSB() {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
@ -61,8 +61,6 @@ namespace demod {
|
|||||||
|
|
||||||
void setInput(dsp::stream<dsp::complex_t>* input) { demod.setInput(input); }
|
void setInput(dsp::stream<dsp::complex_t>* input) { demod.setInput(input); }
|
||||||
|
|
||||||
void AFSampRateChanged(double newSR) {}
|
|
||||||
|
|
||||||
// ============= INFO =============
|
// ============= INFO =============
|
||||||
|
|
||||||
const char* getName() { return "LSB"; }
|
const char* getName() { return "LSB"; }
|
||||||
|
@ -7,13 +7,13 @@ namespace demod {
|
|||||||
public:
|
public:
|
||||||
NFM() {}
|
NFM() {}
|
||||||
|
|
||||||
NFM(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
NFM(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
init(name, config, input, bandwidth, audioSR);
|
init(name, config, input, bandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
~NFM() { stop(); }
|
~NFM() { stop(); }
|
||||||
|
|
||||||
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
this->_config = config;
|
this->_config = config;
|
||||||
|
|
||||||
@ -57,8 +57,6 @@ namespace demod {
|
|||||||
|
|
||||||
void setInput(dsp::stream<dsp::complex_t>* input) { demod.setInput(input); }
|
void setInput(dsp::stream<dsp::complex_t>* input) { demod.setInput(input); }
|
||||||
|
|
||||||
void AFSampRateChanged(double newSR) {}
|
|
||||||
|
|
||||||
// ============= INFO =============
|
// ============= INFO =============
|
||||||
|
|
||||||
const char* getName() { return "FM"; }
|
const char* getName() { return "FM"; }
|
||||||
|
@ -7,17 +7,18 @@ namespace demod {
|
|||||||
public:
|
public:
|
||||||
RAW() {}
|
RAW() {}
|
||||||
|
|
||||||
RAW(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
RAW(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
init(name, config, input, bandwidth, audioSR);
|
init(name, config, input, bandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
~RAW() {
|
~RAW() {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
audioSampleRate = audioSR;
|
audioSampleRate = 48000;
|
||||||
|
// TODO: This needs to be selectable
|
||||||
|
|
||||||
// Define structure
|
// Define structure
|
||||||
c2s.init(input);
|
c2s.init(input);
|
||||||
@ -39,10 +40,6 @@ namespace demod {
|
|||||||
c2s.setInput(input);
|
c2s.setInput(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AFSampRateChanged(double newSR) {
|
|
||||||
audioSampleRate = newSR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============= INFO =============
|
// ============= INFO =============
|
||||||
|
|
||||||
const char* getName() { return "RAW"; }
|
const char* getName() { return "RAW"; }
|
||||||
|
@ -8,15 +8,15 @@ namespace demod {
|
|||||||
public:
|
public:
|
||||||
USB() {}
|
USB() {}
|
||||||
|
|
||||||
USB(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
USB(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
init(name, config, input, bandwidth, audioSR);
|
init(name, config, input, bandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
~USB() {
|
~USB() {
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
@ -62,8 +62,6 @@ namespace demod {
|
|||||||
|
|
||||||
void setInput(dsp::stream<dsp::complex_t>* input) { demod.setInput(input); }
|
void setInput(dsp::stream<dsp::complex_t>* input) { demod.setInput(input); }
|
||||||
|
|
||||||
void AFSampRateChanged(double newSR) {}
|
|
||||||
|
|
||||||
// ============= INFO =============
|
// ============= INFO =============
|
||||||
|
|
||||||
const char* getName() { return "USB"; }
|
const char* getName() { return "USB"; }
|
||||||
|
@ -16,8 +16,8 @@ namespace demod {
|
|||||||
public:
|
public:
|
||||||
WFM() : diag(0.5, 4096) {}
|
WFM() : diag(0.5, 4096) {}
|
||||||
|
|
||||||
WFM(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) : diag(0.5, 4096) {
|
WFM(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) : diag(0.5, 4096) {
|
||||||
init(name, config, input, bandwidth, audioSR);
|
init(name, config, input, bandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
~WFM() {
|
~WFM() {
|
||||||
@ -25,7 +25,7 @@ namespace demod {
|
|||||||
gui::waterfall.onFFTRedraw.unbindHandler(&fftRedrawHandler);
|
gui::waterfall.onFFTRedraw.unbindHandler(&fftRedrawHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth, double audioSR) {
|
void init(std::string name, ConfigManager* config, dsp::stream<dsp::complex_t>* input, double bandwidth) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
@ -252,8 +252,6 @@ namespace demod {
|
|||||||
demod.setInput(input);
|
demod.setInput(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AFSampRateChanged(double newSR) {}
|
|
||||||
|
|
||||||
// ============= INFO =============
|
// ============= INFO =============
|
||||||
|
|
||||||
const char* getName() { return "WFM"; }
|
const char* getName() { return "WFM"; }
|
||||||
|
@ -81,30 +81,16 @@ public:
|
|||||||
// Initialize audio DSP chain
|
// Initialize audio DSP chain
|
||||||
afChain.init(&dummyAudioStream);
|
afChain.init(&dummyAudioStream);
|
||||||
|
|
||||||
resamp.init(NULL, 250000.0, 48000.0);
|
|
||||||
deemp.init(NULL, 50e-6, 48000.0);
|
deemp.init(NULL, 50e-6, 48000.0);
|
||||||
|
|
||||||
afChain.addBlock(&resamp, true);
|
|
||||||
afChain.addBlock(&deemp, false);
|
afChain.addBlock(&deemp, false);
|
||||||
|
|
||||||
// Initialize the sink
|
// Initialize the sink
|
||||||
srChangeHandler.ctx = this;
|
stream = sigpath::streamManager.createStream(name, afChain.out, 48000);
|
||||||
srChangeHandler.handler = sampleRateChangeHandler;
|
|
||||||
stream.init(afChain.out, &srChangeHandler, audioSampleRate);
|
|
||||||
sigpath::sinkManager.registerStream(name, &stream);
|
|
||||||
|
|
||||||
// Select the demodulator
|
// Select the demodulator
|
||||||
selectDemodByID((DemodID)selectedDemodID);
|
selectDemodByID((DemodID)selectedDemodID);
|
||||||
|
|
||||||
// Start IF chain
|
|
||||||
ifChain.start();
|
|
||||||
|
|
||||||
// Start AF chain
|
|
||||||
afChain.start();
|
|
||||||
|
|
||||||
// Start stream, the rest was started when selecting the demodulator
|
|
||||||
stream.start();
|
|
||||||
|
|
||||||
// Register the menu
|
// Register the menu
|
||||||
gui::menu.registerEntry(name, menuHandler, this, this);
|
gui::menu.registerEntry(name, menuHandler, this, this);
|
||||||
|
|
||||||
@ -115,11 +101,10 @@ public:
|
|||||||
~RadioModule() {
|
~RadioModule() {
|
||||||
core::modComManager.unregisterInterface(name);
|
core::modComManager.unregisterInterface(name);
|
||||||
gui::menu.removeEntry(name);
|
gui::menu.removeEntry(name);
|
||||||
stream.stop();
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
disable();
|
disable();
|
||||||
}
|
}
|
||||||
sigpath::sinkManager.unregisterStream(name);
|
sigpath::streamManager.destroyStream(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void postInit() {}
|
void postInit() {}
|
||||||
@ -131,9 +116,7 @@ public:
|
|||||||
vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler);
|
vfo->wtfVFO->onUserChangedBandwidth.bindHandler(&onUserChangedBandwidthHandler);
|
||||||
}
|
}
|
||||||
ifChain.setInput(vfo->output, [=](dsp::stream<dsp::complex_t>* out){ ifChainOutputChangeHandler(out, this); });
|
ifChain.setInput(vfo->output, [=](dsp::stream<dsp::complex_t>* out){ ifChainOutputChangeHandler(out, this); });
|
||||||
ifChain.start();
|
|
||||||
selectDemodByID((DemodID)selectedDemodID);
|
selectDemodByID((DemodID)selectedDemodID);
|
||||||
afChain.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable() {
|
void disable() {
|
||||||
@ -141,6 +124,7 @@ public:
|
|||||||
ifChain.stop();
|
ifChain.stop();
|
||||||
if (selectedDemod) { selectedDemod->stop(); }
|
if (selectedDemod) { selectedDemod->stop(); }
|
||||||
afChain.stop();
|
afChain.stop();
|
||||||
|
stream->stopDSP();
|
||||||
if (vfo) { sigpath::vfoManager.deleteVFO(vfo); }
|
if (vfo) { sigpath::vfoManager.deleteVFO(vfo); }
|
||||||
vfo = NULL;
|
vfo = NULL;
|
||||||
}
|
}
|
||||||
@ -313,7 +297,7 @@ private:
|
|||||||
bw = std::clamp<double>(bw, demod->getMinBandwidth(), demod->getMaxBandwidth());
|
bw = std::clamp<double>(bw, demod->getMinBandwidth(), demod->getMaxBandwidth());
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
demod->init(name, &config, ifChain.out, bw, stream.getSampleRate());
|
demod->init(name, &config, ifChain.out, bw);
|
||||||
|
|
||||||
return demod;
|
return demod;
|
||||||
}
|
}
|
||||||
@ -337,22 +321,34 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void selectDemod(demod::Demodulator* demod) {
|
void selectDemod(demod::Demodulator* demod) {
|
||||||
// Stopcurrently selected demodulator and select new
|
// Stop the IF chain
|
||||||
afChain.setInput(&dummyAudioStream, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
ifChain.stop();
|
||||||
|
|
||||||
|
// Stop the current demodulator
|
||||||
if (selectedDemod) {
|
if (selectedDemod) {
|
||||||
selectedDemod->stop();
|
selectedDemod->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop AF chain
|
||||||
|
afChain.stop();
|
||||||
|
|
||||||
|
// Stop audio stream's DSP
|
||||||
|
stream->stopDSP();
|
||||||
|
|
||||||
|
// Destroy the old demodulator
|
||||||
|
afChain.setInput(&dummyAudioStream, [=](dsp::stream<dsp::stereo_t>* out){ stream->setInput(out); });
|
||||||
|
if (selectedDemod) {
|
||||||
delete selectedDemod;
|
delete selectedDemod;
|
||||||
}
|
}
|
||||||
selectedDemod = demod;
|
|
||||||
|
|
||||||
// Give the demodulator the most recent audio SR
|
// Select the new demodulator
|
||||||
selectedDemod->AFSampRateChanged(audioSampleRate);
|
selectedDemod = demod;
|
||||||
|
|
||||||
// Set the demodulator's input
|
// Set the demodulator's input
|
||||||
selectedDemod->setInput(ifChain.out);
|
selectedDemod->setInput(ifChain.out);
|
||||||
|
|
||||||
// Set AF chain's input
|
// Set AF chain's input
|
||||||
afChain.setInput(selectedDemod->getOutput(), [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
afChain.setInput(selectedDemod->getOutput(), [=](dsp::stream<dsp::stereo_t>* out){ stream->setInput(out); });
|
||||||
|
|
||||||
// Load config
|
// Load config
|
||||||
bandwidth = selectedDemod->getDefaultBandwidth();
|
bandwidth = selectedDemod->getDefaultBandwidth();
|
||||||
@ -440,21 +436,30 @@ private:
|
|||||||
// Configure AF chain
|
// Configure AF chain
|
||||||
if (postProcEnabled) {
|
if (postProcEnabled) {
|
||||||
// Configure resampler
|
// Configure resampler
|
||||||
afChain.stop();
|
deemp.setSamplerate(selectedDemod->getAFSampleRate());
|
||||||
resamp.setInSamplerate(selectedDemod->getAFSampleRate());
|
|
||||||
setAudioSampleRate(audioSampleRate);
|
|
||||||
afChain.enableBlock(&resamp, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
|
||||||
|
|
||||||
// Configure deemphasis
|
// Configure deemphasis
|
||||||
setDeemphasisMode(deempModes[deempId]);
|
setDeemphasisMode(deempModes[deempId]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Disable everything if post processing is disabled
|
// Disable everything if post processing is disabled
|
||||||
afChain.disableAllBlocks([=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
afChain.disableAllBlocks([=](dsp::stream<dsp::stereo_t>* out){ stream->setInput(out); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update audo samplerate
|
||||||
|
stream->setSamplerate(selectedDemod->getAFSampleRate());
|
||||||
|
|
||||||
|
// Start the IF chain
|
||||||
|
ifChain.start();
|
||||||
|
|
||||||
// Start new demodulator
|
// Start new demodulator
|
||||||
selectedDemod->start();
|
selectedDemod->start();
|
||||||
|
|
||||||
|
// Start the AF chain
|
||||||
|
afChain.start();
|
||||||
|
|
||||||
|
// Start the audio stream
|
||||||
|
stream->startDSP();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -470,37 +475,12 @@ private:
|
|||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAudioSampleRate(double sr) {
|
|
||||||
audioSampleRate = sr;
|
|
||||||
if (!selectedDemod) { return; }
|
|
||||||
selectedDemod->AFSampRateChanged(audioSampleRate);
|
|
||||||
if (!postProcEnabled && vfo) {
|
|
||||||
// If postproc is disabled, IF SR = AF SR
|
|
||||||
minBandwidth = selectedDemod->getMinBandwidth();
|
|
||||||
maxBandwidth = selectedDemod->getMaxBandwidth();
|
|
||||||
bandwidth = selectedDemod->getIFSampleRate();
|
|
||||||
vfo->setBandwidthLimits(minBandwidth, maxBandwidth, selectedDemod->getBandwidthLocked());
|
|
||||||
vfo->setSampleRate(selectedDemod->getIFSampleRate(), bandwidth);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
afChain.stop();
|
|
||||||
|
|
||||||
// Configure resampler
|
|
||||||
resamp.setOutSamplerate(audioSampleRate);
|
|
||||||
|
|
||||||
// Configure deemphasis sample rate
|
|
||||||
deemp.setSamplerate(audioSampleRate);
|
|
||||||
|
|
||||||
afChain.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDeemphasisMode(DeemphasisMode mode) {
|
void setDeemphasisMode(DeemphasisMode mode) {
|
||||||
deempId = deempModes.valueId(mode);
|
deempId = deempModes.valueId(mode);
|
||||||
if (!postProcEnabled || !selectedDemod) { return; }
|
if (!postProcEnabled || !selectedDemod) { return; }
|
||||||
bool deempEnabled = (mode != DEEMP_MODE_NONE);
|
bool deempEnabled = (mode != DEEMP_MODE_NONE);
|
||||||
if (deempEnabled) { deemp.setTau(deempTaus[mode]); }
|
if (deempEnabled) { deemp.setTau(deempTaus[mode]); }
|
||||||
afChain.setBlockEnabled(&deemp, deempEnabled, [=](dsp::stream<dsp::stereo_t>* out){ stream.setInput(out); });
|
afChain.setBlockEnabled(&deemp, deempEnabled, [=](dsp::stream<dsp::stereo_t>* out){ stream->setInput(out); });
|
||||||
|
|
||||||
// Save config
|
// Save config
|
||||||
config.acquire();
|
config.acquire();
|
||||||
@ -584,11 +564,6 @@ private:
|
|||||||
_this->setBandwidth(newBw);
|
_this->setBandwidth(newBw);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sampleRateChangeHandler(float sampleRate, void* ctx) {
|
|
||||||
RadioModule* _this = (RadioModule*)ctx;
|
|
||||||
_this->setAudioSampleRate(sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ifChainOutputChangeHandler(dsp::stream<dsp::complex_t>* output, void* ctx) {
|
static void ifChainOutputChangeHandler(dsp::stream<dsp::complex_t>* output, void* ctx) {
|
||||||
RadioModule* _this = (RadioModule*)ctx;
|
RadioModule* _this = (RadioModule*)ctx;
|
||||||
if (!_this->selectedDemod) { return; }
|
if (!_this->selectedDemod) { return; }
|
||||||
@ -597,16 +572,14 @@ private:
|
|||||||
|
|
||||||
static void moduleInterfaceHandler(int code, void* in, void* out, void* ctx) {
|
static void moduleInterfaceHandler(int code, void* in, void* out, void* ctx) {
|
||||||
RadioModule* _this = (RadioModule*)ctx;
|
RadioModule* _this = (RadioModule*)ctx;
|
||||||
|
if (!_this->enabled || !_this->selectedDemod) { return; }
|
||||||
// If no demod is selected, reject the command
|
|
||||||
if (!_this->selectedDemod) { return; }
|
|
||||||
|
|
||||||
// Execute commands
|
// Execute commands
|
||||||
if (code == RADIO_IFACE_CMD_GET_MODE && out) {
|
if (code == RADIO_IFACE_CMD_GET_MODE && out) {
|
||||||
int* _out = (int*)out;
|
int* _out = (int*)out;
|
||||||
*_out = _this->selectedDemodID;
|
*_out = _this->selectedDemodID;
|
||||||
}
|
}
|
||||||
else if (code == RADIO_IFACE_CMD_SET_MODE && in && _this->enabled) {
|
else if (code == RADIO_IFACE_CMD_SET_MODE && in) {
|
||||||
int* _in = (int*)in;
|
int* _in = (int*)in;
|
||||||
_this->selectDemodByID((DemodID)*_in);
|
_this->selectDemodByID((DemodID)*_in);
|
||||||
}
|
}
|
||||||
@ -614,7 +587,7 @@ private:
|
|||||||
float* _out = (float*)out;
|
float* _out = (float*)out;
|
||||||
*_out = _this->bandwidth;
|
*_out = _this->bandwidth;
|
||||||
}
|
}
|
||||||
else if (code == RADIO_IFACE_CMD_SET_BANDWIDTH && in && _this->enabled) {
|
else if (code == RADIO_IFACE_CMD_SET_BANDWIDTH && in) {
|
||||||
float* _in = (float*)in;
|
float* _in = (float*)in;
|
||||||
if (_this->bandwidthLocked) { return; }
|
if (_this->bandwidthLocked) { return; }
|
||||||
_this->setBandwidth(*_in);
|
_this->setBandwidth(*_in);
|
||||||
@ -623,7 +596,7 @@ private:
|
|||||||
bool* _out = (bool*)out;
|
bool* _out = (bool*)out;
|
||||||
*_out = _this->squelchEnabled;
|
*_out = _this->squelchEnabled;
|
||||||
}
|
}
|
||||||
else if (code == RADIO_IFACE_CMD_SET_SQUELCH_ENABLED && in && _this->enabled) {
|
else if (code == RADIO_IFACE_CMD_SET_SQUELCH_ENABLED && in) {
|
||||||
bool* _in = (bool*)in;
|
bool* _in = (bool*)in;
|
||||||
_this->setSquelchEnabled(*_in);
|
_this->setSquelchEnabled(*_in);
|
||||||
}
|
}
|
||||||
@ -631,7 +604,7 @@ private:
|
|||||||
float* _out = (float*)out;
|
float* _out = (float*)out;
|
||||||
*_out = _this->squelchLevel;
|
*_out = _this->squelchLevel;
|
||||||
}
|
}
|
||||||
else if (code == RADIO_IFACE_CMD_SET_SQUELCH_LEVEL && in && _this->enabled) {
|
else if (code == RADIO_IFACE_CMD_SET_SQUELCH_LEVEL && in) {
|
||||||
float* _in = (float*)in;
|
float* _in = (float*)in;
|
||||||
_this->setSquelchLevel(*_in);
|
_this->setSquelchLevel(*_in);
|
||||||
}
|
}
|
||||||
@ -645,7 +618,6 @@ private:
|
|||||||
|
|
||||||
// Handlers
|
// Handlers
|
||||||
EventHandler<double> onUserChangedBandwidthHandler;
|
EventHandler<double> onUserChangedBandwidthHandler;
|
||||||
EventHandler<float> srChangeHandler;
|
|
||||||
EventHandler<dsp::stream<dsp::complex_t>*> ifChainOutputChanged;
|
EventHandler<dsp::stream<dsp::complex_t>*> ifChainOutputChanged;
|
||||||
EventHandler<dsp::stream<dsp::stereo_t>*> afChainOutputChanged;
|
EventHandler<dsp::stream<dsp::stereo_t>*> afChainOutputChanged;
|
||||||
|
|
||||||
@ -660,10 +632,9 @@ private:
|
|||||||
// Audio chain
|
// Audio chain
|
||||||
dsp::stream<dsp::stereo_t> dummyAudioStream;
|
dsp::stream<dsp::stereo_t> dummyAudioStream;
|
||||||
dsp::chain<dsp::stereo_t> afChain;
|
dsp::chain<dsp::stereo_t> afChain;
|
||||||
dsp::multirate::RationalResampler<dsp::stereo_t> resamp;
|
|
||||||
dsp::filter::Deemphasis<dsp::stereo_t> deemp;
|
dsp::filter::Deemphasis<dsp::stereo_t> deemp;
|
||||||
|
|
||||||
SinkManager::Stream stream;
|
std::shared_ptr<MasterStream> stream;
|
||||||
|
|
||||||
demod::Demodulator* selectedDemod = NULL;
|
demod::Demodulator* selectedDemod = NULL;
|
||||||
|
|
||||||
|
@ -9,10 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev
|
|||||||
libcodec2-dev autoconf libtool xxd
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
7z x ./SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
7z x ./SDRplay_RSP_API-Linux-3.14.0
|
||||||
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.14 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
|
@ -9,10 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev
|
|||||||
libcodec2-dev autoconf libtool xxd
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
7z x ./SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
7z x ./SDRplay_RSP_API-Linux-3.14.0
|
||||||
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.14 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
|
@ -9,10 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk1-dev
|
|||||||
libcodec2-dev autoconf libtool xxd
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
7z x ./SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
7z x ./SDRplay_RSP_API-Linux-3.14.0
|
||||||
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.14 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
|
@ -9,10 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk-dev l
|
|||||||
libcodec2-dev autoconf libtool xxd
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
7z x ./SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
7z x ./SDRplay_RSP_API-Linux-3.14.0
|
||||||
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.14 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
|
@ -15,10 +15,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk1-dev
|
|||||||
libcodec2-dev libudev-dev autoconf libtool xxd
|
libcodec2-dev libudev-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
7z x ./SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
7z x ./SDRplay_RSP_API-Linux-3.14.0
|
||||||
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.14 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install a more recent libusb version
|
# Install a more recent libusb version
|
||||||
@ -71,4 +71,4 @@ make VERBOSE=1 -j2
|
|||||||
|
|
||||||
# Generate package
|
# Generate package
|
||||||
cd ..
|
cd ..
|
||||||
sh make_debian_package.sh ./build 'libfftw3-bin, libglfw3, libvolk1-bin, librtaudio6, libzstd1'
|
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk1-dev, librtaudio-dev, libzstd-dev'
|
@ -9,10 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev
|
|||||||
libcodec2-dev autoconf libtool xxd
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
7z x ./SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
7z x ./SDRplay_RSP_API-Linux-3.14.0
|
||||||
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.14 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
@ -32,4 +32,4 @@ cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD
|
|||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
sh make_debian_package.sh ./build 'libfftw3-bin, libglfw3, libvolk2-bin, librtaudio6, libzstd1'
|
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk2-dev, librtaudio-dev, libzstd-dev'
|
@ -9,10 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk2-dev
|
|||||||
libcodec2-dev autoconf libtool xxd
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
7z x ./SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
7z x ./SDRplay_RSP_API-Linux-3.14.0
|
||||||
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.14 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
@ -32,4 +32,4 @@ cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD
|
|||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
sh make_debian_package.sh ./build 'libfftw3-bin, libglfw3, libvolk2-bin, librtaudio6, libzstd1'
|
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk2-dev, librtaudio-dev, libzstd-dev'
|
@ -9,10 +9,10 @@ apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk-dev l
|
|||||||
libcodec2-dev autoconf libtool xxd
|
libcodec2-dev autoconf libtool xxd
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
# Install SDRPlay libraries
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
7z x ./SDRplay_RSP_API-Linux-3.14.0.run
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
7z x ./SDRplay_RSP_API-Linux-3.14.0
|
||||||
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
cp x86_64/libsdrplay_api.so.3.14 /usr/lib/libsdrplay_api.so
|
||||||
cp inc/* /usr/include/
|
cp inc/* /usr/include/
|
||||||
|
|
||||||
# Install libperseus
|
# Install libperseus
|
||||||
@ -32,4 +32,4 @@ cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD
|
|||||||
make VERBOSE=1 -j2
|
make VERBOSE=1 -j2
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
sh make_debian_package.sh ./build 'libfftw3-bin, libglfw3, libvolk-bin, librtaudio6, libzstd1'
|
sh make_debian_package.sh ./build 'libfftw3-dev, libglfw3-dev, libvolk-dev, librtaudio-dev, libzstd-dev'
|
@ -1,4 +0,0 @@
|
|||||||
FROM ubuntu:noble
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
COPY do_build.sh /root
|
|
||||||
RUN chmod +x /root/do_build.sh
|
|
@ -1,35 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
cd /root
|
|
||||||
|
|
||||||
# Install dependencies and tools
|
|
||||||
apt update
|
|
||||||
apt install -y build-essential cmake git libfftw3-dev libglfw3-dev libvolk-dev libzstd-dev libairspyhf-dev libairspy-dev \
|
|
||||||
libiio-dev libad9361-dev librtaudio-dev libhackrf-dev librtlsdr-dev libbladerf-dev liblimesuite-dev p7zip-full wget portaudio19-dev \
|
|
||||||
libcodec2-dev autoconf libtool xxd
|
|
||||||
|
|
||||||
# Install SDRPlay libraries
|
|
||||||
wget https://www.sdrplay.com/software/SDRplay_RSP_API-Linux-3.15.1.run
|
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1.run
|
|
||||||
7z x ./SDRplay_RSP_API-Linux-3.15.1
|
|
||||||
cp x86_64/libsdrplay_api.so.3.15 /usr/lib/libsdrplay_api.so
|
|
||||||
cp inc/* /usr/include/
|
|
||||||
|
|
||||||
# Install libperseus
|
|
||||||
git clone https://github.com/Microtelecom/libperseus-sdr
|
|
||||||
cd libperseus-sdr
|
|
||||||
autoreconf -i
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
ldconfig
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
cd SDRPlusPlus
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake .. -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DOPT_BUILD_PERSEUS_SOURCE=ON
|
|
||||||
make VERBOSE=1 -j2
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
sh make_debian_package.sh ./build 'libfftw3-bin, libglfw3, libvolk-bin, librtaudio6, libzstd1'
|
|
@ -8,7 +8,7 @@ mkdir sdrpp_debian_amd64/DEBIAN
|
|||||||
# Create package info
|
# Create package info
|
||||||
echo Create package info
|
echo Create package info
|
||||||
echo Package: sdrpp >> sdrpp_debian_amd64/DEBIAN/control
|
echo Package: sdrpp >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
echo Version: 1.2.0$BUILD_NO >> sdrpp_debian_amd64/DEBIAN/control
|
echo Version: 1.1.0$BUILD_NO >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
echo Maintainer: Ryzerth >> sdrpp_debian_amd64/DEBIAN/control
|
echo Maintainer: Ryzerth >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
echo Architecture: all >> 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
|
echo Description: Bloat-free SDR receiver software >> sdrpp_debian_amd64/DEBIAN/control
|
||||||
|
@ -22,7 +22,7 @@ cp -R root/res/* $BUNDLE/Contents/Resources/
|
|||||||
bundle_create_icns root/res/icons/sdrpp.macos.png $BUNDLE/Contents/Resources/sdrpp
|
bundle_create_icns root/res/icons/sdrpp.macos.png $BUNDLE/Contents/Resources/sdrpp
|
||||||
|
|
||||||
# Create the property list
|
# Create the property list
|
||||||
bundle_create_plist sdrpp SDR++ org.sdrpp.sdrpp 1.2.0 sdrp sdrpp sdrpp $BUNDLE/Contents/Info.plist
|
bundle_create_plist sdrpp SDR++ org.sdrpp.sdrpp 1.1.0 sdrp sdrpp sdrpp $BUNDLE/Contents/Info.plist
|
||||||
|
|
||||||
# ========================= Install binaries =========================
|
# ========================= Install binaries =========================
|
||||||
|
|
||||||
|
@ -7,86 +7,85 @@ mkdir sdrpp_windows_x64
|
|||||||
cp -Recurse $root_dir/* sdrpp_windows_x64/
|
cp -Recurse $root_dir/* sdrpp_windows_x64/
|
||||||
|
|
||||||
# Copy core
|
# Copy core
|
||||||
cp $build_dir/Debug/* sdrpp_windows_x64/
|
cp $build_dir/Release/* sdrpp_windows_x64/
|
||||||
cp $build_dir/core/Debug/sdrpp_core.pdb sdrpp_windows_x64/
|
|
||||||
cp 'C:/Program Files/PothosSDR/bin/volk.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/volk.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
# Copy source modules
|
# Copy source modules
|
||||||
cp $build_dir/source_modules/airspy_source/Debug/airspy_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/airspy_source/Release/airspy_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/airspy.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/airspy.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/airspyhf_source/Debug/airspyhf_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/airspyhf_source/Release/airspyhf_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/airspyhf.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/airspyhf.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/audio_source/Debug/audio_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/audio_source/Release/audio_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/bladerf_source/Debug/bladerf_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/bladerf_source/Release/bladerf_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/bladeRF.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/bladeRF.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/file_source/Debug/file_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/file_source/Release/file_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/hackrf_source/Debug/hackrf_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/hackrf_source/Release/hackrf_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/hackrf.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/hackrf.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/hermes_source/Debug/hermes_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/hermes_source/Release/hermes_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/limesdr_source/Debug/limesdr_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/limesdr_source/Release/limesdr_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/LimeSuite.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/LimeSuite.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/perseus_source/Debug/perseus_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/perseus_source/Release/perseus_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/perseus-sdr.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/perseus-sdr.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/plutosdr_source/Debug/plutosdr_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/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/libiio.dll' sdrpp_windows_x64/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/libad9361.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/libad9361.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/rfspace_source/Debug/rfspace_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/rfspace_source/Release/rfspace_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/rtl_sdr_source/Debug/rtl_sdr_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/rtl_sdr_source/Release/rtl_sdr_source.dll sdrpp_windows_x64/modules/
|
||||||
cp 'C:/Program Files/PothosSDR/bin/rtlsdr.dll' sdrpp_windows_x64/
|
cp 'C:/Program Files/PothosSDR/bin/rtlsdr.dll' sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/source_modules/rtl_tcp_source/Debug/rtl_tcp_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/rtl_tcp_source/Release/rtl_tcp_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/sdrplay_source/Debug/sdrplay_source.dll sdrpp_windows_x64/modules/ -ErrorAction SilentlyContinue
|
cp $build_dir/source_modules/sdrplay_source/Release/sdrplay_source.dll sdrpp_windows_x64/modules/ -ErrorAction SilentlyContinue
|
||||||
cp 'C:/Program Files/SDRplay/API/x64/sdrplay_api.dll' sdrpp_windows_x64/ -ErrorAction SilentlyContinue
|
cp 'C:/Program Files/SDRplay/API/x64/sdrplay_api.dll' sdrpp_windows_x64/ -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
cp $build_dir/source_modules/sdrpp_server_source/Debug/sdrpp_server_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/sdrpp_server_source/Release/sdrpp_server_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/source_modules/spyserver_source/Debug/spyserver_source.dll sdrpp_windows_x64/modules/
|
cp $build_dir/source_modules/spyserver_source/Release/spyserver_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
# cp $build_dir/source_modules/usrp_source/Debug/usrp_source.dll sdrpp_windows_x64/modules/
|
# cp $build_dir/source_modules/usrp_source/Release/usrp_source.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
|
|
||||||
# Copy sink modules
|
# Copy sink modules
|
||||||
cp $build_dir/sink_modules/audio_sink/Debug/audio_sink.dll sdrpp_windows_x64/modules/
|
cp $build_dir/sink_modules/audio_sink/Release/audio_sink.dll sdrpp_windows_x64/modules/
|
||||||
cp "C:/Program Files (x86)/RtAudio/bin/rtaudio.dll" sdrpp_windows_x64/
|
cp "C:/Program Files (x86)/RtAudio/bin/rtaudio.dll" sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/sink_modules/network_sink/Debug/network_sink.dll sdrpp_windows_x64/modules/
|
cp $build_dir/sink_modules/network_sink/Release/network_sink.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
|
|
||||||
# Copy decoder modules
|
# Copy decoder modules
|
||||||
cp $build_dir/decoder_modules/m17_decoder/Debug/m17_decoder.dll sdrpp_windows_x64/modules/
|
cp $build_dir/decoder_modules/m17_decoder/Release/m17_decoder.dll sdrpp_windows_x64/modules/
|
||||||
cp "C:/Program Files/codec2/lib/libcodec2.dll" sdrpp_windows_x64/
|
cp "C:/Program Files/codec2/lib/libcodec2.dll" sdrpp_windows_x64/
|
||||||
|
|
||||||
cp $build_dir/decoder_modules/meteor_demodulator/Debug/meteor_demodulator.dll sdrpp_windows_x64/modules/
|
cp $build_dir/decoder_modules/meteor_demodulator/Release/meteor_demodulator.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/decoder_modules/radio/Debug/radio.dll sdrpp_windows_x64/modules/
|
cp $build_dir/decoder_modules/radio/Release/radio.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
|
|
||||||
# Copy misc modules
|
# Copy misc modules
|
||||||
cp $build_dir/misc_modules/discord_integration/Debug/discord_integration.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/discord_integration/Release/discord_integration.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/misc_modules/frequency_manager/Debug/frequency_manager.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/frequency_manager/Release/frequency_manager.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/misc_modules/iq_exporter/Debug/iq_exporter.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/iq_exporter/Release/iq_exporter.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/misc_modules/recorder/Debug/recorder.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/recorder/Release/recorder.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/misc_modules/rigctl_client/Debug/rigctl_client.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/rigctl_client/Release/rigctl_client.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/misc_modules/rigctl_server/Debug/rigctl_server.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/rigctl_server/Release/rigctl_server.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
cp $build_dir/misc_modules/scanner/Debug/scanner.dll sdrpp_windows_x64/modules/
|
cp $build_dir/misc_modules/scanner/Release/scanner.dll sdrpp_windows_x64/modules/
|
||||||
|
|
||||||
|
|
||||||
# Copy supporting libs
|
# Copy supporting libs
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
std::recursive_mutex mtx;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
std::lock_guard<std::recursive_mutex> lck(mtx);
|
|
||||||
|
|
||||||
printf("Works just fine!\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -476,9 +476,9 @@ private:
|
|||||||
sprintf(monStr, "%02d", ltm->tm_mon + 1);
|
sprintf(monStr, "%02d", ltm->tm_mon + 1);
|
||||||
sprintf(yearStr, "%02d", ltm->tm_year + 1900);
|
sprintf(yearStr, "%02d", ltm->tm_year + 1900);
|
||||||
if (core::modComManager.getModuleName(name) == "radio") {
|
if (core::modComManager.getModuleName(name) == "radio") {
|
||||||
int mode = -1;
|
int mode;
|
||||||
core::modComManager.callInterface(name, RADIO_IFACE_CMD_GET_MODE, NULL, &mode);
|
core::modComManager.callInterface(name, RADIO_IFACE_CMD_GET_MODE, NULL, &mode);
|
||||||
if (mode >= 0) { modeStr = radioModeToString[mode]; };
|
modeStr = radioModeToString[mode];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace in template
|
// Replace in template
|
||||||
|
@ -331,7 +331,6 @@ Modules in beta are still included in releases for the most part but not enabled
|
|||||||
| network_source | Unfinished | - | OPT_BUILD_NETWORK_SOURCE | ✅ | ✅ | ⛔ |
|
| network_source | Unfinished | - | OPT_BUILD_NETWORK_SOURCE | ✅ | ✅ | ⛔ |
|
||||||
| perseus_source | Beta | libperseus-sdr | OPT_BUILD_PERSEUS_SOURCE | ⛔ | ✅ | ✅ |
|
| perseus_source | Beta | libperseus-sdr | OPT_BUILD_PERSEUS_SOURCE | ⛔ | ✅ | ✅ |
|
||||||
| plutosdr_source | Working | libiio, libad9361 | OPT_BUILD_PLUTOSDR_SOURCE | ✅ | ✅ | ✅ |
|
| plutosdr_source | Working | libiio, libad9361 | OPT_BUILD_PLUTOSDR_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| rfnm_source | Beta | librfnm | OPT_BUILD_RFNM_SOURCE | ⛔ | ⛔ | ⛔ |
|
|
||||||
| rfspace_source | Working | - | OPT_BUILD_RFSPACE_SOURCE | ✅ | ✅ | ✅ |
|
| rfspace_source | Working | - | OPT_BUILD_RFSPACE_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| rtl_sdr_source | Working | librtlsdr | OPT_BUILD_RTL_SDR_SOURCE | ✅ | ✅ | ✅ |
|
| rtl_sdr_source | Working | librtlsdr | OPT_BUILD_RTL_SDR_SOURCE | ✅ | ✅ | ✅ |
|
||||||
| rtl_tcp_source | Working | - | OPT_BUILD_RTL_TCP_SOURCE | ✅ | ✅ | ✅ |
|
| rtl_tcp_source | Working | - | OPT_BUILD_RTL_TCP_SOURCE | ✅ | ✅ | ✅ |
|
||||||
|
@ -1,645 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Brazilian Ham Bands",
|
|
||||||
"country_name": "Brazil",
|
|
||||||
"country_code": "BR",
|
|
||||||
"author_name": "Rafael Beraldo",
|
|
||||||
"author_url": "https://github.com/rberaldo/",
|
|
||||||
"bands": [
|
|
||||||
{
|
|
||||||
"start": 135700,
|
|
||||||
"end": 137800,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "2200m Ham Band CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 472000,
|
|
||||||
"end": 479000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "635m Ham Band CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 1800000,
|
|
||||||
"end": 1810000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "|160m Ham Band CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 1810000,
|
|
||||||
"end": 1839000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 1839000,
|
|
||||||
"end": 1840000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 1840000,
|
|
||||||
"end": 1843000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSB, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 1843000,
|
|
||||||
"end": 1850000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, SSB"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 1850000,
|
|
||||||
"end": 2000000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSB, AM, DV, Digital 160 Ham Band|"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 3500000,
|
|
||||||
"end": 3570000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "|80m Ham Band CW"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 3570000,
|
|
||||||
"end": 3590000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 3590000,
|
|
||||||
"end": 3600000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, SSD, AM, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 3600000,
|
|
||||||
"end": 3775000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSD, AM, DV, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 3775000,
|
|
||||||
"end": 3875000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, SSD, DV, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 3775000,
|
|
||||||
"end": 3875000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSD, DV, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 3875000,
|
|
||||||
"end": 4000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, SSD, AM, DV, Digital, 80m Ham Band|"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 5351500,
|
|
||||||
"end": 5354000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "|60m Ham Band CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 5354000,
|
|
||||||
"end": 5366000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSB, DV, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 5366000,
|
|
||||||
"end": 5366500,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, Digital 60m Ham Band|"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 7000000,
|
|
||||||
"end": 7040000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "|40m Ham Band CW"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 7040000,
|
|
||||||
"end": 7047000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 7047000,
|
|
||||||
"end": 7050000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, SSB, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 7050000,
|
|
||||||
"end": 7100000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSB, DV, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 7100000,
|
|
||||||
"end": 7300000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, SSB, AM, DV, Digital 40m Ham Band|"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 10100000,
|
|
||||||
"end": 10130000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "|30m Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 10130000,
|
|
||||||
"end": 10150000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, Digital 30m Ham Band|"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 14000000,
|
|
||||||
"end": 14070000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "|20m Ham Band CW"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 14070000,
|
|
||||||
"end": 14099000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 14099000,
|
|
||||||
"end": 14101000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW IBP"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 14101000,
|
|
||||||
"end": 14282000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSB, DV, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 14285000,
|
|
||||||
"end": 14350000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, SSB, AM, DV, Digital 20m Ham Band|"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 18068000,
|
|
||||||
"end": 18095000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "|17m Ham Band CW"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 18095000,
|
|
||||||
"end": 18109000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 18109000,
|
|
||||||
"end": 18111000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW IBP"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 18111000,
|
|
||||||
"end": 18168000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSB, DV, Digital 17m Ham Band|"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 21000000,
|
|
||||||
"end": 21070000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "|15m Ham Band CW"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 21070000,
|
|
||||||
"end": 21149000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 21149000,
|
|
||||||
"end": 21151000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, IBP"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 21151000,
|
|
||||||
"end": 21380000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSB, DV, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 21380000,
|
|
||||||
"end": 21450000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, SSB, AM, DV, Digital 15m Ham Band|"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 24890000,
|
|
||||||
"end": 24915000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "|12m Ham Band CW"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 24915000,
|
|
||||||
"end": 24929000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 24929000,
|
|
||||||
"end": 24931000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW IBP"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 24931000,
|
|
||||||
"end": 24990000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSB, DV, Digital 12m Ham Band|"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 28000000,
|
|
||||||
"end": 28070000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "|10m Ham Band CW"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 28070000,
|
|
||||||
"end": 28190000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 28190000,
|
|
||||||
"end": 28199000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW - Pilot Emissions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 28199000,
|
|
||||||
"end": 28201000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW IBP"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 28201000,
|
|
||||||
"end": 28225000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW - Pilot Emissions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 28225000,
|
|
||||||
"end": 28300000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, Digital - Pilot Emissions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 28300000,
|
|
||||||
"end": 29000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, SSB, DV, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 29000000,
|
|
||||||
"end": 29300000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "All Modes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 29300000,
|
|
||||||
"end": 29510000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "All Modes - Satellites"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 29510000,
|
|
||||||
"end": 29520000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "All Modes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 29520000,
|
|
||||||
"end": 29590000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "FM, DV - Repeater input"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 29590000,
|
|
||||||
"end": 29620000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, FM, DV - FM calling freq: 29.600 kHz"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 29620000,
|
|
||||||
"end": 29700000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "FM, DV - Repeater output 10m Ham Band|"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 50000000,
|
|
||||||
"end": 54000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "6m Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 144000000,
|
|
||||||
"end": 144025000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "|2m Ham Band All Modes - Satellites"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 144025000,
|
|
||||||
"end": 144110000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW - EME"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 144110000,
|
|
||||||
"end": 144150000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, Digital - EME"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 144150000,
|
|
||||||
"end": 144180000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSB, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 144180000,
|
|
||||||
"end": 144275000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, SSB - Calling freq: 144.2 MHz"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 144275000,
|
|
||||||
"end": 144300000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW - Pilot Emissions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 144300000,
|
|
||||||
"end": 144360000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, SSB - Calling freq: 144.2 MHz"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 144360000,
|
|
||||||
"end": 144400000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSB, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 144400000,
|
|
||||||
"end": 144600000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "All Modes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 144600000,
|
|
||||||
"end": 144900000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "FM, DV - Repeater input"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 144900000,
|
|
||||||
"end": 145000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, FM, DV, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 145000000,
|
|
||||||
"end": 145200000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "All Modes, IVG"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 145200000,
|
|
||||||
"end": 145500000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "FM, DV - Repeater output"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 145500000,
|
|
||||||
"end": 145565000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "All Modes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 145565000,
|
|
||||||
"end": 145575000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "APRS"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 145575000,
|
|
||||||
"end": 145790000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "All Modes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 145790000,
|
|
||||||
"end": 145800000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "Guard Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 145800000,
|
|
||||||
"end": 146000000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "All Modes - Satellites"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 146000000,
|
|
||||||
"end": 146390000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "FM, DV - Repeater input"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 146390000,
|
|
||||||
"end": 146600000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, FM, DV - Calling freq: 146.52 MHz"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 146600000,
|
|
||||||
"end": 146990000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "FM, DV - Repeater output"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 146990000,
|
|
||||||
"end": 147400000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "FM, DV - Repeater input"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 147400000,
|
|
||||||
"end": 147590000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, FM, DV"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 147590000,
|
|
||||||
"end": 148000000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "FM, DV - Repeater output 2m Ham Band|"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 220000000,
|
|
||||||
"end": 225000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "1.3m Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 430000000,
|
|
||||||
"end": 432000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "|70cm Ham Band All Modes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 432000000,
|
|
||||||
"end": 432025000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW - EME"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 432025000,
|
|
||||||
"end": 432100000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, Digital - EME"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 432100000,
|
|
||||||
"end": 432300000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, SSB - Calling freq: 432.1 MHz"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 432300000,
|
|
||||||
"end": 432400000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW - Pilot Emissions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 432400000,
|
|
||||||
"end": 432420000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, Digital - Pilot Emissions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 432420000,
|
|
||||||
"end": 433000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "CW, SSB, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 433000000,
|
|
||||||
"end": 433050000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "CW, Digital"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 433050000,
|
|
||||||
"end": 434000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "All Modes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 434000000,
|
|
||||||
"end": 435000000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "Fm, DV - Repeater input"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 435000000,
|
|
||||||
"end": 438000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "All Modes - Satellites"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 438000000,
|
|
||||||
"end": 439000000,
|
|
||||||
"type": "amateur1",
|
|
||||||
"name": "All Modes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 439000000,
|
|
||||||
"end": 440000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "FM, DV - Repeater output 70cm Ham Band|"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 902000000,
|
|
||||||
"end": 928000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "33cm Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 1240000000,
|
|
||||||
"end": 1300000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "23cm Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 2330000000,
|
|
||||||
"end": 2450000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "13cm Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 3400000000,
|
|
||||||
"end": 3500000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "9cm Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 5650000000,
|
|
||||||
"end": 5925000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "5cm Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 10000000000,
|
|
||||||
"end": 10500000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "3cm Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 24000000000,
|
|
||||||
"end": 24250000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "1.2cm Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 47000000000,
|
|
||||||
"end": 47200000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "6mm Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 122250000000,
|
|
||||||
"end": 123000000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "2.5mm Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 134000000000,
|
|
||||||
"end": 141000000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "2mm Ham Band"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"start": 241000000000,
|
|
||||||
"end": 250000000000,
|
|
||||||
"type": "amateur",
|
|
||||||
"name": "1mm Ham Band"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
BIN
root/res/icons/align_center.png
Normal file
BIN
root/res/icons/align_center.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.8 KiB |
@ -2,10 +2,10 @@
|
|||||||
#include <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 <dsp/buffer/packer.h>
|
#include <dsp/buffer/packer.h>
|
||||||
#include <dsp/convert/stereo_to_mono.h>
|
#include <dsp/convert/stereo_to_mono.h>
|
||||||
#include <utils/flog.h>
|
#include <utils/flog.h>
|
||||||
|
#include <utils/optionlist.h>
|
||||||
#include <RtAudio.h>
|
#include <RtAudio.h>
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <core.h>
|
#include <core.h>
|
||||||
@ -16,36 +16,51 @@ SDRPP_MOD_INFO{
|
|||||||
/* Name: */ "audio_sink",
|
/* Name: */ "audio_sink",
|
||||||
/* Description: */ "Audio sink module for SDR++",
|
/* Description: */ "Audio sink module for SDR++",
|
||||||
/* Author: */ "Ryzerth",
|
/* Author: */ "Ryzerth",
|
||||||
/* Version: */ 0, 1, 0,
|
/* Version: */ 0, 2, 0,
|
||||||
/* Max instances */ 1
|
/* Max instances */ 1
|
||||||
};
|
};
|
||||||
|
|
||||||
ConfigManager config;
|
ConfigManager config;
|
||||||
|
|
||||||
class AudioSink : SinkManager::Sink {
|
bool operator==(const RtAudio::DeviceInfo& a, const RtAudio::DeviceInfo& b) {
|
||||||
|
return a.name == b.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AudioSink : public Sink {
|
||||||
public:
|
public:
|
||||||
AudioSink(SinkManager::Stream* stream, std::string streamName) {
|
AudioSink(SinkEntry* entry, dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id, const std::string& stringId) :
|
||||||
_stream = stream;
|
Sink(entry, stream, name, id, stringId)
|
||||||
_streamName = streamName;
|
{
|
||||||
s2m.init(_stream->sinkOut);
|
s2m.init(stream);
|
||||||
monoPacker.init(&s2m.out, 512);
|
monoPacker.init(&s2m.out, 512);
|
||||||
stereoPacker.init(_stream->sinkOut, 512);
|
stereoPacker.init(stream, 512);
|
||||||
|
|
||||||
#if RTAUDIO_VERSION_MAJOR >= 6
|
#if RTAUDIO_VERSION_MAJOR >= 6
|
||||||
audio.setErrorCallback(&errorCallback);
|
audio.setErrorCallback(&errorCallback);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if RTAUDIO_VERSION_MAJOR >= 6
|
||||||
|
audio.setErrorCallback(&errorCallback);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Load config (TODO)
|
||||||
bool created = false;
|
bool created = false;
|
||||||
std::string device = "";
|
std::string device = "";
|
||||||
config.acquire();
|
// config.acquire();
|
||||||
if (!config.conf.contains(_streamName)) {
|
// if (config.conf.contains(streamName)) {
|
||||||
created = true;
|
// if (!config.conf[streamName].is_array()) {
|
||||||
config.conf[_streamName]["device"] = "";
|
// json tmp = config.conf[streamName];
|
||||||
config.conf[_streamName]["devices"] = json({});
|
// config.conf[streamName] = json::array();
|
||||||
}
|
// config.conf[streamName][0] = tmp;
|
||||||
device = config.conf[_streamName]["device"];
|
// modified = true;
|
||||||
config.release(created);
|
// }
|
||||||
|
// if (config.conf[streamName].contains((int)id)) {
|
||||||
|
// device = config.conf[streamName][(int)id]["device"];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// config.release(modified);
|
||||||
|
|
||||||
|
// List devices
|
||||||
RtAudio::DeviceInfo info;
|
RtAudio::DeviceInfo info;
|
||||||
#if RTAUDIO_VERSION_MAJOR >= 6
|
#if RTAUDIO_VERSION_MAJOR >= 6
|
||||||
for (int i : audio.getDeviceIds()) {
|
for (int i : audio.getDeviceIds()) {
|
||||||
@ -60,15 +75,13 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
if (info.outputChannels == 0) { continue; }
|
if (info.outputChannels == 0) { continue; }
|
||||||
if (info.isDefaultOutput) { defaultDevId = devList.size(); }
|
if (info.isDefaultOutput) { defaultDevId = devList.size(); }
|
||||||
devList.push_back(info);
|
devList.define(i, info.name, info);
|
||||||
deviceIds.push_back(i);
|
|
||||||
txtDevList += info.name;
|
|
||||||
txtDevList += '\0';
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
flog::error("AudioSinkModule Error getting audio device ({}) info: {}", i, e.what());
|
flog::error("AudioSinkModule Error getting audio device ({}) info: {}", i, e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectByName(device);
|
selectByName(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,67 +115,92 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void selectById(int id) {
|
void selectById(int id) {
|
||||||
|
// Update ID
|
||||||
devId = id;
|
devId = id;
|
||||||
bool created = false;
|
selectedDevName = devList[id].name;
|
||||||
config.acquire();
|
|
||||||
if (!config.conf[_streamName]["devices"].contains(devList[id].name)) {
|
|
||||||
created = true;
|
|
||||||
config.conf[_streamName]["devices"][devList[id].name] = devList[id].preferredSampleRate;
|
|
||||||
}
|
|
||||||
sampleRate = config.conf[_streamName]["devices"][devList[id].name];
|
|
||||||
config.release(created);
|
|
||||||
|
|
||||||
sampleRates = devList[id].sampleRates;
|
// List samplerates and select default SR
|
||||||
sampleRatesTxt = "";
|
|
||||||
char buf[256];
|
char buf[256];
|
||||||
bool found = false;
|
sampleRates.clear();
|
||||||
unsigned int defaultId = 0;
|
const auto& srList = devList[id].sampleRates;
|
||||||
unsigned int defaultSr = devList[id].preferredSampleRate;
|
unsigned int defaultSr = devList[id].preferredSampleRate;
|
||||||
for (int i = 0; i < sampleRates.size(); i++) {
|
for (auto& sr : srList) {
|
||||||
if (sampleRates[i] == sampleRate) {
|
if (sr == defaultSr) {
|
||||||
found = true;
|
srId = sampleRates.size();
|
||||||
srId = i;
|
sampleRate = sr;
|
||||||
}
|
}
|
||||||
if (sampleRates[i] == defaultSr) {
|
sprintf(buf, "%d", sr);
|
||||||
defaultId = i;
|
sampleRates.define(sr, buf, sr);
|
||||||
}
|
|
||||||
sprintf(buf, "%d", sampleRates[i]);
|
|
||||||
sampleRatesTxt += buf;
|
|
||||||
sampleRatesTxt += '\0';
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
sampleRate = defaultSr;
|
|
||||||
srId = defaultId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_stream->setSampleRate(sampleRate);
|
// // Load config
|
||||||
|
// config.acquire();
|
||||||
|
// if (config.conf[streamName][(int)id].contains(selectedDevName)) {
|
||||||
|
// unsigned int wantedSr = config.conf[streamName][id][selectedDevName];
|
||||||
|
// if (sampleRates.keyExists(wantedSr)) {
|
||||||
|
// srId = sampleRates.keyId(wantedSr);
|
||||||
|
// sampleRate = sampleRates[srId];
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// config.release();
|
||||||
|
|
||||||
|
// Lock the sink
|
||||||
|
auto lck = entry->getLock();
|
||||||
|
|
||||||
|
// Stop the sink DSP
|
||||||
|
// TODO: Only if the sink DSP is running, otherwise you risk starting it when it shouldn't
|
||||||
|
entry->stopDSP();
|
||||||
|
|
||||||
|
// Stop the sink
|
||||||
if (running) { doStop(); }
|
if (running) { doStop(); }
|
||||||
|
|
||||||
|
// Update stream samplerate
|
||||||
|
entry->setSamplerate(sampleRate);
|
||||||
|
|
||||||
|
// Start the DSP
|
||||||
|
entry->startDSP();
|
||||||
|
|
||||||
|
// Start the sink
|
||||||
if (running) { doStart(); }
|
if (running) { doStart(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
void menuHandler() {
|
void showMenu() {
|
||||||
float menuWidth = ImGui::GetContentRegionAvail().x;
|
float menuWidth = ImGui::GetContentRegionAvail().x;
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(menuWidth);
|
ImGui::SetNextItemWidth(menuWidth);
|
||||||
if (ImGui::Combo(("##_audio_sink_dev_" + _streamName).c_str(), &devId, txtDevList.c_str())) {
|
if (ImGui::Combo(("##_audio_sink_dev_" + stringId).c_str(), &devId, devList.txt)) {
|
||||||
selectById(devId);
|
selectById(devId);
|
||||||
config.acquire();
|
// config.acquire();
|
||||||
config.conf[_streamName]["device"] = devList[devId].name;
|
// config.conf[streamName]["device"] = devList[devId].name;
|
||||||
config.release(true);
|
// config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(menuWidth);
|
ImGui::SetNextItemWidth(menuWidth);
|
||||||
if (ImGui::Combo(("##_audio_sink_sr_" + _streamName).c_str(), &srId, sampleRatesTxt.c_str())) {
|
if (ImGui::Combo(("##_audio_sink_sr_" + stringId).c_str(), &srId, sampleRates.txt)) {
|
||||||
sampleRate = sampleRates[srId];
|
sampleRate = sampleRates[srId];
|
||||||
_stream->setSampleRate(sampleRate);
|
|
||||||
if (running) {
|
// Lock the sink
|
||||||
doStop();
|
auto lck = entry->getLock();
|
||||||
doStart();
|
|
||||||
}
|
// Stop the sink DSP
|
||||||
config.acquire();
|
// TODO: Only if the sink DSP is running, otherwise you risk starting it when it shouldn't
|
||||||
config.conf[_streamName]["devices"][devList[devId].name] = sampleRate;
|
entry->stopDSP();
|
||||||
config.release(true);
|
|
||||||
|
// Stop the sink
|
||||||
|
if (running) { doStop(); }
|
||||||
|
|
||||||
|
// Update stream samplerate
|
||||||
|
entry->setSamplerate(sampleRate);
|
||||||
|
|
||||||
|
// Start the DSP
|
||||||
|
entry->startDSP();
|
||||||
|
|
||||||
|
// Start the sink
|
||||||
|
if (running) { doStart(); }
|
||||||
|
|
||||||
|
// config.acquire();
|
||||||
|
// config.conf[streamName]["devices"][devList[devId].name] = sampleRate;
|
||||||
|
// config.release(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,12 +223,12 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool doStart() {
|
bool doStart() {
|
||||||
RtAudio::StreamParameters parameters;
|
RtAudio::StreamParameters parameters;
|
||||||
parameters.deviceId = deviceIds[devId];
|
parameters.deviceId = devList.key(devId);
|
||||||
parameters.nChannels = 2;
|
parameters.nChannels = 2;
|
||||||
unsigned int bufferFrames = sampleRate / 60;
|
unsigned int bufferFrames = sampleRate / 60;
|
||||||
RtAudio::StreamOptions opts;
|
RtAudio::StreamOptions opts;
|
||||||
opts.flags = RTAUDIO_MINIMIZE_LATENCY;
|
opts.flags = RTAUDIO_MINIMIZE_LATENCY;
|
||||||
opts.streamName = _streamName;
|
opts.streamName = streamName;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
audio.openStream(¶meters, NULL, RTAUDIO_FLOAT32, sampleRate, &bufferFrames, &callback, this, &opts);
|
audio.openStream(¶meters, NULL, RTAUDIO_FLOAT32, sampleRate, &bufferFrames, &callback, this, &opts);
|
||||||
@ -229,44 +267,34 @@ private:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SinkManager::Stream* _stream;
|
|
||||||
dsp::convert::StereoToMono s2m;
|
dsp::convert::StereoToMono s2m;
|
||||||
dsp::buffer::Packer<float> monoPacker;
|
dsp::buffer::Packer<float> monoPacker;
|
||||||
dsp::buffer::Packer<dsp::stereo_t> stereoPacker;
|
dsp::buffer::Packer<dsp::stereo_t> stereoPacker;
|
||||||
|
|
||||||
std::string _streamName;
|
|
||||||
|
|
||||||
int srId = 0;
|
int srId = 0;
|
||||||
int devCount;
|
|
||||||
int devId = 0;
|
int devId = 0;
|
||||||
bool running = false;
|
bool running = false;
|
||||||
|
std::string selectedDevName;
|
||||||
|
|
||||||
unsigned int defaultDevId = 0;
|
unsigned int defaultDevId = 0;
|
||||||
|
|
||||||
std::vector<RtAudio::DeviceInfo> devList;
|
OptionList<unsigned int, RtAudio::DeviceInfo> devList;
|
||||||
std::vector<unsigned int> deviceIds;
|
OptionList<unsigned int, unsigned int> sampleRates;
|
||||||
std::string txtDevList;
|
|
||||||
|
|
||||||
std::vector<unsigned int> sampleRates;
|
|
||||||
std::string sampleRatesTxt;
|
|
||||||
unsigned int sampleRate = 48000;
|
unsigned int sampleRate = 48000;
|
||||||
|
|
||||||
RtAudio audio;
|
RtAudio audio;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AudioSinkModule : public ModuleManager::Instance {
|
class AudioSinkModule : public ModuleManager::Instance, public SinkProvider {
|
||||||
public:
|
public:
|
||||||
AudioSinkModule(std::string name) {
|
AudioSinkModule(std::string name) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
provider.create = create_sink;
|
sigpath::streamManager.registerSinkProvider("Audio", this);
|
||||||
provider.ctx = this;
|
|
||||||
|
|
||||||
sigpath::sinkManager.registerSinkProvider("Audio", provider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~AudioSinkModule() {
|
~AudioSinkModule() {
|
||||||
// Unregister sink, this will automatically stop and delete all instances of the audio sink
|
sigpath::streamManager.unregisterSinkProvider(this);
|
||||||
sigpath::sinkManager.unregisterSinkProvider("Audio");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void postInit() {}
|
void postInit() {}
|
||||||
@ -283,14 +311,13 @@ public:
|
|||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
std::unique_ptr<Sink> createSink(SinkEntry* entry, dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id, const std::string& stringId) {
|
||||||
static SinkManager::Sink* create_sink(SinkManager::Stream* stream, std::string streamName, void* ctx) {
|
return std::make_unique<AudioSink>(entry, stream, name, id, stringId);
|
||||||
return (SinkManager::Sink*)(new AudioSink(stream, streamName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
SinkManager::SinkProvider provider;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
MOD_EXPORT void _INIT_() {
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
#include <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/stream.h>
|
||||||
#include <dsp/buffer/packer.h>
|
#include <dsp/buffer/packer.h>
|
||||||
#include <dsp/convert/stereo_to_mono.h>
|
#include <dsp/convert/stereo_to_mono.h>
|
||||||
#include <dsp/sink/handler_sink.h>
|
#include <dsp/sink/handler_sink.h>
|
||||||
#include <utils/flog.h>
|
#include <utils/flog.h>
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <gui/style.h>
|
#include <gui/style.h>
|
||||||
|
#include <utils/optionlist.h>
|
||||||
#include <core.h>
|
#include <core.h>
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
@ -18,84 +19,97 @@ SDRPP_MOD_INFO{
|
|||||||
/* Name: */ "network_sink",
|
/* Name: */ "network_sink",
|
||||||
/* Description: */ "Network sink module for SDR++",
|
/* Description: */ "Network sink module for SDR++",
|
||||||
/* Author: */ "Ryzerth",
|
/* Author: */ "Ryzerth",
|
||||||
/* Version: */ 0, 1, 0,
|
/* Version: */ 0, 2, 0,
|
||||||
/* Max instances */ 1
|
/* Max instances */ 1
|
||||||
};
|
};
|
||||||
|
|
||||||
ConfigManager config;
|
ConfigManager config;
|
||||||
|
|
||||||
enum {
|
enum SinkMode {
|
||||||
SINK_MODE_TCP,
|
SINK_MODE_TCP,
|
||||||
SINK_MODE_UDP
|
SINK_MODE_UDP
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* sinkModesTxt = "TCP\0UDP\0";
|
const char* sinkModesTxt = "TCP\0UDP\0";
|
||||||
|
|
||||||
class NetworkSink : SinkManager::Sink {
|
class NetworkSink : public Sink {
|
||||||
public:
|
public:
|
||||||
NetworkSink(SinkManager::Stream* stream, std::string streamName) {
|
NetworkSink(SinkEntry* entry, dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id, const std::string& stringId) :
|
||||||
_stream = stream;
|
Sink(entry, stream, name, id, stringId)
|
||||||
_streamName = streamName;
|
{
|
||||||
|
// Define modes
|
||||||
|
modes.define("TCP", SINK_MODE_TCP);
|
||||||
|
modes.define("UDP", SINK_MODE_UDP);
|
||||||
|
|
||||||
// Load config
|
// Create a list of sample rates
|
||||||
config.acquire();
|
std::vector<int> srList;
|
||||||
if (!config.conf.contains(_streamName)) {
|
for (int sr = 12000; sr <= 200000; sr += 12000) {
|
||||||
config.conf[_streamName]["hostname"] = "localhost";
|
srList.push_back(sr);
|
||||||
config.conf[_streamName]["port"] = 7355;
|
}
|
||||||
config.conf[_streamName]["protocol"] = SINK_MODE_UDP; // UDP
|
for (int sr = 11025; sr <= 192000; sr += 11025) {
|
||||||
config.conf[_streamName]["sampleRate"] = 48000.0;
|
srList.push_back(sr);
|
||||||
config.conf[_streamName]["stereo"] = false;
|
|
||||||
config.conf[_streamName]["listening"] = false;
|
|
||||||
}
|
}
|
||||||
std::string host = config.conf[_streamName]["hostname"];
|
|
||||||
strcpy(hostname, host.c_str());
|
|
||||||
port = config.conf[_streamName]["port"];
|
|
||||||
modeId = config.conf[_streamName]["protocol"];
|
|
||||||
sampleRate = config.conf[_streamName]["sampleRate"];
|
|
||||||
stereo = config.conf[_streamName]["stereo"];
|
|
||||||
bool startNow = config.conf[_streamName]["listening"];
|
|
||||||
config.release(true);
|
|
||||||
|
|
||||||
|
// Sort sample rate list
|
||||||
|
std::sort(srList.begin(), srList.end(), [](double a, double b) { return (a < b); });
|
||||||
|
|
||||||
|
// Define samplerate options
|
||||||
|
for (int sr : srList) {
|
||||||
|
char buf[16];
|
||||||
|
sprintf(buf, "%d", sr);
|
||||||
|
samplerates.define(sr, buf, sr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate buffer
|
||||||
netBuf = new int16_t[STREAM_BUFFER_SIZE];
|
netBuf = new int16_t[STREAM_BUFFER_SIZE];
|
||||||
|
|
||||||
packer.init(_stream->sinkOut, 512);
|
// Init DSP
|
||||||
|
packer.init(stream, 512);
|
||||||
s2m.init(&packer.out);
|
s2m.init(&packer.out);
|
||||||
monoSink.init(&s2m.out, monoHandler, this);
|
monoSink.init(&s2m.out, monoHandler, this);
|
||||||
stereoSink.init(&packer.out, stereoHandler, this);
|
stereoSink.init(&packer.out, stereoHandler, this);
|
||||||
|
|
||||||
|
// Load config
|
||||||
|
config.acquire();
|
||||||
|
bool startNow = false;
|
||||||
|
if (config.conf[stringId].contains("hostname")) {
|
||||||
|
std::string host = config.conf[stringId]["hostname"];
|
||||||
|
strcpy(hostname, host.c_str());
|
||||||
|
}
|
||||||
|
if (config.conf[stringId].contains("port")) {
|
||||||
|
port = config.conf[stringId]["port"];
|
||||||
|
}
|
||||||
|
if (config.conf[stringId].contains("mode")) {
|
||||||
|
std::string modeStr = config.conf[stringId]["mode"];
|
||||||
|
if (modes.keyExists(modeStr)) {
|
||||||
|
mode = modes.value(modes.keyId(modeStr));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mode = SINK_MODE_TCP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config.conf[stringId].contains("samplerate")) {
|
||||||
|
int nSr = config.conf[stringId]["samplerate"];
|
||||||
|
if (samplerates.keyExists(nSr)) {
|
||||||
|
sampleRate = samplerates.value(samplerates.keyId(nSr));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sampleRate = 48000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config.conf[stringId].contains("stereo")) {
|
||||||
|
stereo = config.conf[stringId]["stereo"];
|
||||||
|
}
|
||||||
|
if (config.conf[stringId].contains("running")) {
|
||||||
|
startNow = config.conf[stringId]["running"];
|
||||||
|
}
|
||||||
|
config.release();
|
||||||
|
|
||||||
// Create a list of sample rates
|
// Set mode ID
|
||||||
for (int sr = 12000; sr < 200000; sr += 12000) {
|
modeId = modes.valueId(mode);
|
||||||
sampleRates.push_back(sr);
|
|
||||||
}
|
|
||||||
for (int sr = 11025; sr < 192000; sr += 11025) {
|
|
||||||
sampleRates.push_back(sr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort sample rate list
|
// Set samplerate ID
|
||||||
std::sort(sampleRates.begin(), sampleRates.end(), [](double a, double b) { return (a < b); });
|
srId = samplerates.valueId(sampleRate);
|
||||||
|
|
||||||
// Generate text list for UI
|
|
||||||
char buffer[128];
|
|
||||||
int id = 0;
|
|
||||||
int _48kId;
|
|
||||||
bool found = false;
|
|
||||||
for (auto sr : sampleRates) {
|
|
||||||
sprintf(buffer, "%d", (int)sr);
|
|
||||||
sampleRatesTxt += buffer;
|
|
||||||
sampleRatesTxt += '\0';
|
|
||||||
if (sr == sampleRate) {
|
|
||||||
srId = id;
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
if (sr == 48000.0) { _48kId = id; }
|
|
||||||
id++;
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
srId = _48kId;
|
|
||||||
sampleRate = 48000.0;
|
|
||||||
}
|
|
||||||
_stream->setSampleRate(sampleRate);
|
|
||||||
|
|
||||||
// Start if needed
|
// Start if needed
|
||||||
if (startNow) { startServer(); }
|
if (startNow) { startServer(); }
|
||||||
@ -122,30 +136,30 @@ public:
|
|||||||
running = false;
|
running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void menuHandler() {
|
void showMenu() {
|
||||||
float menuWidth = ImGui::GetContentRegionAvail().x;
|
float menuWidth = ImGui::GetContentRegionAvail().x;
|
||||||
|
|
||||||
bool listening = (listener && listener->isListening()) || (conn && conn->isOpen());
|
bool listening = (listener && listener->isListening()) || (conn && conn->isOpen());
|
||||||
|
|
||||||
if (listening) { style::beginDisabled(); }
|
if (listening) { style::beginDisabled(); }
|
||||||
if (ImGui::InputText(CONCAT("##_network_sink_host_", _streamName), hostname, 1023)) {
|
if (ImGui::InputText(CONCAT("##_network_sink_host_", stringId), hostname, 1023)) {
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["hostname"] = hostname;
|
config.conf[stringId]["hostname"] = hostname;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
if (ImGui::InputInt(CONCAT("##_network_sink_port_", _streamName), &port, 0, 0)) {
|
if (ImGui::InputInt(CONCAT("##_network_sink_port_", stringId), &port, 0, 0)) {
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["port"] = port;
|
config.conf[stringId]["port"] = port;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::LeftLabel("Protocol");
|
ImGui::LeftLabel("Protocol");
|
||||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
if (ImGui::Combo(CONCAT("##_network_sink_mode_", _streamName), &modeId, sinkModesTxt)) {
|
if (ImGui::Combo(CONCAT("##_network_sink_mode_", stringId), &modeId, sinkModesTxt)) {
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["protocol"] = modeId;
|
config.conf[stringId]["mode"] = modeId;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,33 +167,33 @@ public:
|
|||||||
|
|
||||||
ImGui::LeftLabel("Samplerate");
|
ImGui::LeftLabel("Samplerate");
|
||||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
if (ImGui::Combo(CONCAT("##_network_sink_sr_", _streamName), &srId, sampleRatesTxt.c_str())) {
|
if (ImGui::Combo(CONCAT("##_network_sink_sr_", stringId), &srId, samplerates.txt)) {
|
||||||
sampleRate = sampleRates[srId];
|
sampleRate = samplerates.value(srId);
|
||||||
_stream->setSampleRate(sampleRate);
|
entry->setSamplerate(sampleRate);
|
||||||
packer.setSampleCount(sampleRate / 60);
|
packer.setSampleCount(sampleRate / 60);
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["sampleRate"] = sampleRate;
|
config.conf[stringId]["samplerate"] = sampleRate;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Checkbox(CONCAT("Stereo##_network_sink_stereo_", _streamName), &stereo)) {
|
if (ImGui::Checkbox(CONCAT("Stereo##_network_sink_stereo_", stringId), &stereo)) {
|
||||||
stop();
|
stop();
|
||||||
start();
|
start();
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["stereo"] = stereo;
|
config.conf[stringId]["stereo"] = stereo;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listening && ImGui::Button(CONCAT("Stop##_network_sink_stop_", _streamName), ImVec2(menuWidth, 0))) {
|
if (listening && ImGui::Button(CONCAT("Stop##_network_sink_stop_", stringId), ImVec2(menuWidth, 0))) {
|
||||||
stopServer();
|
stopServer();
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["listening"] = false;
|
config.conf[stringId]["running"] = false;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
else if (!listening && ImGui::Button(CONCAT("Start##_network_sink_stop_", _streamName), ImVec2(menuWidth, 0))) {
|
else if (!listening && ImGui::Button(CONCAT("Start##_network_sink_stop_", stringId), ImVec2(menuWidth, 0))) {
|
||||||
startServer();
|
startServer();
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["listening"] = true;
|
config.conf[stringId]["running"] = true;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,47 +285,40 @@ private:
|
|||||||
_this->listener->acceptAsync(clientHandler, _this);
|
_this->listener->acceptAsync(clientHandler, _this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SinkManager::Stream* _stream;
|
// DSP
|
||||||
dsp::buffer::Packer<dsp::stereo_t> packer;
|
dsp::buffer::Packer<dsp::stereo_t> packer;
|
||||||
dsp::convert::StereoToMono s2m;
|
dsp::convert::StereoToMono s2m;
|
||||||
dsp::sink::Handler<float> monoSink;
|
dsp::sink::Handler<float> monoSink;
|
||||||
dsp::sink::Handler<dsp::stereo_t> stereoSink;
|
dsp::sink::Handler<dsp::stereo_t> stereoSink;
|
||||||
|
|
||||||
std::string _streamName;
|
OptionList<std::string, SinkMode> modes;
|
||||||
|
OptionList<int, double> samplerates;
|
||||||
int srId = 0;
|
|
||||||
bool running = false;
|
|
||||||
|
|
||||||
char hostname[1024];
|
char hostname[1024];
|
||||||
int port = 4242;
|
int port = 7355;
|
||||||
|
SinkMode mode = SINK_MODE_TCP;
|
||||||
int modeId = 1;
|
int modeId;
|
||||||
|
int sampleRate = 48000;
|
||||||
std::vector<unsigned int> sampleRates;
|
int srId;
|
||||||
std::string sampleRatesTxt;
|
|
||||||
unsigned int sampleRate = 48000;
|
|
||||||
bool stereo = false;
|
bool stereo = false;
|
||||||
|
bool running = false;
|
||||||
|
|
||||||
int16_t* netBuf;
|
int16_t* netBuf;
|
||||||
|
|
||||||
net::Listener listener;
|
net::Listener listener;
|
||||||
net::Conn conn;
|
net::Conn conn;
|
||||||
std::mutex connMtx;
|
std::mutex connMtx;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetworkSinkModule : public ModuleManager::Instance {
|
class NetworkSinkModule : public ModuleManager::Instance, SinkProvider {
|
||||||
public:
|
public:
|
||||||
NetworkSinkModule(std::string name) {
|
NetworkSinkModule(std::string name) {
|
||||||
this->name = name;
|
// Register self as provider
|
||||||
provider.create = create_sink;
|
sigpath::streamManager.registerSinkProvider("Network", this);
|
||||||
provider.ctx = this;
|
|
||||||
|
|
||||||
sigpath::sinkManager.registerSinkProvider("Network", provider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~NetworkSinkModule() {
|
~NetworkSinkModule() {
|
||||||
// Unregister sink, this will automatically stop and delete all instances of the audio sink
|
// Unregister self
|
||||||
sigpath::sinkManager.unregisterSinkProvider("Network");
|
sigpath::streamManager.unregisterSinkProvider(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void postInit() {}
|
void postInit() {}
|
||||||
@ -328,14 +335,13 @@ public:
|
|||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
std::unique_ptr<Sink> createSink(SinkEntry* entry, dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id, const std::string& stringId) {
|
||||||
static SinkManager::Sink* create_sink(SinkManager::Stream* stream, std::string streamName, void* ctx) {
|
return std::make_unique<NetworkSink>(entry, stream, name, id, stringId);
|
||||||
return (SinkManager::Sink*)(new NetworkSink(stream, streamName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
SinkManager::SinkProvider provider;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
MOD_EXPORT void _INIT_() {
|
||||||
|
@ -152,6 +152,7 @@ public:
|
|||||||
|
|
||||||
// Update samplerate from ID
|
// Update samplerate from ID
|
||||||
sampleRate = sampleRates[srId];
|
sampleRate = sampleRates[srId];
|
||||||
|
core::setInputSampleRate(sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -231,7 +232,6 @@ private:
|
|||||||
if (SmGui::Combo(CONCAT("##_audio_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
if (SmGui::Combo(CONCAT("##_audio_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
||||||
std::string dev = _this->devices.key(_this->devId);
|
std::string dev = _this->devices.key(_this->devId);
|
||||||
_this->select(dev);
|
_this->select(dev);
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf["device"] = dev;
|
config.conf["device"] = dev;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
@ -253,7 +253,6 @@ private:
|
|||||||
if (SmGui::Button(CONCAT("Refresh##_audio_refr_", _this->name))) {
|
if (SmGui::Button(CONCAT("Refresh##_audio_refr_", _this->name))) {
|
||||||
_this->refresh();
|
_this->refresh();
|
||||||
_this->select(_this->selectedDevice);
|
_this->select(_this->selectedDevice);
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_this->running) { SmGui::EndDisabled(); }
|
if (_this->running) { SmGui::EndDisabled(); }
|
||||||
|
@ -304,7 +304,6 @@ private:
|
|||||||
SmGui::ForceSync();
|
SmGui::ForceSync();
|
||||||
if (SmGui::Combo(CONCAT("##_hackrf_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) {
|
if (SmGui::Combo(CONCAT("##_hackrf_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);
|
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf["device"] = _this->selectedSerial;
|
config.conf["device"] = _this->selectedSerial;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
|
@ -118,6 +118,7 @@ private:
|
|||||||
|
|
||||||
// Update host samplerate
|
// Update host samplerate
|
||||||
sampleRate = samplerates.key(srId);
|
sampleRate = samplerates.key(srId);
|
||||||
|
core::setInputSampleRate(sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void menuSelected(void* ctx) {
|
static void menuSelected(void* ctx) {
|
||||||
@ -198,7 +199,6 @@ private:
|
|||||||
SmGui::ForceSync();
|
SmGui::ForceSync();
|
||||||
if (SmGui::Combo(CONCAT("##_hermes_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
if (SmGui::Combo(CONCAT("##_hermes_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
||||||
_this->selectMac(_this->devices.key(_this->devId));
|
_this->selectMac(_this->devices.key(_this->devId));
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
if (!_this->selectedMac.empty()) {
|
if (!_this->selectedMac.empty()) {
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf["device"] = _this->devices.key(_this->devId);
|
config.conf["device"] = _this->devices.key(_this->devId);
|
||||||
@ -225,7 +225,6 @@ private:
|
|||||||
std::string mac = config.conf["device"];
|
std::string mac = config.conf["device"];
|
||||||
config.release();
|
config.release();
|
||||||
_this->selectMac(mac);
|
_this->selectMac(mac);
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_this->running) { SmGui::EndDisabled(); }
|
if (_this->running) { SmGui::EndDisabled(); }
|
||||||
|
@ -210,6 +210,7 @@ public:
|
|||||||
|
|
||||||
// Update samplerate
|
// Update samplerate
|
||||||
sampleRate = srList[srId];
|
sampleRate = srList[srId];
|
||||||
|
core::setInputSampleRate(sampleRate);
|
||||||
|
|
||||||
// Close device
|
// Close device
|
||||||
perseus_close(dev);
|
perseus_close(dev);
|
||||||
@ -328,7 +329,6 @@ private:
|
|||||||
if (SmGui::Combo(CONCAT("##_airspyhf_dev_sel_", _this->name), &_this->devId, _this->devList.txt)) {
|
if (SmGui::Combo(CONCAT("##_airspyhf_dev_sel_", _this->name), &_this->devId, _this->devList.txt)) {
|
||||||
std::string serial = _this->devList.key(_this->devId);
|
std::string serial = _this->devList.key(_this->devId);
|
||||||
_this->select(serial);
|
_this->select(serial);
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf["device"] = serial;
|
config.conf["device"] = serial;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
|
@ -244,6 +244,9 @@ private:
|
|||||||
bwId = 0;
|
bwId = 0;
|
||||||
bandwidth = bandwidths.value(bwId);
|
bandwidth = bandwidths.value(bwId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update core samplerate
|
||||||
|
core::setInputSampleRate(samplerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void menuSelected(void* ctx) {
|
static void menuSelected(void* ctx) {
|
||||||
@ -348,7 +351,6 @@ private:
|
|||||||
SmGui::ForceSync();
|
SmGui::ForceSync();
|
||||||
if (SmGui::Combo("##plutosdr_dev_sel", &_this->devId, _this->devices.txt)) {
|
if (SmGui::Combo("##plutosdr_dev_sel", &_this->devId, _this->devices.txt)) {
|
||||||
_this->select(_this->devices.key(_this->devId));
|
_this->select(_this->devices.key(_this->devId));
|
||||||
core::setInputSampleRate(_this->samplerate);
|
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf["device"] = _this->devices.key(_this->devId);
|
config.conf["device"] = _this->devices.key(_this->devId);
|
||||||
config.release(true);
|
config.release(true);
|
||||||
@ -371,7 +373,7 @@ private:
|
|||||||
if (SmGui::Button(CONCAT("Refresh##_pluto_refr_", _this->name))) {
|
if (SmGui::Button(CONCAT("Refresh##_pluto_refr_", _this->name))) {
|
||||||
_this->refresh();
|
_this->refresh();
|
||||||
_this->select(_this->devDesc);
|
_this->select(_this->devDesc);
|
||||||
core::setInputSampleRate(_this->samplerate);
|
|
||||||
}
|
}
|
||||||
if (_this->running) { SmGui::EndDisabled(); }
|
if (_this->running) { SmGui::EndDisabled(); }
|
||||||
|
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
project(rfnm_source)
|
|
||||||
|
|
||||||
file(GLOB SRC "src/*.cpp")
|
|
||||||
|
|
||||||
include(${SDRPP_MODULE_CMAKE})
|
|
||||||
|
|
||||||
target_include_directories(rfnm_source PRIVATE "C:/Users/ryzerth/Documents/Code/librfnm/include/librfnm")
|
|
||||||
target_link_directories(rfnm_source PRIVATE "C:/Users/ryzerth/Documents/Code/librfnm/build/Release")
|
|
||||||
target_link_libraries(rfnm_source PRIVATE librfnm)
|
|
@ -1,362 +0,0 @@
|
|||||||
#include <imgui.h>
|
|
||||||
#include <module.h>
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <gui/smgui.h>
|
|
||||||
#include <signal_path/signal_path.h>
|
|
||||||
#include <librfnm.h>
|
|
||||||
#include <core.h>
|
|
||||||
#include <utils/optionlist.h>
|
|
||||||
|
|
||||||
SDRPP_MOD_INFO{
|
|
||||||
/* Name: */ "rfnm_source",
|
|
||||||
/* Description: */ "RFNM Source Module",
|
|
||||||
/* Author: */ "Ryzerth",
|
|
||||||
/* Version: */ 0, 1, 0,
|
|
||||||
/* Max instances */ -1
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
|
||||||
|
|
||||||
class RFNMSourceModule : public ModuleManager::Instance {
|
|
||||||
public:
|
|
||||||
RFNMSourceModule(std::string name) {
|
|
||||||
this->name = name;
|
|
||||||
|
|
||||||
sampleRate = 61440000.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 devices
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
// Select first (TODO: Select from config)
|
|
||||||
select("");
|
|
||||||
|
|
||||||
sigpath::sourceManager.registerSource("RFNM", &handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
~RFNMSourceModule() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void postInit() {}
|
|
||||||
|
|
||||||
void enable() {
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void disable() {
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void refresh() {
|
|
||||||
#ifndef __ANDROID__
|
|
||||||
devices.clear();
|
|
||||||
auto list = librfnm::find(librfnm_transport::LIBRFNM_TRANSPORT_USB);
|
|
||||||
for (const auto& info : list) {
|
|
||||||
// Format device name
|
|
||||||
std::string devName = "RFNM ";
|
|
||||||
devName += info.motherboard.user_readable_name;
|
|
||||||
devName += " [";
|
|
||||||
devName += (char*)info.motherboard.serial_number;
|
|
||||||
devName += ']';
|
|
||||||
|
|
||||||
// Save device
|
|
||||||
devices.define((char*)info.motherboard.serial_number, devName, (char*)info.motherboard.serial_number);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// Check for device presence
|
|
||||||
int vid, pid;
|
|
||||||
devFd = backend::getDeviceFD(vid, pid, backend::RFNM_VIDPIDS);
|
|
||||||
if (devFd < 0) { return; }
|
|
||||||
|
|
||||||
// Get device info
|
|
||||||
std::string fakeName = "RFNM USB";
|
|
||||||
devices.define(fakeName, fakeName, fakeName);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void select(const std::string& serial) {
|
|
||||||
// If there are no devices, give up
|
|
||||||
if (devices.empty()) {
|
|
||||||
selectedSerial.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the serial was not found, select the first available serial
|
|
||||||
if (!devices.keyExists(serial)) {
|
|
||||||
select(devices.key(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// // Open the device
|
|
||||||
// librfnm* dev = new librfnm(librfnm_transport::LIBRFNM_TRANSPORT_USB, serial);
|
|
||||||
|
|
||||||
// Define bandwidths
|
|
||||||
bandwidths.clear();
|
|
||||||
bandwidths.define(-1, "Auto", -1);
|
|
||||||
for (int i = 1; i <= 100; i++) {
|
|
||||||
char buf[128];
|
|
||||||
sprintf(buf, "%d MHz", i);
|
|
||||||
bandwidths.define(i, buf, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get gain range
|
|
||||||
gainMin = -30;//dev->librfnm_s->rx.ch[0].gain_range.min;
|
|
||||||
gainMax = 60;//dev->librfnm_s->rx.ch[0].gain_range.max;
|
|
||||||
|
|
||||||
// // Close device
|
|
||||||
// delete dev;
|
|
||||||
|
|
||||||
// Define samplerates
|
|
||||||
samplerates.clear();
|
|
||||||
samplerates.define(61440000, "61.44 MHz", 2);
|
|
||||||
samplerates.define(122880000, "122.88 MHz", 1);
|
|
||||||
|
|
||||||
// TODO: Load options
|
|
||||||
srId = samplerates.keyId(61440000);
|
|
||||||
bwId = bandwidths.nameId("Auto");
|
|
||||||
gain = 0;
|
|
||||||
|
|
||||||
// Update samplerate
|
|
||||||
sampleRate = samplerates.key(srId);
|
|
||||||
|
|
||||||
// Save serial number
|
|
||||||
selectedSerial = serial;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuSelected(void* ctx) {
|
|
||||||
RFNMSourceModule* _this = (RFNMSourceModule*)ctx;
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
flog::info("RFNMSourceModule '{0}': Menu Select!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuDeselected(void* ctx) {
|
|
||||||
RFNMSourceModule* _this = (RFNMSourceModule*)ctx;
|
|
||||||
flog::info("RFNMSourceModule '{0}': Menu Deselect!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start(void* ctx) {
|
|
||||||
RFNMSourceModule* _this = (RFNMSourceModule*)ctx;
|
|
||||||
if (_this->running) { return; }
|
|
||||||
|
|
||||||
// Open the device
|
|
||||||
#ifndef __ANDROID__
|
|
||||||
_this->openDev = new librfnm(librfnm_transport::LIBRFNM_TRANSPORT_USB, _this->selectedSerial);
|
|
||||||
#else
|
|
||||||
_this->openDev = new librfnm(_this->devFd);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Configure the device
|
|
||||||
_this->openDev->librfnm_s->rx.ch[0].enable = RFNM_CH_ON;
|
|
||||||
_this->openDev->librfnm_s->rx.ch[0].samp_freq_div_n = _this->samplerates[_this->srId];
|
|
||||||
_this->openDev->librfnm_s->rx.ch[0].freq = _this->freq;
|
|
||||||
_this->openDev->librfnm_s->rx.ch[0].gain = _this->gain;
|
|
||||||
_this->openDev->librfnm_s->rx.ch[0].rfic_lpf_bw = 100;
|
|
||||||
_this->openDev->librfnm_s->rx.ch[0].fm_notch = _this->fmNotch ? rfnm_fm_notch::RFNM_FM_NOTCH_ON : rfnm_fm_notch::RFNM_FM_NOTCH_OFF;
|
|
||||||
_this->openDev->librfnm_s->rx.ch[0].path = _this->openDev->librfnm_s->rx.ch[0].path_preferred;
|
|
||||||
rfnm_api_failcode fail = _this->openDev->set(LIBRFNM_APPLY_CH0_RX);
|
|
||||||
if (fail != rfnm_api_failcode::RFNM_API_OK) {
|
|
||||||
flog::error("Failed to configure device: {}", (int)fail);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the stream
|
|
||||||
_this->bufferSize = -1;
|
|
||||||
_this->openDev->rx_stream(librfnm_stream_format::LIBRFNM_STREAM_FORMAT_CS16, &_this->bufferSize);
|
|
||||||
if (_this->bufferSize <= 0) {
|
|
||||||
flog::error("Failed to configure stream");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate and queue buffers
|
|
||||||
flog::debug("BUFFER SIZE: {}", _this->bufferSize);
|
|
||||||
for (int i = 0; i < LIBRFNM_MIN_RX_BUFCNT; i++) {
|
|
||||||
_this->rxBuf[i].buf = dsp::buffer::alloc<uint8_t>(_this->bufferSize);
|
|
||||||
_this->openDev->rx_qbuf(&_this->rxBuf[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start worker
|
|
||||||
_this->workerThread = std::thread(&RFNMSourceModule::worker, _this);
|
|
||||||
|
|
||||||
_this->running = true;
|
|
||||||
flog::info("RFNMSourceModule '{0}': Start!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stop(void* ctx) {
|
|
||||||
RFNMSourceModule* _this = (RFNMSourceModule*)ctx;
|
|
||||||
if (!_this->running) { return; }
|
|
||||||
_this->running = false;
|
|
||||||
|
|
||||||
// Stop worker
|
|
||||||
_this->stream.stopWriter();
|
|
||||||
if (_this->workerThread.joinable()) { _this->workerThread.join(); }
|
|
||||||
_this->stream.clearWriteStop();
|
|
||||||
|
|
||||||
// Disable channel
|
|
||||||
_this->openDev->librfnm_s->rx.ch[0].enable = RFNM_CH_ON;
|
|
||||||
_this->openDev->set(LIBRFNM_APPLY_CH0_RX);
|
|
||||||
|
|
||||||
// Close device
|
|
||||||
delete _this->openDev;
|
|
||||||
|
|
||||||
// Free buffers
|
|
||||||
for (int i = 0; i < LIBRFNM_MIN_RX_BUFCNT; i++) {
|
|
||||||
dsp::buffer::free(_this->rxBuf[i].buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
flog::info("RFNMSourceModule '{0}': Stop!", _this->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tune(double freq, void* ctx) {
|
|
||||||
RFNMSourceModule* _this = (RFNMSourceModule*)ctx;
|
|
||||||
if (_this->running) {
|
|
||||||
_this->openDev->librfnm_s->rx.ch[0].freq = freq;
|
|
||||||
rfnm_api_failcode fail = _this->openDev->set(LIBRFNM_APPLY_CH0_RX);
|
|
||||||
if (fail != rfnm_api_failcode::RFNM_API_OK) {
|
|
||||||
flog::error("Failed to tune: {}", (int)fail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_this->freq = freq;
|
|
||||||
flog::info("RFNMSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void menuHandler(void* ctx) {
|
|
||||||
RFNMSourceModule* _this = (RFNMSourceModule*)ctx;
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::BeginDisabled(); }
|
|
||||||
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Combo(CONCAT("##_rfnm_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
|
||||||
_this->select(_this->devices.key(_this->devId));
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SmGui::Combo(CONCAT("##_rfnm_sr_sel_", _this->name), &_this->srId, _this->samplerates.txt)) {
|
|
||||||
_this->sampleRate = _this->samplerates.key(_this->srId);
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::SameLine();
|
|
||||||
SmGui::FillWidth();
|
|
||||||
SmGui::ForceSync();
|
|
||||||
if (SmGui::Button(CONCAT("Refresh##_rfnm_refr_", _this->name))) {
|
|
||||||
_this->refresh();
|
|
||||||
_this->select(_this->selectedSerial);
|
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_this->running) { SmGui::EndDisabled(); }
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Bandwidth");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::Combo(CONCAT("##_rfnm_bw_sel_", _this->name), &_this->bwId, _this->bandwidths.txt)) {
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
SmGui::LeftLabel("Gain");
|
|
||||||
SmGui::FillWidth();
|
|
||||||
if (SmGui::SliderInt(CONCAT("##_rfnm_gain_", _this->name), &_this->gain, _this->gainMin, _this->gainMax)) {
|
|
||||||
if (_this->running) {
|
|
||||||
_this->openDev->librfnm_s->rx.ch[0].gain = _this->gain;
|
|
||||||
rfnm_api_failcode fail = _this->openDev->set(LIBRFNM_APPLY_CH0_RX);
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SmGui::Checkbox(CONCAT("FM Notch##_rfnm_", _this->name), &_this->fmNotch)) {
|
|
||||||
if (_this->running) {
|
|
||||||
_this->openDev->librfnm_s->rx.ch[0].fm_notch = _this->fmNotch ? rfnm_fm_notch::RFNM_FM_NOTCH_ON : rfnm_fm_notch::RFNM_FM_NOTCH_OFF;
|
|
||||||
rfnm_api_failcode fail = _this->openDev->set(LIBRFNM_APPLY_CH0_RX);
|
|
||||||
}
|
|
||||||
// TODO: Save
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void worker() {
|
|
||||||
librfnm_rx_buf* lrxbuf;
|
|
||||||
int sampCount = bufferSize/4;
|
|
||||||
|
|
||||||
// TODO: Define number of buffers per swap to maintain 200 fps
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// Receive a buffer
|
|
||||||
auto fail = openDev->rx_dqbuf(&lrxbuf, LIBRFNM_CH0, 1000);
|
|
||||||
if (fail == rfnm_api_failcode::RFNM_API_DQBUF_NO_DATA) {
|
|
||||||
flog::error("Dequeue buffer didn't have any data");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (fail) { break; }
|
|
||||||
|
|
||||||
// Convert buffer to CF32
|
|
||||||
volk_16i_s32f_convert_32f((float*)stream.writeBuf, (int16_t*)lrxbuf->buf, 32768.0f, sampCount * 2);
|
|
||||||
|
|
||||||
// Reque buffer
|
|
||||||
openDev->rx_qbuf(lrxbuf);
|
|
||||||
|
|
||||||
// Swap data
|
|
||||||
if (!stream.swap(sampCount)) { break; }
|
|
||||||
}
|
|
||||||
|
|
||||||
flog::debug("Worker exiting");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
bool enabled = true;
|
|
||||||
dsp::stream<dsp::complex_t> stream;
|
|
||||||
double sampleRate;
|
|
||||||
SourceManager::SourceHandler handler;
|
|
||||||
bool running = false;
|
|
||||||
double freq;
|
|
||||||
|
|
||||||
OptionList<std::string, std::string> devices;
|
|
||||||
OptionList<int, int> bandwidths;
|
|
||||||
OptionList<int, int> samplerates;
|
|
||||||
int gainMin = 0;
|
|
||||||
int gainMax = 0;
|
|
||||||
|
|
||||||
int devId = 0;
|
|
||||||
int srId = 0;
|
|
||||||
int bwId = 0;
|
|
||||||
int gain = 0;
|
|
||||||
bool fmNotch = false;
|
|
||||||
std::string selectedSerial;
|
|
||||||
librfnm* openDev;
|
|
||||||
int bufferSize = -1;
|
|
||||||
librfnm_rx_buf rxBuf[LIBRFNM_MIN_RX_BUFCNT];
|
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
|
||||||
int devFd = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::thread workerThread;
|
|
||||||
};
|
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
|
||||||
// Nothing here
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
|
||||||
return new RFNMSourceModule(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
|
||||||
delete (RFNMSourceModule*)instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOD_EXPORT void _END_() {
|
|
||||||
// Nothing here
|
|
||||||
}
|
|
@ -411,6 +411,8 @@ public:
|
|||||||
agcSetPoint = config.conf["devices"][selectedName]["agcSetPoint"];
|
agcSetPoint = config.conf["devices"][selectedName]["agcSetPoint"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
core::setInputSampleRate(sampleRate);
|
||||||
|
|
||||||
// Per device options
|
// Per device options
|
||||||
if (openDev.hwVer == SDRPLAY_RSP1_ID) {
|
if (openDev.hwVer == SDRPLAY_RSP1_ID) {
|
||||||
// No config to load
|
// No config to load
|
||||||
@ -686,7 +688,6 @@ private:
|
|||||||
SmGui::ForceSync();
|
SmGui::ForceSync();
|
||||||
if (SmGui::Combo(CONCAT("##sdrplay_dev", _this->name), &_this->devId, _this->devListTxt.c_str())) {
|
if (SmGui::Combo(CONCAT("##sdrplay_dev", _this->name), &_this->devId, _this->devListTxt.c_str())) {
|
||||||
_this->selectById(_this->devId);
|
_this->selectById(_this->devId);
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf["device"] = _this->devNameList[_this->devId];
|
config.conf["device"] = _this->devNameList[_this->devId];
|
||||||
config.release(true);
|
config.release(true);
|
||||||
@ -710,7 +711,6 @@ private:
|
|||||||
if (SmGui::Button(CONCAT("Refresh##sdrplay_refresh", _this->name))) {
|
if (SmGui::Button(CONCAT("Refresh##sdrplay_refresh", _this->name))) {
|
||||||
_this->refresh();
|
_this->refresh();
|
||||||
_this->selectByName(_this->selectedName);
|
_this->selectByName(_this->selectedName);
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SmGui::LeftLabel("Bandwidth");
|
SmGui::LeftLabel("Bandwidth");
|
||||||
|
@ -9,13 +9,8 @@
|
|||||||
#include <gui/smgui.h>
|
#include <gui/smgui.h>
|
||||||
#include <utils/optionlist.h>
|
#include <utils/optionlist.h>
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <locale>
|
|
||||||
#include <aaroniartsaapi.h>
|
#include <aaroniartsaapi.h>
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#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{
|
||||||
@ -194,6 +189,7 @@ public:
|
|||||||
|
|
||||||
// Set samplerate
|
// Set samplerate
|
||||||
samplerate = sampleRateList.value(srId);
|
samplerate = sampleRateList.value(srId);
|
||||||
|
core::setInputSampleRate(samplerate.effective);
|
||||||
|
|
||||||
// Close device
|
// Close device
|
||||||
AARTSAAPI_CloseDevice(&api, &dev);
|
AARTSAAPI_CloseDevice(&api, &dev);
|
||||||
@ -333,10 +329,9 @@ private:
|
|||||||
SmGui::FillWidth();
|
SmGui::FillWidth();
|
||||||
SmGui::ForceSync();
|
SmGui::ForceSync();
|
||||||
if (SmGui::Combo(CONCAT("##_spectran_dev_", _this->name), &_this->devId, _this->devList.txt)) {
|
if (SmGui::Combo(CONCAT("##_spectran_dev_", _this->name), &_this->devId, _this->devList.txt)) {
|
||||||
_this->selectSerial(_this->devList.key(_this->devId));
|
|
||||||
core::setInputSampleRate(_this->samplerate.effective);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
// TODO: SR sel
|
||||||
if (SmGui::Combo(CONCAT("##_spectran_sr_", _this->name), &_this->srId, _this->sampleRateList.txt)) {
|
if (SmGui::Combo(CONCAT("##_spectran_sr_", _this->name), &_this->srId, _this->sampleRateList.txt)) {
|
||||||
_this->samplerate = _this->sampleRateList.value(_this->srId);
|
_this->samplerate = _this->sampleRateList.value(_this->srId);
|
||||||
core::setInputSampleRate(_this->samplerate.effective);
|
core::setInputSampleRate(_this->samplerate.effective);
|
||||||
|
@ -211,6 +211,7 @@ public:
|
|||||||
|
|
||||||
// Apply samplerate
|
// Apply samplerate
|
||||||
sampleRate = samplerates.key(srId);
|
sampleRate = samplerates.key(srId);
|
||||||
|
core::setInputSampleRate(sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBandwidth(double bw) {
|
void setBandwidth(double bw) {
|
||||||
@ -334,7 +335,6 @@ private:
|
|||||||
SmGui::ForceSync();
|
SmGui::ForceSync();
|
||||||
if (SmGui::Combo(CONCAT("##_usrp_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
if (SmGui::Combo(CONCAT("##_usrp_dev_sel_", _this->name), &_this->devId, _this->devices.txt)) {
|
||||||
_this->select(_this->devices.key(_this->devId));
|
_this->select(_this->devices.key(_this->devId));
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
|
||||||
if (!_this->selectedSer.empty()) {
|
if (!_this->selectedSer.empty()) {
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf["device"] = _this->devices.key(_this->devId);
|
config.conf["device"] = _this->devices.key(_this->devId);
|
||||||
@ -357,8 +357,10 @@ private:
|
|||||||
SmGui::ForceSync();
|
SmGui::ForceSync();
|
||||||
if (SmGui::Button(CONCAT("Refresh##_usrp_refr_", _this->name))) {
|
if (SmGui::Button(CONCAT("Refresh##_usrp_refr_", _this->name))) {
|
||||||
_this->refresh();
|
_this->refresh();
|
||||||
_this->select(_this->selectedSer);
|
config.acquire();
|
||||||
core::setInputSampleRate(_this->sampleRate);
|
std::string ser = config.conf["device"];
|
||||||
|
config.release();
|
||||||
|
_this->select(ser);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_this->channels.size() > 1) {
|
if (_this->channels.size() > 1) {
|
||||||
|
Reference in New Issue
Block a user