mirror of
https://github.com/f4exb/sdrangel.git
synced 2026-04-25 08:53:59 -04:00
Merge master
This commit is contained in:
commit
ee35715bd4
2
.github/workflows/sdrangel.yml
vendored
2
.github/workflows/sdrangel.yml
vendored
@ -7,6 +7,8 @@ on:
|
||||
branches:
|
||||
- master
|
||||
- mac_ci
|
||||
- fix-*
|
||||
- feature-*
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
|
||||
@ -153,6 +153,7 @@ option(ENABLE_FEATURE_REMOTECONTROL "Enable feature remote control plugin" ON)
|
||||
option(ENABLE_FEATURE_SKYMAP "Enable feature sky map plugin" ON)
|
||||
option(ENABLE_FEATURE_SID "Enable feature sid plugin" ON)
|
||||
option(ENABLE_FEATURE_MORSEDECODER "Enable feature morsedecoder plugin" ON)
|
||||
option(ENABLE_FEATURE_DENOISER "Enable feature denoiser plugin" ON)
|
||||
|
||||
# on windows always build external libraries
|
||||
if(WIN32)
|
||||
@ -826,6 +827,7 @@ if (NOT ENABLE_EXTERNAL_LIBRARIES OR (ENABLE_EXTERNAL_LIBRARIES STREQUAL "AUTO")
|
||||
find_package(FFmpeg COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
|
||||
find_package(GGMorse)
|
||||
find_package(LibInmarsatC)
|
||||
find_package(RNnoise)
|
||||
|
||||
# Devices
|
||||
if(ENABLE_AIRSPY)
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "default",
|
||||
"binaryDir": "build-default",
|
||||
"binaryDir": "build",
|
||||
"cacheVariables": {
|
||||
"DEBUG_OUTPUT": "ON",
|
||||
"AIRSPYHF_DIR": "/opt/install/libairspyhf",
|
||||
@ -29,6 +29,7 @@
|
||||
"UHD_DIR": "/opt/install/uhd",
|
||||
"XTRX_DIR": "/opt/install/xtrx-images",
|
||||
"GGMORSE_DIR": "/opt/install/ggmorse",
|
||||
"RNNOISE_DIR": "/opt/install/rnnoise",
|
||||
"CMAKE_INSTALL_PREFIX": "/opt/install/sdrangel"
|
||||
},
|
||||
"warnings": {
|
||||
|
||||
38
cmake/Modules/FindRNnoise.cmake
Normal file
38
cmake/Modules/FindRNnoise.cmake
Normal file
@ -0,0 +1,38 @@
|
||||
if (NOT RNNOISE_FOUND)
|
||||
INCLUDE(FindPkgConfig)
|
||||
PKG_CHECK_MODULES(PC_RNNoise "librnnoise")
|
||||
|
||||
FIND_PATH(RNNOISE_INCLUDE_DIR
|
||||
NAMES rnnoise.h
|
||||
HINTS ${RNNOISE_DIR}/include
|
||||
${PC_RNNOISE_INCLUDE_DIR}
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
PATHS /usr/local/include
|
||||
/usr/include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(RNNOISE_LIBRARIES
|
||||
NAMES rnnoise librnnoise
|
||||
HINTS ${RNNOISE_DIR}/lib
|
||||
${RNNOISE_DIR}/lib64
|
||||
${PC_RNNOISE_LIBDIR}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
${CMAKE_INSTALL_PREFIX}/lib64
|
||||
PATHS /usr/local/lib
|
||||
/usr/local/lib64
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
)
|
||||
|
||||
if (RNNOISE_INCLUDE_DIR AND RNNOISE_LIBRARIES)
|
||||
set(RNNOISE_FOUND TRUE CACHE INTERNAL "RNNoise found")
|
||||
message(STATUS "Found RNNoise: ${RNNOISE_INCLUDE_DIR}, ${RNNOISE_LIBRARIES}")
|
||||
else (RNNOISE_INCLUDE_DIR AND RNNOISE_LIBRARIES)
|
||||
set(RNNOISE_FOUND FALSE CACHE INTERNAL "RNNoise found")
|
||||
message(STATUS "RNNoise not found")
|
||||
endif (RNNOISE_INCLUDE_DIR AND RNNOISE_LIBRARIES)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(RNNoise DEFAULT_MSG RNNOISE_LIBRARIES RNNOISE_INCLUDE_DIR)
|
||||
MARK_AS_ADVANCED(RNNOISE_LIBRARIES RNNOISE_INCLUDE_DIR)
|
||||
endif (NOT RNNOISE_FOUND)
|
||||
BIN
doc/img/DenoiserFeature_plugin.png
Normal file
BIN
doc/img/DenoiserFeature_plugin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
BIN
doc/img/DenoiserFeature_plugin.xcf
Normal file
BIN
doc/img/DenoiserFeature_plugin.xcf
Normal file
Binary file not shown.
30
external/CMakeLists.txt
vendored
30
external/CMakeLists.txt
vendored
@ -968,6 +968,36 @@ if(ENABLE_CHANNELRX_DEMODINMARSAT)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
# For denoiser feature
|
||||
if(LINUX AND ENABLE_FEATURE_DENOISER)
|
||||
if (WIN32)
|
||||
set(RNNOISE_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/rnnoise.lib" CACHE INTERNAL "")
|
||||
set(RNNOISE_ARGS "-DRNN_ENABLE_X86_RTCD=OFF")
|
||||
elseif (LINUX)
|
||||
set(RNNOISE_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib${LIB_SUFFIX}/librnnoise${CMAKE_SHARED_LIBRARY_SUFFIX}" CACHE INTERNAL "")
|
||||
set(RNNOISE_ARGS "-DRNN_ENABLE_X86_RTCD=ON")
|
||||
endif()
|
||||
ExternalProject_Add(rnnoise
|
||||
GIT_REPOSITORY https://github.com/f4exb/rnnoise.git
|
||||
GIT_TAG "main"
|
||||
PREFIX "${EXTERNAL_BUILD_LIBRARIES}/rnnoise"
|
||||
CMAKE_ARGS ${COMMON_CMAKE_ARGS}
|
||||
${RNNOISE_ARGS}
|
||||
-DRNNOISE_BUILD=ON
|
||||
BUILD_BYPRODUCTS "${RNNOISE_LIBRARIES}"
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
ExternalProject_Get_Property(rnnoise source_dir binary_dir)
|
||||
set(RNNOISE_DEPENDS rnnoise CACHE INTERNAL "")
|
||||
set_global_cache(RNNOISE_FOUND ON)
|
||||
set(RNNOISE_EXTERNAL ON CACHE INTERNAL "")
|
||||
set(RNNOISE_INCLUDE_DIR "${EXTERNAL_BUILD_LIBRARIES}/rnnoise/src/rnnoise/include" CACHE INTERNAL "")
|
||||
if (WIN32)
|
||||
install(FILES "${SDRANGEL_BINARY_BIN_DIR}/rnnoise${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
# VkFFT (header only library)
|
||||
ExternalProject_Add(vkfft
|
||||
GIT_REPOSITORY https://github.com/DTolm/VkFFT.git
|
||||
|
||||
@ -106,6 +106,8 @@ void AMDemodSink::processOneSample(Complex &ci)
|
||||
m_movingAverage(magsq);
|
||||
m_magsq = m_movingAverage.asDouble();
|
||||
m_magsqSum += magsq;
|
||||
QList<ObjectPipe*> dataPipes;
|
||||
MainCore::instance()->getDataPipes().getDataPipes(m_channel, "demod", dataPipes);
|
||||
|
||||
if (magsq > m_magsqPeak)
|
||||
{
|
||||
@ -133,7 +135,7 @@ void AMDemodSink::processOneSample(Complex &ci)
|
||||
|
||||
m_squelchOpen = (m_squelchCount >= m_audioSampleRate / 20);
|
||||
|
||||
if (m_squelchOpen && !m_settings.m_audioMute)
|
||||
if (m_squelchOpen && (!m_settings.m_audioMute || dataPipes.size() > 0))
|
||||
{
|
||||
Real demod;
|
||||
|
||||
@ -198,8 +200,8 @@ void AMDemodSink::processOneSample(Complex &ci)
|
||||
sample = 0;
|
||||
}
|
||||
|
||||
m_audioBuffer[m_audioBufferFill].l = sample;
|
||||
m_audioBuffer[m_audioBufferFill].r = sample;
|
||||
m_audioBuffer[m_audioBufferFill].l = m_settings.m_audioMute ? 0 : sample;
|
||||
m_audioBuffer[m_audioBufferFill].r = m_settings.m_audioMute ? 0 : sample;
|
||||
++m_audioBufferFill;
|
||||
|
||||
if (m_audioBufferFill >= m_audioBuffer.size())
|
||||
@ -220,9 +222,6 @@ void AMDemodSink::processOneSample(Complex &ci)
|
||||
|
||||
if (m_demodBufferFill >= m_demodBuffer.size())
|
||||
{
|
||||
QList<ObjectPipe*> dataPipes;
|
||||
MainCore::instance()->getDataPipes().getDataPipes(m_channel, "demod", dataPipes);
|
||||
|
||||
if (dataPipes.size() > 0)
|
||||
{
|
||||
QList<ObjectPipe*>::iterator it = dataPipes.begin();
|
||||
|
||||
@ -95,10 +95,6 @@ void BFMDemodSink::feed(const SampleVector::const_iterator& begin, const SampleV
|
||||
|
||||
m_sampleBuffer.clear();
|
||||
|
||||
if (m_settings.m_audioMute) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (SampleVector::const_iterator it = begin; it != end; ++it)
|
||||
{
|
||||
Complex c(it->real() / SDR_RX_SCALEF, it->imag() / SDR_RX_SCALEF);
|
||||
@ -199,25 +195,30 @@ void BFMDemodSink::feed(const SampleVector::const_iterator& begin, const SampleV
|
||||
|
||||
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, e, &ci))
|
||||
{
|
||||
qint16 sample_l;
|
||||
qint16 sample_r;
|
||||
|
||||
if (m_settings.m_audioStereo)
|
||||
{
|
||||
Real deemph_l, deemph_r; // Pre-emphasis is applied on each channel before multiplexing
|
||||
m_deemphasisFilterX.process(ci.real() + sampleStereo, deemph_l);
|
||||
m_deemphasisFilterY.process(ci.real() - sampleStereo, deemph_r);
|
||||
m_audioBuffer[m_audioBufferFill].l = (qint16)(deemph_l * (1<<12) * m_settings.m_volume);
|
||||
m_audioBuffer[m_audioBufferFill].r = (qint16)(deemph_r * (1<<12) * m_settings.m_volume);
|
||||
sample_l = (qint16)(deemph_l * (1<<12) * m_settings.m_volume);
|
||||
sample_r = (qint16)(deemph_r * (1<<12) * m_settings.m_volume);
|
||||
}
|
||||
else
|
||||
{
|
||||
Real deemph;
|
||||
m_deemphasisFilterX.process(ci.real(), deemph);
|
||||
quint16 sample = (qint16)(deemph * (1<<12) * m_settings.m_volume);
|
||||
m_audioBuffer[m_audioBufferFill].l = sample;
|
||||
m_audioBuffer[m_audioBufferFill].r = sample;
|
||||
sample_l = sample;
|
||||
sample_r = sample;
|
||||
}
|
||||
|
||||
m_demodBuffer[m_demodBufferFill++] = m_audioBuffer[m_audioBufferFill].l;
|
||||
m_demodBuffer[m_demodBufferFill++] = m_audioBuffer[m_audioBufferFill].r;
|
||||
m_audioBuffer[m_audioBufferFill].l = m_settings.m_audioMute ? 0 : sample_l;
|
||||
m_audioBuffer[m_audioBufferFill].r = m_settings.m_audioMute ? 0 : sample_r;
|
||||
m_demodBuffer[m_demodBufferFill++] = sample_l;
|
||||
m_demodBuffer[m_demodBufferFill++] = sample_r;
|
||||
|
||||
++m_audioBufferFill;
|
||||
|
||||
|
||||
@ -556,9 +556,9 @@ void InmarsatDemodSink::processOneSample(Complex &ci)
|
||||
m_symbolBuffer.push(m_bit, m_eq);
|
||||
if (m_symbolBuffer.checkUW())
|
||||
{
|
||||
if (m_syncedToUW && (m_symbolCounter != m_symbolBuffer.size() - 1)) {
|
||||
/*if (m_syncedToUW && (m_symbolCounter != m_symbolBuffer.size() - 1)) {
|
||||
qDebug() << "Already synced" << m_symbolCounter << m_symbolBuffer.size();
|
||||
}
|
||||
}*/
|
||||
m_symbolCounter = 0;
|
||||
if (!m_syncedToUW && (m_settings.m_equalizer == InmarsatDemodSettings::LMS))
|
||||
{
|
||||
|
||||
@ -163,6 +163,8 @@ void NFMDemodSink::processOneSample(Complex &ci)
|
||||
m_squelchOpen = m_squelchCount > m_squelchGate;
|
||||
int ctcssIndex = m_squelchOpen && m_settings.m_ctcssOn ? m_ctcssIndex : 0;
|
||||
unsigned int dcsCode = m_squelchOpen && m_settings.m_dcsOn ? m_dcsCode : 0;
|
||||
QList<ObjectPipe*> dataPipes;
|
||||
MainCore::instance()->getDataPipes().getDataPipes(m_channel, "demod", dataPipes);
|
||||
|
||||
if (m_squelchOpen)
|
||||
{
|
||||
@ -196,7 +198,7 @@ void NFMDemodSink::processOneSample(Complex &ci)
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_settings.m_audioMute &&
|
||||
if ((!m_settings.m_audioMute || dataPipes.size() > 0) &&
|
||||
(!m_settings.m_ctcssOn || m_ctcssIndexSelected == ctcssIndex || m_ctcssIndexSelected == 0) &&
|
||||
(!m_settings.m_dcsOn || m_dcsCodeSeleted == dcsCode || m_dcsCodeSeleted == 0))
|
||||
{
|
||||
@ -232,8 +234,8 @@ void NFMDemodSink::processOneSample(Complex &ci)
|
||||
m_dcsCode = dcsCode;
|
||||
}
|
||||
|
||||
m_audioBuffer[m_audioBufferFill].l = sample;
|
||||
m_audioBuffer[m_audioBufferFill].r = sample;
|
||||
m_audioBuffer[m_audioBufferFill].l = m_settings.m_audioMute ? 0 : sample;
|
||||
m_audioBuffer[m_audioBufferFill].r = m_settings.m_audioMute ? 0 : sample;
|
||||
++m_audioBufferFill;
|
||||
|
||||
if (m_audioBufferFill >= m_audioBuffer.size())
|
||||
@ -254,9 +256,6 @@ void NFMDemodSink::processOneSample(Complex &ci)
|
||||
|
||||
if (m_demodBufferFill >= m_demodBuffer.size())
|
||||
{
|
||||
QList<ObjectPipe*> dataPipes;
|
||||
MainCore::instance()->getDataPipes().getDataPipes(m_channel, "demod", dataPipes);
|
||||
|
||||
if (dataPipes.size() > 0)
|
||||
{
|
||||
QList<ObjectPipe*>::iterator it = dataPipes.begin();
|
||||
|
||||
@ -123,6 +123,8 @@ void SSBDemodSink::processOneSample(Complex &ci)
|
||||
int n_out = 0;
|
||||
int decim = 1<<(m_spanLog2 - 1);
|
||||
unsigned char decim_mask = decim - 1; // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
|
||||
QList<ObjectPipe*> dataPipes;
|
||||
MainCore::instance()->getDataPipes().getDataPipes(m_channel, "demod", dataPipes);
|
||||
|
||||
if (m_dsb) {
|
||||
n_out = DSBFilter->runDSB(ci, &sideband);
|
||||
@ -182,64 +184,58 @@ void SSBDemodSink::processOneSample(Complex &ci)
|
||||
m_squelchDelayLine.write(sideband[i]*agcVal);
|
||||
}
|
||||
|
||||
if (m_audioMute)
|
||||
fftfilt::cmplx z = (m_agcActive && m_agcClamping) ?
|
||||
fftfilt::cmplx{m_lowpassI.filter(delayedSample.real()), m_lowpassQ.filter(delayedSample.imag())}
|
||||
: delayedSample;
|
||||
qint16 sample_l;
|
||||
qint16 sample_r;
|
||||
|
||||
if (m_audioBinaual)
|
||||
{
|
||||
m_audioBuffer[m_audioBufferFill].r = 0;
|
||||
m_audioBuffer[m_audioBufferFill].l = 0;
|
||||
Real left = m_audioFlipChannels ? z.imag() : z.real();
|
||||
Real right = m_audioFlipChannels ? z.real() : z.imag();
|
||||
left = std::clamp(left * m_volume, -32767.0f, 32767.0f);
|
||||
right = std::clamp(right * m_volume, -32767.0f, 32767.0f);
|
||||
sample_l = (qint16) left;
|
||||
sample_r = (qint16) right;
|
||||
|
||||
m_demodBuffer[m_demodBufferFill++] = z.real();
|
||||
m_demodBuffer[m_demodBufferFill++] = z.imag();
|
||||
}
|
||||
else
|
||||
{
|
||||
fftfilt::cmplx z = (m_agcActive && m_agcClamping) ?
|
||||
fftfilt::cmplx{m_lowpassI.filter(delayedSample.real()), m_lowpassQ.filter(delayedSample.imag())}
|
||||
: delayedSample;
|
||||
Real demod = (z.real() + z.imag()) * 0.7;
|
||||
qint16 sample = (qint16)(std::clamp(demod * m_volume, -32767.0f, 32767.0f));
|
||||
sample_l = sample;
|
||||
sample_r = sample;
|
||||
m_demodBuffer[m_demodBufferFill++] = (z.real() + z.imag()) * 0.7;
|
||||
}
|
||||
|
||||
if (m_audioBinaual)
|
||||
m_audioBuffer[m_audioBufferFill].l = m_audioMute ? 0 : sample_l;
|
||||
m_audioBuffer[m_audioBufferFill].r = m_audioMute ? 0 : sample_r;
|
||||
|
||||
if (m_demodBufferFill >= m_demodBuffer.size())
|
||||
{
|
||||
if (dataPipes.size() > 0)
|
||||
{
|
||||
Real left = m_audioFlipChannels ? z.imag() : z.real();
|
||||
Real right = m_audioFlipChannels ? z.real() : z.imag();
|
||||
left = std::clamp(left * m_volume, -32767.0f, 32767.0f);
|
||||
right = std::clamp(right * m_volume, -32767.0f, 32767.0f);
|
||||
m_audioBuffer[m_audioBufferFill].l = (qint16)left;
|
||||
m_audioBuffer[m_audioBufferFill].r = (qint16)right;
|
||||
QList<ObjectPipe*>::iterator it = dataPipes.begin();
|
||||
|
||||
m_demodBuffer[m_demodBufferFill++] = z.real();
|
||||
m_demodBuffer[m_demodBufferFill++] = z.imag();
|
||||
}
|
||||
else
|
||||
{
|
||||
Real demod = (z.real() + z.imag()) * 0.7;
|
||||
qint16 sample = (qint16)(std::clamp(demod * m_volume, -32767.0f, 32767.0f));
|
||||
m_audioBuffer[m_audioBufferFill].l = sample;
|
||||
m_audioBuffer[m_audioBufferFill].r = sample;
|
||||
m_demodBuffer[m_demodBufferFill++] = (z.real() + z.imag()) * 0.7;
|
||||
}
|
||||
|
||||
if (m_demodBufferFill >= m_demodBuffer.size())
|
||||
{
|
||||
QList<ObjectPipe*> dataPipes;
|
||||
MainCore::instance()->getDataPipes().getDataPipes(m_channel, "demod", dataPipes);
|
||||
|
||||
if (dataPipes.size() > 0)
|
||||
for (; it != dataPipes.end(); ++it)
|
||||
{
|
||||
QList<ObjectPipe*>::iterator it = dataPipes.begin();
|
||||
DataFifo *fifo = qobject_cast<DataFifo*>((*it)->m_element);
|
||||
|
||||
for (; it != dataPipes.end(); ++it)
|
||||
if (fifo)
|
||||
{
|
||||
DataFifo *fifo = qobject_cast<DataFifo*>((*it)->m_element);
|
||||
|
||||
if (fifo)
|
||||
{
|
||||
fifo->write(
|
||||
(quint8*) &m_demodBuffer[0],
|
||||
m_demodBuffer.size() * sizeof(qint16),
|
||||
m_audioBinaual ? DataFifo::DataTypeCI16 : DataFifo::DataTypeI16
|
||||
);
|
||||
}
|
||||
fifo->write(
|
||||
(quint8*) &m_demodBuffer[0],
|
||||
m_demodBuffer.size() * sizeof(qint16),
|
||||
m_audioBinaual ? DataFifo::DataTypeCI16 : DataFifo::DataTypeI16
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
m_demodBufferFill = 0;
|
||||
}
|
||||
|
||||
m_demodBufferFill = 0;
|
||||
}
|
||||
|
||||
++m_audioBufferFill;
|
||||
|
||||
@ -67,6 +67,8 @@ void WFMDemodSink::feed(const SampleVector::const_iterator& begin, const SampleV
|
||||
Real demod;
|
||||
double msq;
|
||||
float fmDev;
|
||||
QList<ObjectPipe*> dataPipes;
|
||||
MainCore::instance()->getDataPipes().getDataPipes(m_channel, "demod", dataPipes);
|
||||
|
||||
for (SampleVector::const_iterator it = begin; it != end; ++it)
|
||||
{
|
||||
@ -103,7 +105,7 @@ void WFMDemodSink::feed(const SampleVector::const_iterator& begin, const SampleV
|
||||
|
||||
m_squelchOpen = (m_squelchState > (m_settings.m_rfBandwidth / 20));
|
||||
|
||||
if (m_squelchOpen && !m_settings.m_audioMute) { // squelch open and not mute
|
||||
if (m_squelchOpen && (!m_settings.m_audioMute || dataPipes.size() > 0)) { // squelch open and not mute
|
||||
demod = m_phaseDiscri.phaseDiscriminatorDelta(rf[i], msq, fmDev);
|
||||
} else {
|
||||
demod = 0;
|
||||
@ -114,8 +116,8 @@ void WFMDemodSink::feed(const SampleVector::const_iterator& begin, const SampleV
|
||||
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, e, &ci))
|
||||
{
|
||||
qint16 sample = (qint16)(ci.real() * 3276.8f * m_settings.m_volume);
|
||||
m_audioBuffer[m_audioBufferFill].l = sample;
|
||||
m_audioBuffer[m_audioBufferFill].r = sample;
|
||||
m_audioBuffer[m_audioBufferFill].l = m_settings.m_audioMute ? 0 : sample;
|
||||
m_audioBuffer[m_audioBufferFill].r = m_settings.m_audioMute ? 0 : sample;
|
||||
|
||||
++m_audioBufferFill;
|
||||
|
||||
@ -136,9 +138,6 @@ void WFMDemodSink::feed(const SampleVector::const_iterator& begin, const SampleV
|
||||
|
||||
if (m_demodBufferFill >= m_demodBuffer.size())
|
||||
{
|
||||
QList<ObjectPipe*> dataPipes;
|
||||
MainCore::instance()->getDataPipes().getDataPipes(m_channel, "demod", dataPipes);
|
||||
|
||||
if (dataPipes.size() > 0)
|
||||
{
|
||||
QList<ObjectPipe*>::iterator it = dataPipes.begin();
|
||||
|
||||
@ -149,6 +149,8 @@ void WDSPRxSink::feed(const SampleVector::const_iterator& begin, const SampleVec
|
||||
}
|
||||
|
||||
Complex ci;
|
||||
QList<ObjectPipe*> dataPipes;
|
||||
MainCore::instance()->getDataPipes().getDataPipes(m_channel, "demod", dataPipes);
|
||||
|
||||
for(SampleVector::const_iterator it = begin; it < end; ++it)
|
||||
{
|
||||
@ -159,7 +161,7 @@ void WDSPRxSink::feed(const SampleVector::const_iterator& begin, const SampleVec
|
||||
{
|
||||
while (!m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci))
|
||||
{
|
||||
processOneSample(ci);
|
||||
processOneSample(ci, dataPipes);
|
||||
m_interpolatorDistanceRemain += m_interpolatorDistance;
|
||||
}
|
||||
}
|
||||
@ -167,7 +169,7 @@ void WDSPRxSink::feed(const SampleVector::const_iterator& begin, const SampleVec
|
||||
{
|
||||
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci))
|
||||
{
|
||||
processOneSample(ci);
|
||||
processOneSample(ci, dataPipes);
|
||||
m_interpolatorDistanceRemain += m_interpolatorDistance;
|
||||
}
|
||||
}
|
||||
@ -181,7 +183,7 @@ void WDSPRxSink::getMagSqLevels(double& avg, double& peak, int& nbSamples) const
|
||||
nbSamples = m_sCount;
|
||||
}
|
||||
|
||||
void WDSPRxSink::processOneSample(const Complex &ci)
|
||||
void WDSPRxSink::processOneSample(const Complex &ci, QList<ObjectPipe*>& dataPipes)
|
||||
{
|
||||
m_rxa->get_inbuff()[2*m_inCount] = ci.imag() / SDR_RX_SCALEF;
|
||||
m_rxa->get_inbuff()[2*m_inCount+1] = ci.real() / SDR_RX_SCALEF;
|
||||
@ -196,20 +198,13 @@ void WDSPRxSink::processOneSample(const Complex &ci)
|
||||
|
||||
for (int i = 0; i < m_rxa->get_outsize(); i++)
|
||||
{
|
||||
if (m_settings.m_audioMute)
|
||||
{
|
||||
m_audioBuffer[m_audioBufferFill].r = 0;
|
||||
m_audioBuffer[m_audioBufferFill].l = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const double& dr = m_rxa->get_outbuff()[2*i+1];
|
||||
const double& di = m_rxa->get_outbuff()[2*i];
|
||||
qint16 zr = dr * 32768.0;
|
||||
qint16 zi = di * 32768.0;
|
||||
m_audioBuffer[m_audioBufferFill].r = zr;
|
||||
m_audioBuffer[m_audioBufferFill].l = zi;
|
||||
const double& dr = m_rxa->get_outbuff()[2*i+1];
|
||||
const double& di = m_rxa->get_outbuff()[2*i];
|
||||
qint16 zr = dr * 32768.0;
|
||||
qint16 zi = di * 32768.0;
|
||||
|
||||
if (!dataPipes.empty())
|
||||
{
|
||||
if (m_settings.m_audioBinaural)
|
||||
{
|
||||
m_demodBuffer[m_demodBufferFill++] = zr;
|
||||
@ -224,28 +219,34 @@ void WDSPRxSink::processOneSample(const Complex &ci)
|
||||
|
||||
if (m_demodBufferFill >= m_demodBuffer.size())
|
||||
{
|
||||
QList<ObjectPipe*> dataPipes;
|
||||
MainCore::instance()->getDataPipes().getDataPipes(m_channel, "demod", dataPipes);
|
||||
|
||||
if (!dataPipes.empty())
|
||||
for (auto dataPipe : dataPipes)
|
||||
{
|
||||
for (auto dataPipe : dataPipes)
|
||||
{
|
||||
DataFifo *fifo = qobject_cast<DataFifo*>(dataPipe->m_element);
|
||||
DataFifo *fifo = qobject_cast<DataFifo*>(dataPipe->m_element);
|
||||
|
||||
if (fifo)
|
||||
{
|
||||
fifo->write(
|
||||
(quint8*) &m_demodBuffer[0],
|
||||
m_demodBuffer.size() * sizeof(qint16),
|
||||
m_settings.m_audioBinaural ? DataFifo::DataTypeCI16 : DataFifo::DataTypeI16
|
||||
);
|
||||
}
|
||||
if (fifo)
|
||||
{
|
||||
fifo->write(
|
||||
(quint8*) &m_demodBuffer[0],
|
||||
m_demodBuffer.size() * sizeof(qint16),
|
||||
m_settings.m_audioBinaural ? DataFifo::DataTypeCI16 : DataFifo::DataTypeI16
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_demodBufferFill = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_settings.m_audioMute)
|
||||
{
|
||||
m_audioBuffer[m_audioBufferFill].r = 0;
|
||||
m_audioBuffer[m_audioBufferFill].l = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_audioBuffer[m_audioBufferFill].r = zr;
|
||||
m_audioBuffer[m_audioBufferFill].l = zi;
|
||||
|
||||
} // audio sample
|
||||
|
||||
if (++m_audioBufferFill == m_audioBuffer.size())
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "audio/audiofifo.h"
|
||||
#include "util/doublebufferfifo.h"
|
||||
#include "bufferprobe.hpp"
|
||||
#include "pipes/datapipes.h"
|
||||
|
||||
#include "wdsprxsettings.h"
|
||||
|
||||
@ -122,7 +123,7 @@ private:
|
||||
static const int m_wdspSampleRate;
|
||||
static const int m_wdspBufSize;
|
||||
|
||||
void processOneSample(const Complex &ci);
|
||||
void processOneSample(const Complex &ci, QList<ObjectPipe*>& dataPipes);
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SSBDEMODSINK_H
|
||||
|
||||
@ -132,3 +132,9 @@ if (ENABLE_FEATURE_MORSEDECODER AND GGMORSE_FOUND)
|
||||
else()
|
||||
message(STATUS "Not building morsedecoder (ENABLE_FEATURE_MORSEDECODER=${ENABLE_FEATURE_MORSEDECODER} GGMODSE_FOUND=${GGMORSE_FOUND})")
|
||||
endif()
|
||||
|
||||
if (ENABLE_FEATURE_DENOISER AND RNNOISE_FOUND)
|
||||
add_subdirectory(denoiser)
|
||||
else()
|
||||
message(STATUS "Not building denoiser (ENABLE_FEATURE_DENOISER=${ENABLE_FEATURE_DENOISER} RNNOISE_FOUND=${RNNOISE_FOUND})")
|
||||
endif()
|
||||
|
||||
69
plugins/feature/denoiser/CMakeLists.txt
Normal file
69
plugins/feature/denoiser/CMakeLists.txt
Normal file
@ -0,0 +1,69 @@
|
||||
project(denoiser)
|
||||
|
||||
set(denoiser_SOURCES
|
||||
denoiser.cpp
|
||||
denoisersettings.cpp
|
||||
denoiserplugin.cpp
|
||||
denoiserworker.cpp
|
||||
denoiserwebapiadapter.cpp
|
||||
)
|
||||
|
||||
set(denoiser_HEADERS
|
||||
denoiser.h
|
||||
denoisersettings.h
|
||||
denoiserplugin.h
|
||||
denoiserworker.h
|
||||
denoiserwebapiadapter.h
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
${RNNOISE_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if(NOT SERVER_MODE)
|
||||
set(denoiser_SOURCES
|
||||
${denoiser_SOURCES}
|
||||
denoisergui.cpp
|
||||
denoisergui.ui
|
||||
)
|
||||
set(denoiser_HEADERS
|
||||
${denoiser_HEADERS}
|
||||
denoisergui.h
|
||||
)
|
||||
|
||||
set(TARGET_NAME ${PLUGINS_PREFIX}featuredenoiser)
|
||||
set(TARGET_LIB "Qt::Widgets")
|
||||
set(TARGET_LIB_GUI "sdrgui")
|
||||
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
|
||||
else()
|
||||
set(TARGET_NAME ${PLUGINSSRV_PREFIX}featuredenoisersrv)
|
||||
set(TARGET_LIB "")
|
||||
set(TARGET_LIB_GUI "")
|
||||
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
|
||||
endif()
|
||||
|
||||
if(NOT Qt6_FOUND)
|
||||
add_library(${TARGET_NAME} ${denoiser_SOURCES})
|
||||
else()
|
||||
qt_add_plugin(${TARGET_NAME} CLASS_NAME DenoiserPlugin ${denoiser_SOURCES})
|
||||
endif()
|
||||
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
set_property(GLOBAL APPEND PROPERTY STATIC_PLUGINS_PROPERTY ${TARGET_NAME})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} PRIVATE
|
||||
Qt::Core
|
||||
${TARGET_LIB}
|
||||
sdrbase
|
||||
${TARGET_LIB_GUI}
|
||||
${RNNOISE_LIBRARIES}
|
||||
)
|
||||
|
||||
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
|
||||
|
||||
# Install debug symbols
|
||||
if (WIN32)
|
||||
install(FILES $<TARGET_PDB_FILE:${TARGET_NAME}> CONFIGURATIONS Debug RelWithDebInfo DESTINATION ${INSTALL_FOLDER} )
|
||||
endif()
|
||||
710
plugins/feature/denoiser/denoiser.cpp
Normal file
710
plugins/feature/denoiser/denoiser.cpp
Normal file
@ -0,0 +1,710 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QDebug>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QBuffer>
|
||||
|
||||
#include "SWGFeatureSettings.h"
|
||||
#include "SWGFeatureActions.h"
|
||||
#include "SWGDeviceState.h"
|
||||
|
||||
#include "dsp/dspcommands.h"
|
||||
#include "dsp/datafifo.h"
|
||||
#include "settings/serializable.h"
|
||||
#include "channel/channelapi.h"
|
||||
#include "maincore.h"
|
||||
|
||||
#include "denoiserworker.h"
|
||||
#include "denoiser.h"
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(Denoiser::MsgConfigureDenoiser, Message)
|
||||
MESSAGE_CLASS_DEFINITION(Denoiser::MsgStartStop, Message)
|
||||
MESSAGE_CLASS_DEFINITION(Denoiser::MsgReportChannels, Message)
|
||||
MESSAGE_CLASS_DEFINITION(Denoiser::MsgSelectChannel, Message)
|
||||
MESSAGE_CLASS_DEFINITION(Denoiser::MsgReportSampleRate, Message)
|
||||
|
||||
const char* const Denoiser::m_featureIdURI = "sdrangel.feature.denoiser";
|
||||
const char* const Denoiser::m_featureId = "Denoiser";
|
||||
|
||||
Denoiser::Denoiser(WebAPIAdapterInterface *webAPIAdapterInterface) :
|
||||
Feature(m_featureIdURI, webAPIAdapterInterface),
|
||||
m_thread(nullptr),
|
||||
m_running(false),
|
||||
m_worker(nullptr),
|
||||
m_availableChannelOrFeatureHandler(DenoiserSettings::m_channelURIs),
|
||||
m_selectedChannel(nullptr),
|
||||
m_dataPipe(nullptr)
|
||||
{
|
||||
qDebug("Denoiser::Denoiser: webAPIAdapterInterface: %p", webAPIAdapterInterface);
|
||||
setObjectName(m_featureId);
|
||||
m_state = StIdle;
|
||||
m_errorMessage = "Denoiser error";
|
||||
m_networkManager = new QNetworkAccessManager();
|
||||
QObject::connect(
|
||||
m_networkManager,
|
||||
&QNetworkAccessManager::finished,
|
||||
this,
|
||||
&Denoiser::networkManagerFinished
|
||||
);
|
||||
QObject::connect(
|
||||
&m_availableChannelOrFeatureHandler,
|
||||
&AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged,
|
||||
this,
|
||||
&Denoiser::channelsOrFeaturesChanged
|
||||
);
|
||||
m_availableChannelOrFeatureHandler.scanAvailableChannelsAndFeatures();
|
||||
}
|
||||
|
||||
Denoiser::~Denoiser()
|
||||
{
|
||||
QObject::disconnect(
|
||||
&m_availableChannelOrFeatureHandler,
|
||||
&AvailableChannelOrFeatureHandler::channelsOrFeaturesChanged,
|
||||
this,
|
||||
&Denoiser::channelsOrFeaturesChanged
|
||||
);
|
||||
QObject::disconnect(
|
||||
m_networkManager,
|
||||
&QNetworkAccessManager::finished,
|
||||
this,
|
||||
&Denoiser::networkManagerFinished
|
||||
);
|
||||
delete m_networkManager;
|
||||
|
||||
if (m_running)
|
||||
{
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void Denoiser::start()
|
||||
{
|
||||
QMutexLocker m_lock(&m_mutex);
|
||||
|
||||
if (m_running) {
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug("Denoiser::start");
|
||||
m_thread = new QThread();
|
||||
m_worker = new DenoiserWorker();
|
||||
m_worker->moveToThread(m_thread);
|
||||
|
||||
QObject::connect(
|
||||
m_thread,
|
||||
&QThread::started,
|
||||
m_worker,
|
||||
&DenoiserWorker::startWork
|
||||
);
|
||||
QObject::connect(
|
||||
m_thread,
|
||||
&QThread::finished,
|
||||
m_worker,
|
||||
&QObject::deleteLater
|
||||
);
|
||||
QObject::connect(
|
||||
m_thread,
|
||||
&QThread::finished,
|
||||
m_thread,
|
||||
&QThread::deleteLater
|
||||
);
|
||||
|
||||
m_worker->setMessageQueueToFeature(getInputMessageQueue());
|
||||
m_worker->startWork();
|
||||
m_state = StRunning;
|
||||
m_thread->start();
|
||||
|
||||
DenoiserWorker::MsgConfigureDenoiserWorker *msg
|
||||
= DenoiserWorker::MsgConfigureDenoiserWorker::create(m_settings, QList<QString>(), true);
|
||||
m_worker->getInputMessageQueue()->push(msg);
|
||||
m_worker->applySampleRate(m_sampleRate);
|
||||
|
||||
if (m_dataPipe)
|
||||
{
|
||||
DataFifo *fifo = qobject_cast<DataFifo*>(m_dataPipe->m_element);
|
||||
|
||||
if (fifo)
|
||||
{
|
||||
DenoiserWorker::MsgConnectFifo *msg = DenoiserWorker::MsgConnectFifo::create(fifo, true);
|
||||
m_worker->getInputMessageQueue()->push(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_levelMeter) {
|
||||
connect(m_worker, SIGNAL(levelChanged(qreal, qreal, int)), m_levelMeter, SLOT(levelChanged(qreal, qreal, int)));
|
||||
}
|
||||
|
||||
|
||||
m_running = true;
|
||||
}
|
||||
|
||||
void Denoiser::stop()
|
||||
{
|
||||
QMutexLocker m_lock(&m_mutex);
|
||||
|
||||
if (!m_running) {
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug("Denoiser::stop");
|
||||
m_running = false;
|
||||
|
||||
if (m_dataPipe)
|
||||
{
|
||||
DataFifo *fifo = qobject_cast<DataFifo*>(m_dataPipe->m_element);
|
||||
|
||||
if (fifo)
|
||||
{
|
||||
DenoiserWorker::MsgConnectFifo *msg = DenoiserWorker::MsgConnectFifo::create(fifo, false);
|
||||
m_worker->getInputMessageQueue()->push(msg);
|
||||
}
|
||||
}
|
||||
|
||||
m_worker->stopWork();
|
||||
m_state = StIdle;
|
||||
m_thread->quit();
|
||||
m_thread->wait();
|
||||
}
|
||||
|
||||
double Denoiser::getMagSqAvg() const
|
||||
{
|
||||
return m_running ? m_worker->getMagSqAvg() : 0.0;
|
||||
}
|
||||
|
||||
bool Denoiser::handleMessage(const Message& cmd)
|
||||
{
|
||||
if (MsgConfigureDenoiser::match(cmd))
|
||||
{
|
||||
MsgConfigureDenoiser& cfg = (MsgConfigureDenoiser&) cmd;
|
||||
qDebug() << "Denoiser::handleMessage: MsgConfigureDenoiser";
|
||||
applySettings(cfg.getSettings(), cfg.getSettingsKeys(), cfg.getForce());
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (MsgStartStop::match(cmd))
|
||||
{
|
||||
MsgStartStop& cfg = (MsgStartStop&) cmd;
|
||||
qDebug() << "Denoiser::handleMessage: MsgStartStop: start:" << cfg.getStartStop();
|
||||
|
||||
if (cfg.getStartStop()) {
|
||||
start();
|
||||
} else {
|
||||
stop();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (MsgSelectChannel::match(cmd))
|
||||
{
|
||||
MsgSelectChannel& cfg = (MsgSelectChannel&) cmd;
|
||||
ChannelAPI *selectedChannel = cfg.getChannel();
|
||||
qDebug("Denoiser::handleMessage: MsgSelectChannel: %p %s",
|
||||
selectedChannel, qPrintable(selectedChannel->objectName()));
|
||||
setChannel(selectedChannel);
|
||||
MainCore::MsgChannelDemodQuery *msg = MainCore::MsgChannelDemodQuery::create();
|
||||
selectedChannel->getInputMessageQueue()->push(msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (MainCore::MsgChannelDemodReport::match(cmd))
|
||||
{
|
||||
qDebug() << "Denoiser::handleMessage: MainCore::MsgChannelDemodReport";
|
||||
MainCore::MsgChannelDemodReport& report = (MainCore::MsgChannelDemodReport&) cmd;
|
||||
|
||||
if (report.getChannelAPI() == m_selectedChannel)
|
||||
{
|
||||
m_sampleRate = report.getSampleRate();
|
||||
|
||||
if (m_running) {
|
||||
m_worker->applySampleRate(m_sampleRate);
|
||||
}
|
||||
|
||||
if (m_dataPipe)
|
||||
{
|
||||
DataFifo *fifo = qobject_cast<DataFifo*>(m_dataPipe->m_element);
|
||||
|
||||
if (fifo) {
|
||||
fifo->setSize(2*m_sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
if (getMessageQueueToGUI())
|
||||
{
|
||||
MsgReportSampleRate *msg = MsgReportSampleRate::create(m_sampleRate);
|
||||
getMessageQueueToGUI()->push(msg);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray Denoiser::serialize() const
|
||||
{
|
||||
return m_settings.serialize();
|
||||
}
|
||||
|
||||
bool Denoiser::deserialize(const QByteArray& data)
|
||||
{
|
||||
if (m_settings.deserialize(data))
|
||||
{
|
||||
MsgConfigureDenoiser *msg = MsgConfigureDenoiser::create(m_settings, QList<QString>(), true);
|
||||
m_inputMessageQueue.push(msg);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_settings.resetToDefaults();
|
||||
MsgConfigureDenoiser *msg = MsgConfigureDenoiser::create(m_settings, QList<QString>(), true);
|
||||
m_inputMessageQueue.push(msg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Denoiser::applySettings(const DenoiserSettings& settings, const QList<QString>& settingsKeys, bool force)
|
||||
{
|
||||
qDebug() << "Denoiser::applySettings:" << settings.getDebugString(settingsKeys, force) << " force: " << force;
|
||||
|
||||
if (m_running)
|
||||
{
|
||||
DenoiserWorker::MsgConfigureDenoiserWorker *msg = DenoiserWorker::MsgConfigureDenoiserWorker::create(
|
||||
settings, settingsKeys, force
|
||||
);
|
||||
m_worker->getInputMessageQueue()->push(msg);
|
||||
}
|
||||
|
||||
if (settings.m_useReverseAPI)
|
||||
{
|
||||
bool fullUpdate = (settingsKeys.contains("useReverseAPI") && settings.m_useReverseAPI) ||
|
||||
settingsKeys.contains("reverseAPIAddress") ||
|
||||
settingsKeys.contains("reverseAPIPort") ||
|
||||
settingsKeys.contains("reverseAPIFeatureSetIndex") ||
|
||||
settingsKeys.contains("m_reverseAPIFeatureIndex");
|
||||
webapiReverseSendSettings(settingsKeys, settings, fullUpdate || force);
|
||||
}
|
||||
|
||||
if (force) {
|
||||
m_settings = settings;
|
||||
} else {
|
||||
m_settings.applySettings(settingsKeys, settings);
|
||||
}
|
||||
}
|
||||
|
||||
void Denoiser::channelsOrFeaturesChanged(const QStringList& renameFrom, const QStringList& renameTo)
|
||||
{
|
||||
m_availableChannels = m_availableChannelOrFeatureHandler.getAvailableChannelOrFeatureList();
|
||||
notifyUpdate(renameFrom, renameTo);
|
||||
}
|
||||
|
||||
void Denoiser::notifyUpdate(const QStringList& renameFrom, const QStringList& renameTo)
|
||||
{
|
||||
if (getMessageQueueToGUI())
|
||||
{
|
||||
MsgReportChannels *msg = MsgReportChannels::create(renameFrom, renameTo);
|
||||
msg->getAvailableChannels() = m_availableChannels;
|
||||
getMessageQueueToGUI()->push(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void Denoiser::getAvailableChannelsReport()
|
||||
{
|
||||
notifyUpdate(QStringList{}, QStringList{});
|
||||
}
|
||||
|
||||
|
||||
void Denoiser::setChannel(ChannelAPI *selectedChannel)
|
||||
{
|
||||
if ((selectedChannel == m_selectedChannel) || (m_availableChannels.indexOfObject(selectedChannel) == -1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MainCore *mainCore = MainCore::instance();
|
||||
|
||||
if (m_selectedChannel)
|
||||
{
|
||||
ObjectPipe *pipe = mainCore->getDataPipes().unregisterProducerToConsumer(m_selectedChannel, this, "demod");
|
||||
DataFifo *fifo = qobject_cast<DataFifo*>(pipe->m_element);
|
||||
|
||||
if ((fifo) && m_running)
|
||||
{
|
||||
DenoiserWorker::MsgConnectFifo *msg = DenoiserWorker::MsgConnectFifo::create(fifo, false);
|
||||
m_worker->getInputMessageQueue()->push(msg);
|
||||
}
|
||||
|
||||
ObjectPipe *messagePipe = mainCore->getMessagePipes().unregisterProducerToConsumer(m_selectedChannel, this, "reportdemod");
|
||||
|
||||
if (messagePipe)
|
||||
{
|
||||
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(messagePipe->m_element);
|
||||
|
||||
if (messageQueue) {
|
||||
disconnect(messageQueue, &MessageQueue::messageEnqueued, this, nullptr); // Have to use nullptr, as slot is a lambda.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_dataPipe = mainCore->getDataPipes().registerProducerToConsumer(selectedChannel, this, "demod");
|
||||
connect(m_dataPipe, SIGNAL(toBeDeleted(int, QObject*)), this, SLOT(handleDataPipeToBeDeleted(int, QObject*)));
|
||||
DataFifo *fifo = qobject_cast<DataFifo*>(m_dataPipe->m_element);
|
||||
|
||||
if (fifo)
|
||||
{
|
||||
fifo->setSize(96000);
|
||||
|
||||
if (m_running)
|
||||
{
|
||||
DenoiserWorker::MsgConnectFifo *msg = DenoiserWorker::MsgConnectFifo::create(fifo, true);
|
||||
m_worker->getInputMessageQueue()->push(msg);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectPipe *messagePipe = mainCore->getMessagePipes().registerProducerToConsumer(selectedChannel, this, "reportdemod");
|
||||
|
||||
if (messagePipe)
|
||||
{
|
||||
MessageQueue *messageQueue = qobject_cast<MessageQueue*>(messagePipe->m_element);
|
||||
|
||||
if (messageQueue)
|
||||
{
|
||||
QObject::connect(
|
||||
messageQueue,
|
||||
&MessageQueue::messageEnqueued,
|
||||
this,
|
||||
[=](){ this->handleChannelMessageQueue(messageQueue); },
|
||||
Qt::QueuedConnection
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
m_selectedChannel = selectedChannel;
|
||||
}
|
||||
|
||||
int Denoiser::webapiRun(bool run,
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
getFeatureStateStr(*response.getState());
|
||||
MsgStartStop *msg = MsgStartStop::create(run);
|
||||
getInputMessageQueue()->push(msg);
|
||||
return 202;
|
||||
}
|
||||
|
||||
int Denoiser::webapiSettingsGet(
|
||||
SWGSDRangel::SWGFeatureSettings& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
response.setDenoiserSettings(new SWGSDRangel::SWGDenoiserSettings());
|
||||
response.getDenoiserSettings()->init();
|
||||
webapiFormatFeatureSettings(response, m_settings);
|
||||
return 200;
|
||||
}
|
||||
|
||||
int Denoiser::webapiSettingsPutPatch(
|
||||
bool force,
|
||||
const QStringList& featureSettingsKeys,
|
||||
SWGSDRangel::SWGFeatureSettings& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
DenoiserSettings settings = m_settings;
|
||||
webapiUpdateFeatureSettings(settings, featureSettingsKeys, response);
|
||||
|
||||
MsgConfigureDenoiser *msg = MsgConfigureDenoiser::create(settings, featureSettingsKeys, force);
|
||||
m_inputMessageQueue.push(msg);
|
||||
|
||||
qDebug("Denoiser::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
|
||||
if (m_guiMessageQueue) // forward to GUI if any
|
||||
{
|
||||
MsgConfigureDenoiser *msgToGUI = MsgConfigureDenoiser::create(settings, featureSettingsKeys, force);
|
||||
m_guiMessageQueue->push(msgToGUI);
|
||||
}
|
||||
|
||||
webapiFormatFeatureSettings(response, settings);
|
||||
|
||||
return 200;
|
||||
}
|
||||
|
||||
void Denoiser::webapiFormatFeatureSettings(
|
||||
SWGSDRangel::SWGFeatureSettings& response,
|
||||
const DenoiserSettings& settings)
|
||||
{
|
||||
response.getDenoiserSettings()->setDenoiserType(static_cast<int>(settings.m_denoiserType));
|
||||
response.getDenoiserSettings()->setEnableDenoiser(settings.m_enableDenoiser ? 1 : 0);
|
||||
response.getDenoiserSettings()->setAudioMute(settings.m_audioMute ? 1 : 0);
|
||||
response.getDenoiserSettings()->setVolumeTenths(settings.m_volumeTenths);
|
||||
if (response.getDenoiserSettings()->getAudioDeviceName()) {
|
||||
*response.getDenoiserSettings()->getAudioDeviceName() = settings.m_audioDeviceName;
|
||||
} else {
|
||||
response.getDenoiserSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||
}
|
||||
if (response.getDenoiserSettings()->getTitle()) {
|
||||
*response.getDenoiserSettings()->getTitle() = settings.m_title;
|
||||
} else {
|
||||
response.getDenoiserSettings()->setTitle(new QString(settings.m_title));
|
||||
}
|
||||
|
||||
response.getDenoiserSettings()->setRgbColor(settings.m_rgbColor);
|
||||
response.getDenoiserSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||
|
||||
if (response.getDenoiserSettings()->getReverseApiAddress()) {
|
||||
*response.getDenoiserSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
|
||||
} else {
|
||||
response.getDenoiserSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
|
||||
}
|
||||
|
||||
response.getDenoiserSettings()->setReverseApiPort(settings.m_reverseAPIPort);
|
||||
response.getDenoiserSettings()->setReverseApiFeatureSetIndex(settings.m_reverseAPIFeatureSetIndex);
|
||||
response.getDenoiserSettings()->setReverseApiFeatureIndex(settings.m_reverseAPIFeatureIndex);
|
||||
|
||||
if (response.getDenoiserSettings()->getFileRecordName()) {
|
||||
*response.getDenoiserSettings()->getFileRecordName() = settings.m_fileRecordName;
|
||||
} else {
|
||||
response.getDenoiserSettings()->setFileRecordName(new QString(settings.m_fileRecordName));
|
||||
}
|
||||
|
||||
response.getDenoiserSettings()->setRecordToFile(settings.m_recordToFile ? 1 : 0);
|
||||
|
||||
if (settings.m_rollupState)
|
||||
{
|
||||
if (response.getDenoiserSettings()->getRollupState())
|
||||
{
|
||||
settings.m_rollupState->formatTo(response.getDenoiserSettings()->getRollupState());
|
||||
}
|
||||
else
|
||||
{
|
||||
SWGSDRangel::SWGRollupState *swgRollupState = new SWGSDRangel::SWGRollupState();
|
||||
settings.m_rollupState->formatTo(swgRollupState);
|
||||
response.getDenoiserSettings()->setRollupState(swgRollupState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Denoiser::webapiUpdateFeatureSettings(
|
||||
DenoiserSettings& settings,
|
||||
const QStringList& featureSettingsKeys,
|
||||
SWGSDRangel::SWGFeatureSettings& response)
|
||||
{
|
||||
if (featureSettingsKeys.contains("DenoiserType")) {
|
||||
settings.m_denoiserType = static_cast<DenoiserSettings::DenoiserType>(response.getDenoiserSettings()->getDenoiserType());
|
||||
}
|
||||
if (featureSettingsKeys.contains("enableDenoiser")) {
|
||||
settings.m_enableDenoiser = response.getDenoiserSettings()->getEnableDenoiser() != 0;
|
||||
}
|
||||
if (featureSettingsKeys.contains("audioMute")) {
|
||||
settings.m_audioMute = response.getDenoiserSettings()->getAudioMute() != 0;
|
||||
}
|
||||
if (featureSettingsKeys.contains("volumeTenths")) {
|
||||
settings.m_volumeTenths = response.getDenoiserSettings()->getVolumeTenths();
|
||||
}
|
||||
if (featureSettingsKeys.contains("audioDeviceName")) {
|
||||
settings.m_audioDeviceName = *response.getDenoiserSettings()->getAudioDeviceName();
|
||||
}
|
||||
if (featureSettingsKeys.contains("title")) {
|
||||
settings.m_title = *response.getDenoiserSettings()->getTitle();
|
||||
}
|
||||
if (featureSettingsKeys.contains("rgbColor")) {
|
||||
settings.m_rgbColor = response.getDenoiserSettings()->getRgbColor();
|
||||
}
|
||||
if (featureSettingsKeys.contains("useReverseAPI")) {
|
||||
settings.m_useReverseAPI = response.getDenoiserSettings()->getUseReverseApi() != 0;
|
||||
}
|
||||
if (featureSettingsKeys.contains("reverseAPIAddress")) {
|
||||
settings.m_reverseAPIAddress = *response.getDenoiserSettings()->getReverseApiAddress();
|
||||
}
|
||||
if (featureSettingsKeys.contains("reverseAPIPort")) {
|
||||
settings.m_reverseAPIPort = response.getDenoiserSettings()->getReverseApiPort();
|
||||
}
|
||||
if (featureSettingsKeys.contains("reverseAPIFeatureSetIndex")) {
|
||||
settings.m_reverseAPIFeatureSetIndex = response.getDenoiserSettings()->getReverseApiFeatureSetIndex();
|
||||
}
|
||||
if (featureSettingsKeys.contains("reverseAPIFeatureIndex")) {
|
||||
settings.m_reverseAPIFeatureIndex = response.getDenoiserSettings()->getReverseApiFeatureIndex();
|
||||
}
|
||||
if (settings.m_rollupState && featureSettingsKeys.contains("rollupState")) {
|
||||
settings.m_rollupState->updateFrom(featureSettingsKeys, response.getDenoiserSettings()->getRollupState());
|
||||
}
|
||||
if (featureSettingsKeys.contains("fileRecordName")) {
|
||||
settings.m_fileRecordName = *response.getDenoiserSettings()->getFileRecordName();
|
||||
}
|
||||
if (featureSettingsKeys.contains("recordToFile")) {
|
||||
settings.m_recordToFile = response.getDenoiserSettings()->getRecordToFile() != 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Denoiser::webapiReverseSendSettings(const QList<QString>& featureSettingsKeys, const DenoiserSettings& settings, bool force)
|
||||
{
|
||||
SWGSDRangel::SWGFeatureSettings *swgFeatureSettings = new SWGSDRangel::SWGFeatureSettings();
|
||||
// swgFeatureSettings->setOriginatorFeatureIndex(getIndexInDeviceSet());
|
||||
// swgFeatureSettings->setOriginatorFeatureSetIndex(getDeviceSetIndex());
|
||||
swgFeatureSettings->setFeatureType(new QString("Denoiser"));
|
||||
swgFeatureSettings->setDenoiserSettings(new SWGSDRangel::SWGDenoiserSettings());
|
||||
SWGSDRangel::SWGDenoiserSettings *swgDenoiserSettings = swgFeatureSettings->getDenoiserSettings();
|
||||
|
||||
// transfer data that has been modified. When force is on transfer all data except reverse API data
|
||||
|
||||
if (featureSettingsKeys.contains("useReverseAPI") || force) {
|
||||
swgDenoiserSettings->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
|
||||
}
|
||||
if (featureSettingsKeys.contains("reverseAPIAddress") || force) {
|
||||
swgDenoiserSettings->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
|
||||
}
|
||||
if (featureSettingsKeys.contains("reverseAPIPort") || force) {
|
||||
swgDenoiserSettings->setReverseApiPort(settings.m_reverseAPIPort);
|
||||
}
|
||||
if (featureSettingsKeys.contains("reverseAPIFeatureSetIndex") || force) {
|
||||
swgDenoiserSettings->setReverseApiFeatureSetIndex(settings.m_reverseAPIFeatureSetIndex);
|
||||
}
|
||||
if (featureSettingsKeys.contains("reverseAPIFeatureIndex") || force) {
|
||||
swgDenoiserSettings->setReverseApiFeatureIndex(settings.m_reverseAPIFeatureIndex);
|
||||
}
|
||||
if (featureSettingsKeys.contains("DenoiserType") || force) {
|
||||
swgDenoiserSettings->setDenoiserType(static_cast<int>(settings.m_denoiserType));
|
||||
}
|
||||
if (featureSettingsKeys.contains("enableDenoiser") || force) {
|
||||
swgDenoiserSettings->setEnableDenoiser(settings.m_enableDenoiser ? 1 : 0);
|
||||
}
|
||||
if (featureSettingsKeys.contains("audioMute") || force) {
|
||||
swgDenoiserSettings->setAudioMute(settings.m_audioMute ? 1 : 0);
|
||||
}
|
||||
if (featureSettingsKeys.contains("volumeTenths") || force) {
|
||||
swgDenoiserSettings->setVolumeTenths(settings.m_volumeTenths);
|
||||
}
|
||||
if (featureSettingsKeys.contains("audioDeviceName") || force) {
|
||||
swgDenoiserSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
|
||||
}
|
||||
if (featureSettingsKeys.contains("title") || force) {
|
||||
swgDenoiserSettings->setTitle(new QString(settings.m_title));
|
||||
}
|
||||
if (featureSettingsKeys.contains("rgbColor") || force) {
|
||||
swgDenoiserSettings->setRgbColor(settings.m_rgbColor);
|
||||
}
|
||||
if (featureSettingsKeys.contains("fileRecordName")) {
|
||||
swgDenoiserSettings->setFileRecordName(new QString(settings.m_fileRecordName));
|
||||
}
|
||||
if (featureSettingsKeys.contains("recordToFile")) {
|
||||
swgDenoiserSettings->setRecordToFile(settings.m_recordToFile ? 1 : 0);
|
||||
}
|
||||
if (settings.m_rollupState && (featureSettingsKeys.contains("rollupState") || force)) {
|
||||
SWGSDRangel::SWGRollupState *swgRollupState = new SWGSDRangel::SWGRollupState();
|
||||
settings.m_rollupState->formatTo(swgRollupState);
|
||||
swgDenoiserSettings->setRollupState(swgRollupState);
|
||||
}
|
||||
|
||||
QString channelSettingsURL = QString("http://%1:%2/sdrangel/featureset/%3/feature/%4/settings")
|
||||
.arg(settings.m_reverseAPIAddress)
|
||||
.arg(settings.m_reverseAPIPort)
|
||||
.arg(settings.m_reverseAPIFeatureSetIndex)
|
||||
.arg(settings.m_reverseAPIFeatureIndex);
|
||||
m_networkRequest.setUrl(QUrl(channelSettingsURL));
|
||||
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
QBuffer *buffer = new QBuffer();
|
||||
buffer->open((QBuffer::ReadWrite));
|
||||
buffer->write(swgFeatureSettings->asJson().toUtf8());
|
||||
buffer->seek(0);
|
||||
|
||||
// Always use PATCH to avoid passing reverse API settings
|
||||
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
|
||||
buffer->setParent(reply);
|
||||
|
||||
delete swgFeatureSettings;
|
||||
}
|
||||
|
||||
void Denoiser::networkManagerFinished(QNetworkReply *reply)
|
||||
{
|
||||
QNetworkReply::NetworkError replyError = reply->error();
|
||||
|
||||
if (replyError)
|
||||
{
|
||||
qWarning() << "Denoiser::networkManagerFinished:"
|
||||
<< " error(" << (int) replyError
|
||||
<< "): " << replyError
|
||||
<< ": " << reply->errorString();
|
||||
}
|
||||
else
|
||||
{
|
||||
QString answer = reply->readAll();
|
||||
answer.chop(1); // remove last \n
|
||||
qDebug("Denoiser::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void Denoiser::handleChannelMessageQueue(MessageQueue* messageQueue)
|
||||
{
|
||||
Message* message;
|
||||
|
||||
while ((message = messageQueue->pop()) != nullptr)
|
||||
{
|
||||
if (handleMessage(*message)) {
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Denoiser::handleDataPipeToBeDeleted(int reason, QObject *object)
|
||||
{
|
||||
qDebug("Denoiser::handleDataPipeToBeDeleted: %d %p", reason, object);
|
||||
|
||||
if ((reason == 0) && (m_selectedChannel == object))
|
||||
{
|
||||
DataFifo *fifo = qobject_cast<DataFifo*>(m_dataPipe->m_element);
|
||||
|
||||
if ((fifo) && m_running)
|
||||
{
|
||||
DenoiserWorker::MsgConnectFifo *msg = DenoiserWorker::MsgConnectFifo::create(fifo, false);
|
||||
m_worker->getInputMessageQueue()->push(msg);
|
||||
}
|
||||
|
||||
m_selectedChannel = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int Denoiser::webapiActionsPost(
|
||||
const QStringList&,
|
||||
SWGSDRangel::SWGFeatureActions& query,
|
||||
QString& errorMessage) {
|
||||
|
||||
MainCore* m_core = MainCore::instance();
|
||||
auto action = query.getDenoiserActions();
|
||||
if (action == nullptr) {
|
||||
errorMessage = QString("missing DenoiserActions in request");
|
||||
return 404;
|
||||
}
|
||||
|
||||
auto deviceId = action->getDeviceId();
|
||||
auto chanId = action->getChannelId();
|
||||
|
||||
ChannelAPI * chan = m_core->getChannel(deviceId, chanId);
|
||||
if (chan == nullptr) {
|
||||
errorMessage = QString("device(%1) or channel (%2) on the device does not exist").arg(deviceId).arg(chanId);
|
||||
return 404;
|
||||
}
|
||||
|
||||
MsgSelectChannel *msg = MsgSelectChannel::create(chan);
|
||||
getInputMessageQueue()->push(msg);
|
||||
return 200;
|
||||
}
|
||||
228
plugins/feature/denoiser/denoiser.h
Normal file
228
plugins/feature/denoiser/denoiser.h
Normal file
@ -0,0 +1,228 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_FEATURE_DENOISER_H_
|
||||
#define INCLUDE_FEATURE_DENOISER_H_
|
||||
|
||||
#include <QHash>
|
||||
#include <QNetworkRequest>
|
||||
#include <QRecursiveMutex>
|
||||
|
||||
#include "feature/feature.h"
|
||||
#include "util/message.h"
|
||||
#include "availablechannelorfeaturehandler.h"
|
||||
|
||||
#include "denoisersettings.h"
|
||||
|
||||
class WebAPIAdapterInterface;
|
||||
class DenoiserWorker;
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
class QThread;
|
||||
class ObjectPipe;
|
||||
|
||||
namespace SWGSDRangel {
|
||||
class SWGDeviceState;
|
||||
}
|
||||
|
||||
class Denoiser : public Feature
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
class MsgConfigureDenoiser : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
const DenoiserSettings& getSettings() const { return m_settings; }
|
||||
const QList<QString>& getSettingsKeys() const { return m_settingsKeys; }
|
||||
bool getForce() const { return m_force; }
|
||||
|
||||
static MsgConfigureDenoiser* create(const DenoiserSettings& settings, const QList<QString>& settingsKeys, bool force) {
|
||||
return new MsgConfigureDenoiser(settings, settingsKeys, force);
|
||||
}
|
||||
|
||||
private:
|
||||
DenoiserSettings m_settings;
|
||||
QList<QString> m_settingsKeys;
|
||||
bool m_force;
|
||||
|
||||
MsgConfigureDenoiser(const DenoiserSettings& settings, const QList<QString>& settingsKeys, bool force) :
|
||||
Message(),
|
||||
m_settings(settings),
|
||||
m_settingsKeys(settingsKeys),
|
||||
m_force(force)
|
||||
{ }
|
||||
};
|
||||
|
||||
class MsgStartStop : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
bool getStartStop() const { return m_startStop; }
|
||||
|
||||
static MsgStartStop* create(bool startStop) {
|
||||
return new MsgStartStop(startStop);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_startStop;
|
||||
|
||||
MsgStartStop(bool startStop) :
|
||||
Message(),
|
||||
m_startStop(startStop)
|
||||
{ }
|
||||
};
|
||||
|
||||
class MsgReportChannels : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
AvailableChannelOrFeatureList& getAvailableChannels() { return m_availableChannels; }
|
||||
const QStringList& getRenameFrom() const { return m_renameFrom; }
|
||||
const QStringList& getRenameTo() const { return m_renameTo; }
|
||||
|
||||
static MsgReportChannels* create(const QStringList& renameFrom, const QStringList& renameTo) {
|
||||
return new MsgReportChannels(renameFrom, renameTo);
|
||||
}
|
||||
|
||||
private:
|
||||
AvailableChannelOrFeatureList m_availableChannels;
|
||||
QStringList m_renameFrom;
|
||||
QStringList m_renameTo;
|
||||
|
||||
MsgReportChannels(const QStringList& renameFrom, const QStringList& renameTo) :
|
||||
Message(),
|
||||
m_renameFrom(renameFrom),
|
||||
m_renameTo(renameTo)
|
||||
{}
|
||||
};
|
||||
|
||||
class MsgSelectChannel : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
ChannelAPI *getChannel() { return m_channel; }
|
||||
static MsgSelectChannel* create(ChannelAPI *channel) {
|
||||
return new MsgSelectChannel(channel);
|
||||
}
|
||||
|
||||
protected:
|
||||
ChannelAPI *m_channel;
|
||||
|
||||
MsgSelectChannel(ChannelAPI *channel) :
|
||||
Message(),
|
||||
m_channel(channel)
|
||||
{ }
|
||||
};
|
||||
|
||||
class MsgReportSampleRate : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
|
||||
public:
|
||||
int getSampleRate() const { return m_sampleRate; }
|
||||
|
||||
static MsgReportSampleRate* create(int sampleRate) {
|
||||
return new MsgReportSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
private:
|
||||
int m_sampleRate;
|
||||
|
||||
MsgReportSampleRate(int sampleRate) :
|
||||
Message(),
|
||||
m_sampleRate(sampleRate)
|
||||
{}
|
||||
};
|
||||
|
||||
Denoiser(WebAPIAdapterInterface *webAPIAdapterInterface);
|
||||
virtual ~Denoiser();
|
||||
virtual void destroy() { delete this; }
|
||||
double getMagSqAvg() const;
|
||||
virtual bool handleMessage(const Message& cmd);
|
||||
|
||||
virtual void getIdentifier(QString& id) const { id = objectName(); }
|
||||
virtual QString getIdentifier() const { return objectName(); }
|
||||
virtual void getTitle(QString& title) const { title = m_settings.m_title; }
|
||||
|
||||
virtual QByteArray serialize() const;
|
||||
virtual bool deserialize(const QByteArray& data);
|
||||
|
||||
virtual int webapiRun(bool run,
|
||||
SWGSDRangel::SWGDeviceState& response,
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiSettingsGet(
|
||||
SWGSDRangel::SWGFeatureSettings& response,
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiSettingsPutPatch(
|
||||
bool force,
|
||||
const QStringList& featureSettingsKeys,
|
||||
SWGSDRangel::SWGFeatureSettings& response,
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiActionsPost(
|
||||
const QStringList& featureActionsKeys,
|
||||
SWGSDRangel::SWGFeatureActions& query,
|
||||
QString& errorMessage);
|
||||
|
||||
static void webapiFormatFeatureSettings(
|
||||
SWGSDRangel::SWGFeatureSettings& response,
|
||||
const DenoiserSettings& settings);
|
||||
|
||||
static void webapiUpdateFeatureSettings(
|
||||
DenoiserSettings& settings,
|
||||
const QStringList& featureSettingsKeys,
|
||||
SWGSDRangel::SWGFeatureSettings& response);
|
||||
|
||||
void getAvailableChannelsReport();
|
||||
void setLevelMeter(QObject *levelMeter) { m_levelMeter = levelMeter; }
|
||||
|
||||
static const char* const m_featureIdURI;
|
||||
static const char* const m_featureId;
|
||||
|
||||
private:
|
||||
QThread *m_thread;
|
||||
QRecursiveMutex m_mutex;
|
||||
bool m_running;
|
||||
DenoiserWorker *m_worker;
|
||||
DenoiserSettings m_settings;
|
||||
AvailableChannelOrFeatureList m_availableChannels;
|
||||
AvailableChannelOrFeatureHandler m_availableChannelOrFeatureHandler;
|
||||
ChannelAPI *m_selectedChannel;
|
||||
ObjectPipe *m_dataPipe;
|
||||
int m_sampleRate;
|
||||
QObject *m_levelMeter = nullptr;
|
||||
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
QNetworkRequest m_networkRequest;
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
void applySettings(const DenoiserSettings& settings, const QList<QString>& settingsKeys, bool force = false);
|
||||
void notifyUpdate(const QStringList& renameFrom, const QStringList& renameTo);
|
||||
void setChannel(ChannelAPI *selectedChannel);
|
||||
void webapiReverseSendSettings(const QList<QString>& featureSettingsKeys, const DenoiserSettings& settings, bool force);
|
||||
|
||||
private slots:
|
||||
void networkManagerFinished(QNetworkReply *reply);
|
||||
void handleChannelMessageQueue(MessageQueue *messageQueues);
|
||||
void channelsOrFeaturesChanged(const QStringList& renameFrom, const QStringList& renameTo);
|
||||
void handleDataPipeToBeDeleted(int reason, QObject *object);
|
||||
};
|
||||
|
||||
#endif // INCLUDE_FEATURE_DENOISER_H_
|
||||
475
plugins/feature/denoiser/denoisergui.cpp
Normal file
475
plugins/feature/denoiser/denoisergui.cpp
Normal file
@ -0,0 +1,475 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "feature/featureuiset.h"
|
||||
#include "gui/basicfeaturesettingsdialog.h"
|
||||
#include "gui/dialpopup.h"
|
||||
#include "gui/dialogpositioner.h"
|
||||
#include "gui/crightclickenabler.h"
|
||||
#include "gui/audioselectdialog.h"
|
||||
#include "dsp/dspengine.h"
|
||||
#include "util/db.h"
|
||||
#include "maincore.h"
|
||||
|
||||
#include "ui_denoisergui.h"
|
||||
#include "denoiser.h"
|
||||
#include "denoisergui.h"
|
||||
|
||||
DenoiserGUI* DenoiserGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature)
|
||||
{
|
||||
DenoiserGUI* gui = new DenoiserGUI(pluginAPI, featureUISet, feature);
|
||||
return gui;
|
||||
}
|
||||
|
||||
void DenoiserGUI::destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void DenoiserGUI::resetToDefaults()
|
||||
{
|
||||
m_settings.resetToDefaults();
|
||||
displaySettings();
|
||||
applySettings(true);
|
||||
}
|
||||
|
||||
QByteArray DenoiserGUI::serialize() const
|
||||
{
|
||||
return m_settings.serialize();
|
||||
}
|
||||
|
||||
bool DenoiserGUI::deserialize(const QByteArray& data)
|
||||
{
|
||||
if (m_settings.deserialize(data))
|
||||
{
|
||||
m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex);
|
||||
displaySettings();
|
||||
applySettings(true);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
resetToDefaults();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DenoiserGUI::handleMessage(const Message& message)
|
||||
{
|
||||
if (Denoiser::MsgConfigureDenoiser::match(message))
|
||||
{
|
||||
qDebug("DenoiserGUI::handleMessage: Denoiser::MsgConfigureDenoiser");
|
||||
const Denoiser::MsgConfigureDenoiser& cfg = (Denoiser::MsgConfigureDenoiser&) message;
|
||||
|
||||
if (cfg.getForce()) {
|
||||
m_settings = cfg.getSettings();
|
||||
} else {
|
||||
m_settings.applySettings(cfg.getSettingsKeys(), cfg.getSettings());
|
||||
}
|
||||
|
||||
blockApplySettings(true);
|
||||
displaySettings();
|
||||
blockApplySettings(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (Denoiser::MsgReportChannels::match(message))
|
||||
{
|
||||
qDebug("DenoiserGUI::handleMessage: Denoiser::MsgReportChannels");
|
||||
Denoiser::MsgReportChannels& report = (Denoiser::MsgReportChannels&) message;
|
||||
m_availableChannels = report.getAvailableChannels();
|
||||
updateChannelList();
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (Denoiser::MsgReportSampleRate::match(message))
|
||||
{
|
||||
Denoiser::MsgReportSampleRate& report = (Denoiser::MsgReportSampleRate&) message;
|
||||
int sampleRate = report.getSampleRate();
|
||||
qDebug("DenoiserGUI::handleMessage: Denoiser::MsgReportSampleRate: %d", sampleRate);
|
||||
displaySampleRate(sampleRate);
|
||||
m_sampleRate = sampleRate;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DenoiserGUI::handleInputMessages()
|
||||
{
|
||||
Message* message;
|
||||
|
||||
while ((message = getInputMessageQueue()->pop()))
|
||||
{
|
||||
if (handleMessage(*message)) {
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
||||
{
|
||||
(void) widget;
|
||||
(void) rollDown;
|
||||
|
||||
RollupContents *rollupContents = getRollupContents();
|
||||
|
||||
rollupContents->saveState(m_rollupState);
|
||||
applySettings();
|
||||
}
|
||||
|
||||
DenoiserGUI::DenoiserGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) :
|
||||
FeatureGUI(parent),
|
||||
ui(new Ui::DenoiserGUI),
|
||||
m_pluginAPI(pluginAPI),
|
||||
m_featureUISet(featureUISet),
|
||||
m_sampleRate(48000),
|
||||
m_doApplySettings(true),
|
||||
m_lastFeatureState(0),
|
||||
m_selectedChannel(nullptr)
|
||||
{
|
||||
m_feature = feature;
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
m_helpURL = "plugins/feature/denoiser/readme.md";
|
||||
RollupContents *rollupContents = getRollupContents();
|
||||
ui->setupUi(rollupContents);
|
||||
rollupContents->arrangeRollups();
|
||||
connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
|
||||
|
||||
m_denoiser = reinterpret_cast<Denoiser*>(feature);
|
||||
m_denoiser->setMessageQueueToGUI(&m_inputMessageQueue);
|
||||
|
||||
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
|
||||
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||
|
||||
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
||||
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect(const QPoint &)));
|
||||
|
||||
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
|
||||
m_statusTimer.start(1000);
|
||||
|
||||
displaySampleRate(m_sampleRate);
|
||||
|
||||
connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
|
||||
|
||||
m_settings.setRollupState(&m_rollupState);
|
||||
|
||||
displaySettings();
|
||||
applySettings(true);
|
||||
makeUIConnections();
|
||||
DialPopup::addPopupsToChildDials(this);
|
||||
m_resizer.enableChildMouseTracking();
|
||||
m_denoiser->getAvailableChannelsReport();
|
||||
m_denoiser->setLevelMeter(ui->volumeMeter);
|
||||
}
|
||||
|
||||
DenoiserGUI::~DenoiserGUI()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void DenoiserGUI::blockApplySettings(bool block)
|
||||
{
|
||||
m_doApplySettings = !block;
|
||||
}
|
||||
|
||||
void DenoiserGUI::setWorkspaceIndex(int index)
|
||||
{
|
||||
m_settings.m_workspaceIndex = index;
|
||||
m_feature->setWorkspaceIndex(index);
|
||||
}
|
||||
|
||||
void DenoiserGUI::displaySettings()
|
||||
{
|
||||
setTitleColor(m_settings.m_rgbColor);
|
||||
setWindowTitle(m_settings.m_title);
|
||||
setTitle(m_settings.m_title);
|
||||
blockApplySettings(true);
|
||||
ui->record->setChecked(m_settings.m_recordToFile);
|
||||
ui->fileNameText->setText(m_settings.m_fileRecordName);
|
||||
ui->showFileDialog->setEnabled(!m_settings.m_recordToFile);
|
||||
ui->denoiserType->setCurrentIndex(static_cast<int>(m_settings.m_denoiserType));
|
||||
ui->enable->setChecked(m_settings.m_enableDenoiser);
|
||||
ui->audioMute->setChecked(m_settings.m_audioMute);
|
||||
ui->volume->setValue(m_settings.m_volumeTenths);
|
||||
ui->volumeText->setText(QString::number(m_settings.m_volumeTenths / 10.0, 'f', 1));
|
||||
displayNRenabled();
|
||||
getRollupContents()->restoreState(m_rollupState);
|
||||
blockApplySettings(false);
|
||||
}
|
||||
|
||||
void DenoiserGUI::displaySampleRate(int sampleRate)
|
||||
{
|
||||
QString s = QString::number(sampleRate/1000.0, 'f', 1);
|
||||
ui->sinkSampleRateText->setText(tr("%1 kS/s").arg(s));
|
||||
}
|
||||
|
||||
void DenoiserGUI::updateChannelList()
|
||||
{
|
||||
ui->channels->blockSignals(true);
|
||||
ui->channels->clear();
|
||||
|
||||
AvailableChannelOrFeatureList::const_iterator it = m_availableChannels.begin();
|
||||
int selectedItem = -1;
|
||||
|
||||
for (int i = 0; it != m_availableChannels.end(); ++it, i++)
|
||||
{
|
||||
ui->channels->addItem(it->getLongId());
|
||||
|
||||
if (it->m_object == m_selectedChannel) {
|
||||
selectedItem = i;
|
||||
}
|
||||
}
|
||||
|
||||
ui->channels->blockSignals(false);
|
||||
|
||||
if (m_availableChannels.size() > 0)
|
||||
{
|
||||
if (selectedItem >= 0) {
|
||||
ui->channels->setCurrentIndex(selectedItem);
|
||||
} else {
|
||||
ui->channels->setCurrentIndex(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserGUI::onMenuDialogCalled(const QPoint &p)
|
||||
{
|
||||
if (m_contextMenuType == ContextMenuType::ContextMenuChannelSettings)
|
||||
{
|
||||
BasicFeatureSettingsDialog dialog(this);
|
||||
dialog.setTitle(m_settings.m_title);
|
||||
dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
|
||||
dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
|
||||
dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
|
||||
dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex);
|
||||
dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex);
|
||||
dialog.setDefaultTitle(m_displayedName);
|
||||
|
||||
dialog.move(p);
|
||||
new DialogPositioner(&dialog, false);
|
||||
dialog.exec();
|
||||
|
||||
m_settings.m_title = dialog.getTitle();
|
||||
m_settings.m_useReverseAPI = dialog.useReverseAPI();
|
||||
m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
|
||||
m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
|
||||
m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex();
|
||||
m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex();
|
||||
|
||||
setTitle(m_settings.m_title);
|
||||
setTitleColor(m_settings.m_rgbColor);
|
||||
|
||||
m_settingsKeys.append("title");
|
||||
m_settingsKeys.append("rgbColor");
|
||||
m_settingsKeys.append("useReverseAPI");
|
||||
m_settingsKeys.append("reverseAPIAddress");
|
||||
m_settingsKeys.append("reverseAPIPort");
|
||||
m_settingsKeys.append("reverseAPIFeatureSetIndex");
|
||||
m_settingsKeys.append("reverseAPIFeatureIndex");
|
||||
|
||||
applySettings();
|
||||
}
|
||||
|
||||
resetContextMenuType();
|
||||
}
|
||||
|
||||
void DenoiserGUI::on_startStop_toggled(bool checked)
|
||||
{
|
||||
if (m_doApplySettings)
|
||||
{
|
||||
Denoiser::MsgStartStop *message = Denoiser::MsgStartStop::create(checked);
|
||||
m_denoiser->getInputMessageQueue()->push(message);
|
||||
|
||||
if (checked && (ui->channels->count() > 0)) {
|
||||
on_channels_currentIndexChanged(ui->channels->currentIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserGUI::on_channels_currentIndexChanged(int index)
|
||||
{
|
||||
if ((index >= 0) && (index < m_availableChannels.size()))
|
||||
{
|
||||
m_selectedChannel = qobject_cast<ChannelAPI*>(m_availableChannels[index].m_object);
|
||||
Denoiser::MsgSelectChannel *msg = Denoiser::MsgSelectChannel::create(m_selectedChannel);
|
||||
m_denoiser->getInputMessageQueue()->push(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserGUI::on_channelApply_clicked()
|
||||
{
|
||||
if (ui->channels->count() > 0) {
|
||||
on_channels_currentIndexChanged(ui->channels->currentIndex());
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserGUI::on_record_toggled(bool checked)
|
||||
{
|
||||
ui->showFileDialog->setEnabled(!checked);
|
||||
m_settings.m_recordToFile = checked;
|
||||
m_settingsKeys.append("recordToFile");
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void DenoiserGUI::on_showFileDialog_clicked(bool checked)
|
||||
{
|
||||
(void) checked;
|
||||
QFileDialog fileDialog(
|
||||
this,
|
||||
tr("Save record file"),
|
||||
m_settings.m_fileRecordName,
|
||||
tr("WAV Files (*.wav)")
|
||||
);
|
||||
|
||||
fileDialog.setOptions(QFileDialog::DontUseNativeDialog);
|
||||
fileDialog.setFileMode(QFileDialog::AnyFile);
|
||||
QStringList fileNames;
|
||||
|
||||
if (fileDialog.exec())
|
||||
{
|
||||
fileNames = fileDialog.selectedFiles();
|
||||
|
||||
if (fileNames.size() > 0)
|
||||
{
|
||||
m_settings.m_fileRecordName = fileNames.at(0);
|
||||
ui->fileNameText->setText(m_settings.m_fileRecordName);
|
||||
m_settingsKeys.append("fileRecordName");
|
||||
applySettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserGUI::on_denoiserType_currentIndexChanged(int index)
|
||||
{
|
||||
m_settings.m_denoiserType = static_cast<DenoiserSettings::DenoiserType>(index);
|
||||
m_settingsKeys.append("denoiserType");
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void DenoiserGUI::on_enable_toggled(bool checked)
|
||||
{
|
||||
m_settings.m_enableDenoiser = checked;
|
||||
displayNRenabled();
|
||||
m_settingsKeys.append("enableDenoiser");
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void DenoiserGUI::on_audioMute_toggled(bool checked)
|
||||
{
|
||||
m_settings.m_audioMute = checked;
|
||||
m_settingsKeys.append("audioMute");
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void DenoiserGUI::on_volume_valueChanged(int value)
|
||||
{
|
||||
m_settings.m_volumeTenths = value;
|
||||
ui->volumeText->setText(QString::number(value / 10.0, 'f', 1));
|
||||
m_settingsKeys.append("volumeTenths");
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void DenoiserGUI::audioSelect(const QPoint& p)
|
||||
{
|
||||
qDebug("DenoiserGUI::audioSelect");
|
||||
AudioSelectDialog audioSelect(DSPEngine::instance()->getAudioDeviceManager(), m_settings.m_audioDeviceName);
|
||||
audioSelect.move(p);
|
||||
new DialogPositioner(&audioSelect, false);
|
||||
audioSelect.exec();
|
||||
|
||||
if (audioSelect.m_selected)
|
||||
{
|
||||
m_settings.m_audioDeviceName = audioSelect.m_audioDeviceName;
|
||||
m_settingsKeys.append("audioDeviceName");
|
||||
applySettings();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DenoiserGUI::tick()
|
||||
{
|
||||
m_channelPowerAvg(m_denoiser->getMagSqAvg());
|
||||
double powDb = CalcDb::dbPower((double) m_channelPowerAvg);
|
||||
ui->channelPower->setText(tr("%1 dB").arg(powDb, 0, 'f', 1));
|
||||
}
|
||||
|
||||
void DenoiserGUI::updateStatus()
|
||||
{
|
||||
int state = m_denoiser->getState();
|
||||
|
||||
if (m_lastFeatureState != state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case Feature::StNotStarted:
|
||||
ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
|
||||
break;
|
||||
case Feature::StIdle:
|
||||
ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
|
||||
break;
|
||||
case Feature::StRunning:
|
||||
ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
|
||||
break;
|
||||
case Feature::StError:
|
||||
ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
|
||||
QMessageBox::information(this, tr("Message"), m_denoiser->getErrorMessage());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_lastFeatureState = state;
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserGUI::displayNRenabled()
|
||||
{
|
||||
if (m_settings.m_enableDenoiser) {
|
||||
ui->enable->setStyleSheet("QToolButton { background-color : green; }");
|
||||
} else {
|
||||
ui->enable->setStyleSheet("QToolButton { background-color : blue; }");
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserGUI::applySettings(bool force)
|
||||
{
|
||||
if (m_doApplySettings)
|
||||
{
|
||||
Denoiser::MsgConfigureDenoiser* message = Denoiser::MsgConfigureDenoiser::create( m_settings, m_settingsKeys, force);
|
||||
m_denoiser->getInputMessageQueue()->push(message);
|
||||
}
|
||||
|
||||
m_settingsKeys.clear();
|
||||
}
|
||||
|
||||
void DenoiserGUI::makeUIConnections()
|
||||
{
|
||||
QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &DenoiserGUI::on_startStop_toggled);
|
||||
QObject::connect(ui->channels, qOverload<int>(&QComboBox::currentIndexChanged), this, &DenoiserGUI::on_channels_currentIndexChanged);
|
||||
QObject::connect(ui->channelApply, &QPushButton::clicked, this, &DenoiserGUI::on_channelApply_clicked);
|
||||
QObject::connect(ui->record, &ButtonSwitch::toggled, this, &DenoiserGUI::on_record_toggled);
|
||||
QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &DenoiserGUI::on_showFileDialog_clicked);
|
||||
QObject::connect(ui->denoiserType, qOverload<int>(&QComboBox::currentIndexChanged), this, &DenoiserGUI::on_denoiserType_currentIndexChanged);
|
||||
QObject::connect(ui->enable, &ButtonSwitch::toggled, this, &DenoiserGUI::on_enable_toggled);
|
||||
QObject::connect(ui->audioMute, &ButtonSwitch::toggled, this, &DenoiserGUI::on_audioMute_toggled);
|
||||
QObject::connect(ui->volume, &QDial::valueChanged, this, &DenoiserGUI::on_volume_valueChanged);
|
||||
}
|
||||
105
plugins/feature/denoiser/denoisergui.h
Normal file
105
plugins/feature/denoiser/denoisergui.h
Normal file
@ -0,0 +1,105 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_FEATURE_DENOISERGUI_H_
|
||||
#define INCLUDE_FEATURE_DENOISERGUI_H_
|
||||
|
||||
#include <QTimer>
|
||||
#include <QList>
|
||||
|
||||
#include "feature/featuregui.h"
|
||||
#include "util/movingaverage.h"
|
||||
#include "util/messagequeue.h"
|
||||
#include "availablechannelorfeaturehandler.h"
|
||||
#include "settings/rollupstate.h"
|
||||
|
||||
#include "denoisersettings.h"
|
||||
|
||||
class PluginAPI;
|
||||
class FeatureUISet;
|
||||
class Denoiser;
|
||||
class Feature;
|
||||
|
||||
namespace Ui {
|
||||
class DenoiserGUI;
|
||||
}
|
||||
|
||||
class DenoiserGUI : public FeatureGUI {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static DenoiserGUI* create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature);
|
||||
virtual void destroy();
|
||||
|
||||
void resetToDefaults();
|
||||
QByteArray serialize() const;
|
||||
bool deserialize(const QByteArray& data);
|
||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||
virtual void setWorkspaceIndex(int index);
|
||||
virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }
|
||||
virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }
|
||||
virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }
|
||||
|
||||
private:
|
||||
Ui::DenoiserGUI* ui;
|
||||
PluginAPI* m_pluginAPI;
|
||||
FeatureUISet* m_featureUISet;
|
||||
DenoiserSettings m_settings;
|
||||
QList<QString> m_settingsKeys;
|
||||
RollupState m_rollupState;
|
||||
int m_sampleRate;
|
||||
bool m_doApplySettings;
|
||||
|
||||
Denoiser* m_denoiser;
|
||||
MessageQueue m_inputMessageQueue;
|
||||
QTimer m_statusTimer;
|
||||
int m_lastFeatureState;
|
||||
AvailableChannelOrFeatureList m_availableChannels;
|
||||
ChannelAPI *m_selectedChannel;
|
||||
MovingAverageUtil<double, double, 40> m_channelPowerAvg;
|
||||
|
||||
explicit DenoiserGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr);
|
||||
virtual ~DenoiserGUI();
|
||||
|
||||
void blockApplySettings(bool block);
|
||||
void applySettings(bool force = false);
|
||||
void displaySettings();
|
||||
void displaySampleRate(int sampleRate);
|
||||
void displayNRenabled();
|
||||
void updateChannelList();
|
||||
bool handleMessage(const Message& message);
|
||||
void makeUIConnections();
|
||||
|
||||
private slots:
|
||||
void onMenuDialogCalled(const QPoint &p);
|
||||
void onWidgetRolled(QWidget* widget, bool rollDown);
|
||||
void handleInputMessages();
|
||||
void on_startStop_toggled(bool checked);
|
||||
void on_channels_currentIndexChanged(int index);
|
||||
void on_channelApply_clicked();
|
||||
void on_record_toggled(bool checked);
|
||||
void on_showFileDialog_clicked(bool checked);
|
||||
void on_denoiserType_currentIndexChanged(int index);
|
||||
void on_enable_toggled(bool checked);
|
||||
void on_audioMute_toggled(bool checked);
|
||||
void on_volume_valueChanged(int value);
|
||||
void audioSelect(const QPoint& p);
|
||||
void updateStatus();
|
||||
void tick();
|
||||
};
|
||||
|
||||
|
||||
#endif // INCLUDE_FEATURE_DENOISERGUI_H_
|
||||
437
plugins/feature/denoiser/denoisergui.ui
Normal file
437
plugins/feature/denoiser/denoisergui.ui
Normal file
@ -0,0 +1,437 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DenoiserGUI</class>
|
||||
<widget class="RollupContents" name="DenoiserGUI">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>452</width>
|
||||
<height>200</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>452</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Liberation Sans</family>
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Denoiser</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="settingsContainer" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>2</y>
|
||||
<width>450</width>
|
||||
<height>151</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>450</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="HeaderLayout">
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="startStop">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>start/stop acquisition</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/play.png</normaloff>
|
||||
<normalon>:/stop.png</normalon>:/play.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="channelsLabel">
|
||||
<property name="text">
|
||||
<string>Chan</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="channels">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Channel index</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="channelApply">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>(Re) associate with channel</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/link.png</normaloff>:/link.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="sinkSampleRateText">
|
||||
<property name="toolTip">
|
||||
<string>Analyzer (sink) sample rate</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>00000.0 kS/s</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="channelPower">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>52</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Channel power</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>-100.0 dB</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="denoiserLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="denoiserType">
|
||||
<property name="toolTip">
|
||||
<string>Noise reduction scheme</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>RNnoise</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="enable">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Denoiser on/off</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/play.png</normaloff>
|
||||
<normalon>:/stop.png</normalon>:/play.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="audioMute">
|
||||
<property name="toolTip">
|
||||
<string>Left: Mute/Unmute audio Right: view/select audio device</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/sound_on.png</normaloff>
|
||||
<normalon>:/sound_off.png</normalon>:/sound_on.png</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="volumeLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="volLabel">
|
||||
<property name="text">
|
||||
<string>Vol</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDial" name="volume">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Audio input gain</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="volumeText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Audio input gain value</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1.0</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LevelMeterVU" name="volumeMeter" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Liberation Mono</family>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Input level (% full range) top trace: average, bottom trace: instantaneous peak, tip: peak hold</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="fileNameLayout">
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="record">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Start/stop recording</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/record_off.png</normaloff>:/record_off.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="showFileDialog">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Open file</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../sdrgui/resources/res.qrc">
|
||||
<normaloff>:/preset-load.png</normaloff>:/preset-load.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="fileNameText">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Current recording file</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ButtonSwitch</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>gui/buttonswitch.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>RollupContents</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>gui/rollupcontents.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LevelMeterVU</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>gui/levelmeter.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../../sdrgui/resources/res.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
78
plugins/feature/denoiser/denoiserplugin.cpp
Normal file
78
plugins/feature/denoiser/denoiserplugin.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <QtPlugin>
|
||||
#include "plugin/pluginapi.h"
|
||||
|
||||
#ifndef SERVER_MODE
|
||||
#include "denoisergui.h"
|
||||
#endif
|
||||
#include "denoiser.h"
|
||||
#include "denoiserplugin.h"
|
||||
#include "denoiserwebapiadapter.h"
|
||||
const PluginDescriptor DenoiserPlugin::m_pluginDescriptor = {
|
||||
Denoiser::m_featureId,
|
||||
QStringLiteral("Denoiser"),
|
||||
QStringLiteral("7.22.11"),
|
||||
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
|
||||
QStringLiteral("https://github.com/f4exb/sdrangel"),
|
||||
true,
|
||||
QStringLiteral("https://github.com/f4exb/sdrangel")
|
||||
};
|
||||
|
||||
DenoiserPlugin::DenoiserPlugin(QObject* parent) :
|
||||
QObject(parent),
|
||||
m_pluginAPI(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
const PluginDescriptor& DenoiserPlugin::getPluginDescriptor() const
|
||||
{
|
||||
return m_pluginDescriptor;
|
||||
}
|
||||
|
||||
void DenoiserPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||
{
|
||||
m_pluginAPI = pluginAPI;
|
||||
|
||||
// register RigCtl Server feature
|
||||
m_pluginAPI->registerFeature(Denoiser::m_featureIdURI, Denoiser::m_featureId, this);
|
||||
}
|
||||
|
||||
#ifdef SERVER_MODE
|
||||
FeatureGUI* DenoiserPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const
|
||||
{
|
||||
(void) featureUISet;
|
||||
(void) feature;
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
FeatureGUI* DenoiserPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const
|
||||
{
|
||||
return DenoiserGUI::create(m_pluginAPI, featureUISet, feature);
|
||||
}
|
||||
#endif
|
||||
|
||||
Feature* DenoiserPlugin::createFeature(WebAPIAdapterInterface* webAPIAdapterInterface) const
|
||||
{
|
||||
return new Denoiser(webAPIAdapterInterface);
|
||||
}
|
||||
|
||||
FeatureWebAPIAdapter* DenoiserPlugin::createFeatureWebAPIAdapter() const
|
||||
{
|
||||
return new DenoiserWebAPIAdapter();
|
||||
}
|
||||
48
plugins/feature/denoiser/denoiserplugin.h
Normal file
48
plugins/feature/denoiser/denoiserplugin.h
Normal file
@ -0,0 +1,48 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_FEATURE_DENOISERPLUGIN_H
|
||||
#define INCLUDE_FEATURE_DENOISERPLUGIN_H
|
||||
|
||||
#include <QObject>
|
||||
#include "plugin/plugininterface.h"
|
||||
|
||||
class FeatureGUI;
|
||||
class WebAPIAdapterInterface;
|
||||
|
||||
class DenoiserPlugin : public QObject, PluginInterface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(PluginInterface)
|
||||
Q_PLUGIN_METADATA(IID "sdrangel.feature.denoiser")
|
||||
|
||||
public:
|
||||
explicit DenoiserPlugin(QObject* parent = nullptr);
|
||||
|
||||
const PluginDescriptor& getPluginDescriptor() const;
|
||||
void initPlugin(PluginAPI* pluginAPI);
|
||||
|
||||
virtual FeatureGUI* createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const;
|
||||
virtual Feature* createFeature(WebAPIAdapterInterface *webAPIAdapterInterface) const;
|
||||
virtual FeatureWebAPIAdapter* createFeatureWebAPIAdapter() const;
|
||||
|
||||
private:
|
||||
static const PluginDescriptor m_pluginDescriptor;
|
||||
|
||||
PluginAPI* m_pluginAPI;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_FEATURE_DENOISERPLUGIN_H
|
||||
250
plugins/feature/denoiser/denoisersettings.cpp
Normal file
250
plugins/feature/denoiser/denoisersettings.cpp
Normal file
@ -0,0 +1,250 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "util/simpleserializer.h"
|
||||
#include "settings/serializable.h"
|
||||
#include "audio/audiodevicemanager.h"
|
||||
|
||||
#include "denoisersettings.h"
|
||||
|
||||
const QStringList DenoiserSettings::m_channelURIs = {
|
||||
QStringLiteral("sdrangel.channel.amdemod"),
|
||||
QStringLiteral("sdrangel.channel.bfm"),
|
||||
QStringLiteral("sdrangel.channel.dabdemod"),
|
||||
QStringLiteral("sdrangel.channel.dsddemod"),
|
||||
QStringLiteral("sdrangel.channel.m17demod"),
|
||||
QStringLiteral("sdrangel.channel.nfmdemod"),
|
||||
QStringLiteral("sdrangel.channel.ssbdemod"),
|
||||
QStringLiteral("sdrangel.channel.wfmdemod"),
|
||||
QStringLiteral("sdrangel.channel.wdsprx"),
|
||||
};
|
||||
|
||||
DenoiserSettings::DenoiserSettings() :
|
||||
m_rollupState(nullptr)
|
||||
{
|
||||
resetToDefaults();
|
||||
}
|
||||
|
||||
void DenoiserSettings::resetToDefaults()
|
||||
{
|
||||
m_denoiserType = DenoiserType::DenoiserType_RNnoise;
|
||||
m_title = "Denoiser";
|
||||
m_enableDenoiser = true;
|
||||
m_audioMute = false;
|
||||
m_volumeTenths = 10;
|
||||
m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName;
|
||||
m_rgbColor = 0xffd700; // gold
|
||||
m_useReverseAPI = false;
|
||||
m_reverseAPIAddress = "localhost";
|
||||
m_reverseAPIPort = 8888;
|
||||
m_reverseAPIFeatureSetIndex = 0;
|
||||
m_reverseAPIFeatureIndex = 0;
|
||||
m_fileRecordName = "denoiser_record.wav";
|
||||
m_recordToFile = false;
|
||||
m_workspaceIndex = -1;
|
||||
m_geometryBytes.clear();
|
||||
}
|
||||
|
||||
QByteArray DenoiserSettings::serialize() const
|
||||
{
|
||||
SimpleSerializer s(1);
|
||||
|
||||
s.writeS32(1, static_cast<qint32>(m_denoiserType));
|
||||
s.writeString(2, m_title);
|
||||
s.writeU32(3, m_rgbColor);
|
||||
s.writeBool(4, m_useReverseAPI);
|
||||
s.writeString(5, m_reverseAPIAddress);
|
||||
s.writeU32(6, m_reverseAPIPort);
|
||||
s.writeU32(7, m_reverseAPIFeatureSetIndex);
|
||||
s.writeU32(8, m_reverseAPIFeatureIndex);
|
||||
s.writeString(9, m_fileRecordName);
|
||||
s.writeBool(10, m_recordToFile);
|
||||
s.writeS32(11, m_workspaceIndex);
|
||||
s.writeBlob(12, m_geometryBytes);
|
||||
|
||||
if (m_rollupState) {
|
||||
s.writeBlob(13, m_rollupState->serialize());
|
||||
}
|
||||
|
||||
s.writeBool(14, m_audioMute);
|
||||
s.writeString(15, m_audioDeviceName);
|
||||
s.writeBool(16, m_enableDenoiser);
|
||||
s.writeS32(17, m_volumeTenths);
|
||||
|
||||
return s.final();
|
||||
}
|
||||
|
||||
bool DenoiserSettings::deserialize(const QByteArray& data)
|
||||
{
|
||||
SimpleDeserializer d(data);
|
||||
|
||||
if (!d.isValid())
|
||||
{
|
||||
resetToDefaults();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (d.getVersion() == 1)
|
||||
{
|
||||
qint32 itmp;
|
||||
QByteArray bytetmp;
|
||||
uint32_t utmp;
|
||||
|
||||
d.readS32(1, &itmp, 1);
|
||||
m_denoiserType = static_cast<DenoiserType>(itmp);
|
||||
d.readString(2, &m_title, "Denoiser");
|
||||
d.readU32(3, &m_rgbColor, 0xffd700); // gold
|
||||
d.readBool(4, &m_useReverseAPI, false);
|
||||
d.readString(5, &m_reverseAPIAddress, "localhost");
|
||||
d.readU32(6, &utmp, 8888);
|
||||
|
||||
if ((utmp > 1023) && (utmp < 65535)) {
|
||||
m_reverseAPIPort = utmp;
|
||||
} else {
|
||||
m_reverseAPIPort = 8888;
|
||||
}
|
||||
|
||||
d.readU32(7, &utmp, 0);
|
||||
m_reverseAPIFeatureSetIndex = utmp > 99 ? 99 : utmp;
|
||||
d.readU32(8, &utmp, 0);
|
||||
m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp;
|
||||
d.readString(9, &m_fileRecordName, "denoiser_record.wav");
|
||||
d.readBool(10, &m_recordToFile, false);
|
||||
d.readS32(11, &m_workspaceIndex, -1);
|
||||
d.readBlob(12, &m_geometryBytes);
|
||||
|
||||
if (m_rollupState)
|
||||
{
|
||||
d.readBlob(13, &bytetmp);
|
||||
m_rollupState->deserialize(bytetmp);
|
||||
}
|
||||
|
||||
d.readBool(14, &m_audioMute, false);
|
||||
d.readString(15, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName);
|
||||
d.readBool(16, &m_enableDenoiser, true);
|
||||
d.readS32(17, &m_volumeTenths, 10);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
resetToDefaults();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserSettings::applySettings(const QStringList& settingsKeys, const DenoiserSettings& settings)
|
||||
{
|
||||
if (settingsKeys.contains("denoiserType")) {
|
||||
m_denoiserType = settings.m_denoiserType;
|
||||
}
|
||||
if (settingsKeys.contains("enableDenoiser")) {
|
||||
m_enableDenoiser = settings.m_enableDenoiser;
|
||||
}
|
||||
if (settingsKeys.contains("audioMute")) {
|
||||
m_audioMute = settings.m_audioMute;
|
||||
}
|
||||
if (settingsKeys.contains("volumeTenths")) {
|
||||
m_volumeTenths = settings.m_volumeTenths;
|
||||
}
|
||||
if (settingsKeys.contains("audioDeviceName")) {
|
||||
m_audioDeviceName = settings.m_audioDeviceName;
|
||||
}
|
||||
if (settingsKeys.contains("title")) {
|
||||
m_title = settings.m_title;
|
||||
}
|
||||
if (settingsKeys.contains("rgbColor")) {
|
||||
m_rgbColor = settings.m_rgbColor;
|
||||
}
|
||||
if (settingsKeys.contains("useReverseAPI")) {
|
||||
m_useReverseAPI = settings.m_useReverseAPI;
|
||||
}
|
||||
if (settingsKeys.contains("reverseAPIAddress")) {
|
||||
m_reverseAPIAddress = settings.m_reverseAPIAddress;
|
||||
}
|
||||
if (settingsKeys.contains("reverseAPIPort")) {
|
||||
m_reverseAPIPort = settings.m_reverseAPIPort;
|
||||
}
|
||||
if (settingsKeys.contains("reverseAPIFeatureSetIndex")) {
|
||||
m_reverseAPIFeatureSetIndex = settings.m_reverseAPIFeatureSetIndex;
|
||||
}
|
||||
if (settingsKeys.contains("reverseAPIFeatureIndex")) {
|
||||
m_reverseAPIFeatureIndex = settings.m_reverseAPIFeatureIndex;
|
||||
}
|
||||
if (settingsKeys.contains("workspaceIndex")) {
|
||||
m_workspaceIndex = settings.m_workspaceIndex;
|
||||
}
|
||||
if (settingsKeys.contains("fileRecordName")) {
|
||||
m_fileRecordName = settings.m_fileRecordName;
|
||||
}
|
||||
if (settingsKeys.contains("recordToFile")) {
|
||||
m_recordToFile = settings.m_recordToFile;
|
||||
}
|
||||
}
|
||||
|
||||
QString DenoiserSettings::getDebugString(const QStringList& settingsKeys, bool force) const
|
||||
{
|
||||
QString debugString;
|
||||
|
||||
if (settingsKeys.contains("denoiserType") || force) {
|
||||
debugString += QString("DenoiserType: %1 ").arg(static_cast<qint32>(m_denoiserType));
|
||||
}
|
||||
if (settingsKeys.contains("enableDenoiser") || force) {
|
||||
debugString += QString("Denoiser Enable: %1 ").arg(m_enableDenoiser ? "true" : "false");
|
||||
}
|
||||
if (settingsKeys.contains("audioMute") || force) {
|
||||
debugString += QString("Audio Mute: %1 ").arg(m_audioMute ? "true" : "false");
|
||||
}
|
||||
if (settingsKeys.contains("volumeTenths") || force) {
|
||||
debugString += QString("Volume : %1 ").arg(m_volumeTenths/10.0);
|
||||
}
|
||||
if (settingsKeys.contains("audioDeviceName") || force) {
|
||||
debugString += QString("Audio Device Name: %1 ").arg(m_audioDeviceName);
|
||||
}
|
||||
if (settingsKeys.contains("title") || force) {
|
||||
debugString += QString("Title: %1 ").arg(m_title);
|
||||
}
|
||||
if (settingsKeys.contains("rgbColor") || force) {
|
||||
debugString += QString("RGB Color: 0x%1 ").arg(QString::number(m_rgbColor, 16).rightJustified(6, '0'));
|
||||
}
|
||||
if (settingsKeys.contains("useReverseAPI") || force) {
|
||||
debugString += QString("Use Reverse API: %1 ").arg(m_useReverseAPI ? "true" : "false");
|
||||
}
|
||||
if (settingsKeys.contains("reverseAPIAddress") || force) {
|
||||
debugString += QString("Reverse API Address: %1 ").arg(m_reverseAPIAddress);
|
||||
}
|
||||
if (settingsKeys.contains("reverseAPIPort") || force) {
|
||||
debugString += QString("Reverse API Port: %1 ").arg(m_reverseAPIPort);
|
||||
}
|
||||
if (settingsKeys.contains("reverseAPIFeatureSetIndex") || force) {
|
||||
debugString += QString("Reverse API Feature Set Index: %1 ").arg(m_reverseAPIFeatureSetIndex);
|
||||
}
|
||||
if (settingsKeys.contains("reverseAPIFeatureIndex") || force) {
|
||||
debugString += QString("Reverse API Feature Index: %1 ").arg(m_reverseAPIFeatureIndex);
|
||||
}
|
||||
if (settingsKeys.contains("workspaceIndex") || force) {
|
||||
debugString += QString("Workspace Index: %1 ").arg(m_workspaceIndex);
|
||||
}
|
||||
if (settingsKeys.contains("fileRecordName") || force) {
|
||||
debugString += QString("File Record Name: %1 ").arg(m_fileRecordName);
|
||||
}
|
||||
if (settingsKeys.contains("recordToFile") || force) {
|
||||
debugString += QString("Record To File: %1 ").arg(m_recordToFile ? "true" : "false");
|
||||
}
|
||||
|
||||
return debugString;
|
||||
}
|
||||
65
plugins/feature/denoiser/denoisersettings.h
Normal file
65
plugins/feature/denoiser/denoisersettings.h
Normal file
@ -0,0 +1,65 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef INCLUDE_FEATURE_DENOISER_DENOISERSETTINGS_H_
|
||||
#define INCLUDE_FEATURE_DENOISER_DENOISERSETTINGS_H_
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class Serializable;
|
||||
|
||||
struct DenoiserSettings
|
||||
{
|
||||
enum class DenoiserType
|
||||
{
|
||||
DenoiserType_None = 0,
|
||||
DenoiserType_RNnoise = 1,
|
||||
};
|
||||
|
||||
DenoiserType m_denoiserType;
|
||||
bool m_enableDenoiser;
|
||||
bool m_audioMute;
|
||||
int m_volumeTenths;
|
||||
QString m_audioDeviceName;
|
||||
QString m_title;
|
||||
quint32 m_rgbColor;
|
||||
bool m_useReverseAPI;
|
||||
QString m_reverseAPIAddress;
|
||||
uint16_t m_reverseAPIPort;
|
||||
uint16_t m_reverseAPIFeatureSetIndex;
|
||||
uint16_t m_reverseAPIFeatureIndex;
|
||||
QString m_fileRecordName;
|
||||
bool m_recordToFile;
|
||||
Serializable *m_rollupState;
|
||||
int m_workspaceIndex;
|
||||
QByteArray m_geometryBytes;
|
||||
|
||||
DenoiserSettings();
|
||||
~DenoiserSettings() = default;
|
||||
void resetToDefaults();
|
||||
QByteArray serialize() const;
|
||||
bool deserialize(const QByteArray& data);
|
||||
void setRollupState(Serializable *rollupState) { m_rollupState = rollupState; }
|
||||
void applySettings(const QStringList& settingsKeys, const DenoiserSettings& settings);
|
||||
QString getDebugString(const QStringList& settingsKeys, bool force=false) const;
|
||||
|
||||
static const QStringList m_channelURIs;
|
||||
};
|
||||
|
||||
|
||||
#endif // INCLUDE_FEATURE_DENOISER_DENOISERSETTINGS_H_
|
||||
51
plugins/feature/denoiser/denoiserwebapiadapter.cpp
Normal file
51
plugins/feature/denoiser/denoiserwebapiadapter.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SWGFeatureSettings.h"
|
||||
#include "denoiser.h"
|
||||
#include "denoiserwebapiadapter.h"
|
||||
|
||||
DenoiserWebAPIAdapter::DenoiserWebAPIAdapter()
|
||||
{}
|
||||
|
||||
DenoiserWebAPIAdapter::~DenoiserWebAPIAdapter()
|
||||
{}
|
||||
|
||||
int DenoiserWebAPIAdapter::webapiSettingsGet(
|
||||
SWGSDRangel::SWGFeatureSettings& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) errorMessage;
|
||||
response.setDenoiserSettings(new SWGSDRangel::SWGDenoiserSettings());
|
||||
response.getDenoiserSettings()->init();
|
||||
Denoiser::webapiFormatFeatureSettings(response, m_settings);
|
||||
|
||||
return 200;
|
||||
}
|
||||
|
||||
int DenoiserWebAPIAdapter::webapiSettingsPutPatch(
|
||||
bool force,
|
||||
const QStringList& featureSettingsKeys,
|
||||
SWGSDRangel::SWGFeatureSettings& response,
|
||||
QString& errorMessage)
|
||||
{
|
||||
(void) force; // no action
|
||||
(void) errorMessage;
|
||||
Denoiser::webapiUpdateFeatureSettings(m_settings, featureSettingsKeys, response);
|
||||
|
||||
return 200;
|
||||
}
|
||||
49
plugins/feature/denoiser/denoiserwebapiadapter.h
Normal file
49
plugins/feature/denoiser/denoiserwebapiadapter.h
Normal file
@ -0,0 +1,49 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_DENOISER_WEBAPIADAPTER_H
|
||||
#define INCLUDE_DENOISER_WEBAPIADAPTER_H
|
||||
|
||||
#include "feature/featurewebapiadapter.h"
|
||||
#include "denoisersettings.h"
|
||||
|
||||
/**
|
||||
* Standalone API adapter only for the settings
|
||||
*/
|
||||
class DenoiserWebAPIAdapter : public FeatureWebAPIAdapter {
|
||||
public:
|
||||
DenoiserWebAPIAdapter();
|
||||
virtual ~DenoiserWebAPIAdapter();
|
||||
|
||||
virtual QByteArray serialize() const { return m_settings.serialize(); }
|
||||
virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
|
||||
|
||||
virtual int webapiSettingsGet(
|
||||
SWGSDRangel::SWGFeatureSettings& response,
|
||||
QString& errorMessage);
|
||||
|
||||
virtual int webapiSettingsPutPatch(
|
||||
bool force,
|
||||
const QStringList& featureSettingsKeys,
|
||||
SWGSDRangel::SWGFeatureSettings& response,
|
||||
QString& errorMessage);
|
||||
|
||||
private:
|
||||
DenoiserSettings m_settings;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_DENOISER_WEBAPIADAPTER_H
|
||||
529
plugins/feature/denoiser/denoiserworker.cpp
Normal file
529
plugins/feature/denoiser/denoiserworker.cpp
Normal file
@ -0,0 +1,529 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "dsp/wavfilerecord.h"
|
||||
#include "audio/audiodevicemanager.h"
|
||||
#include "dsp/dspengine.h"
|
||||
#include "rnnoise.h"
|
||||
|
||||
#include "denoiserworker.h"
|
||||
|
||||
const int DenoiserWorker::m_levelNbSamples = 480; // 10 ms at 48 kHz
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(DenoiserWorker::MsgConfigureDenoiserWorker, Message)
|
||||
MESSAGE_CLASS_DEFINITION(DenoiserWorker::MsgConnectFifo, Message)
|
||||
|
||||
DenoiserWorker::DenoiserWorker(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_dataFifo(nullptr),
|
||||
m_sinkSampleRate(0),
|
||||
m_msgQueueToFeature(nullptr),
|
||||
m_magsq(0.0),
|
||||
m_sampleBufferSize(0),
|
||||
m_channelPowerAvg(),
|
||||
m_wavFileRecord(nullptr),
|
||||
m_recordSilenceNbSamples(0),
|
||||
m_recordSilenceCount(0),
|
||||
m_nbBytes(0),
|
||||
m_rnnoiseFill(0)
|
||||
{
|
||||
m_audioBuffer.resize(4800);
|
||||
m_audioBufferFill = 0;
|
||||
m_audioFifo.setSize(4800 * 4);
|
||||
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(getAudioFifo(), getInputMessageQueue());
|
||||
m_rnnoiseState = rnnoise_create(nullptr);
|
||||
}
|
||||
|
||||
DenoiserWorker::~DenoiserWorker()
|
||||
{
|
||||
m_inputMessageQueue.clear();
|
||||
DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(getAudioFifo());
|
||||
rnnoise_destroy(m_rnnoiseState);
|
||||
}
|
||||
|
||||
void DenoiserWorker::reset()
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
m_inputMessageQueue.clear();
|
||||
}
|
||||
|
||||
void DenoiserWorker::startWork()
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
m_wavFileRecord = new WavFileRecord(m_sinkSampleRate);
|
||||
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||
}
|
||||
|
||||
void DenoiserWorker::stopWork()
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
if (m_wavFileRecord)
|
||||
{
|
||||
delete m_wavFileRecord;
|
||||
m_wavFileRecord = nullptr;
|
||||
}
|
||||
disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
|
||||
}
|
||||
|
||||
void DenoiserWorker::feedPart(
|
||||
const QByteArray::const_iterator& begin,
|
||||
const QByteArray::const_iterator& end,
|
||||
DataFifo::DataType dataType
|
||||
)
|
||||
{
|
||||
int nbBytes;
|
||||
|
||||
switch(dataType)
|
||||
{
|
||||
case DataFifo::DataTypeCI16:
|
||||
nbBytes = 4;
|
||||
break;
|
||||
case DataFifo::DataTypeI16:
|
||||
default:
|
||||
nbBytes = 2;
|
||||
}
|
||||
|
||||
if ((nbBytes != m_nbBytes) && m_wavFileRecord)
|
||||
{
|
||||
m_wavFileRecord->stopRecording();
|
||||
m_wavFileRecord->setMono(nbBytes == 2);
|
||||
}
|
||||
|
||||
m_nbBytes = nbBytes;
|
||||
int countSamples = (end - begin) / nbBytes;
|
||||
|
||||
if (countSamples > m_sampleBufferSize)
|
||||
{
|
||||
m_sampleBuffer.resize(countSamples);
|
||||
m_sampleBufferSize = countSamples;
|
||||
}
|
||||
|
||||
for (int i = 0; i < countSamples; i++) {
|
||||
processSample(dataType, begin, i);
|
||||
}
|
||||
|
||||
if (m_settings.m_recordToFile && m_wavFileRecord)
|
||||
{
|
||||
for (const auto& sample : m_sampleBuffer) {
|
||||
writeSampleToFile(sample);
|
||||
}
|
||||
|
||||
m_sampleBuffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserWorker::writeSampleToFile(const Sample& sample)
|
||||
{
|
||||
if (!m_wavFileRecord) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (SDR_RX_SAMP_SZ == 16)
|
||||
{
|
||||
if (m_nbBytes == 2) {
|
||||
m_wavFileRecord->writeMono(sample.m_real);
|
||||
} else {
|
||||
m_wavFileRecord->write(sample.m_real, sample.m_imag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_nbBytes == 2) {
|
||||
m_wavFileRecord->writeMono(sample.m_real >> 8);
|
||||
} else {
|
||||
m_wavFileRecord->write(sample.m_real >> 8, sample.m_imag >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserWorker::handleInputMessages()
|
||||
{
|
||||
Message* message = nullptr;
|
||||
|
||||
while ((message = m_inputMessageQueue.pop()) != nullptr)
|
||||
{
|
||||
const Message& cmd = *message;
|
||||
handleMessage(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
bool DenoiserWorker::handleMessage(const Message& cmd)
|
||||
{
|
||||
if (MsgConfigureDenoiserWorker::match(cmd))
|
||||
{
|
||||
const MsgConfigureDenoiserWorker& conf = static_cast<const MsgConfigureDenoiserWorker&>(cmd);
|
||||
qDebug("DenoiserWorker::handleMessage: MsgConfigureDenoiserWorker");
|
||||
applySettings(conf.getSettings(), conf.getSettingsKeys(), conf.getForce());
|
||||
return true;
|
||||
}
|
||||
else if (MsgConnectFifo::match(cmd))
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
MsgConnectFifo& msg = (MsgConnectFifo&) cmd;
|
||||
m_dataFifo = msg.getFifo();
|
||||
bool doConnect = msg.getConnect();
|
||||
qDebug("DenoiserWorker::handleMessage: MsgConnectFifo: %s", (doConnect ? "connect" : "disconnect"));
|
||||
|
||||
if (doConnect) {
|
||||
QObject::connect(
|
||||
m_dataFifo,
|
||||
&DataFifo::dataReady,
|
||||
this,
|
||||
&DenoiserWorker::handleData,
|
||||
Qt::QueuedConnection
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
QObject::disconnect(
|
||||
m_dataFifo,
|
||||
&DataFifo::dataReady,
|
||||
this,
|
||||
&DenoiserWorker::handleData
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DenoiserWorker::applySettings(const DenoiserSettings& settings, const QStringList& settingsKeys, bool force)
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
qDebug() << "DenoiserWorker::applySettings" << settings.getDebugString(settingsKeys, force) << " force: " << force;
|
||||
|
||||
if (settingsKeys.contains("fileRecordName") || force)
|
||||
{
|
||||
if (m_wavFileRecord)
|
||||
{
|
||||
QStringList dotBreakout = settings.m_fileRecordName.split(QLatin1Char('.'));
|
||||
|
||||
if (dotBreakout.size() > 1)
|
||||
{
|
||||
QString extension = dotBreakout.last();
|
||||
|
||||
if (extension != "wav") {
|
||||
dotBreakout.last() = "wav";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dotBreakout.append("wav");
|
||||
}
|
||||
|
||||
QString newFileRecordName = dotBreakout.join(QLatin1Char('.'));
|
||||
QString fileBase;
|
||||
FileRecordInterface::guessTypeFromFileName(newFileRecordName, fileBase);
|
||||
qDebug("DemodAnalyzerWorker::applySettings: newFileRecordName: %s fileBase: %s", qPrintable(newFileRecordName), qPrintable(fileBase));
|
||||
m_wavFileRecord->setFileName(fileBase);
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsKeys.contains("recordToFile") || force)
|
||||
{
|
||||
if (m_wavFileRecord)
|
||||
{
|
||||
if (settings.m_recordToFile)
|
||||
{
|
||||
if (!m_wavFileRecord->isRecording()) {
|
||||
m_wavFileRecord->startRecording();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_wavFileRecord->isRecording()) {
|
||||
m_wavFileRecord->stopRecording();
|
||||
}
|
||||
}
|
||||
|
||||
m_recordSilenceCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((settingsKeys.contains("audioDeviceName") && (settings.m_audioDeviceName != m_settings.m_audioDeviceName)) || force)
|
||||
{
|
||||
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
|
||||
int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName);
|
||||
audioDeviceManager->removeAudioSink(getAudioFifo());
|
||||
audioDeviceManager->addAudioSink(getAudioFifo(), getInputMessageQueue(), audioDeviceIndex);
|
||||
unsigned int audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex);
|
||||
qDebug() << "DenoiserWorker::applySettings: audio device name:" << settings.m_audioDeviceName
|
||||
<< " index:" << audioDeviceIndex << " sample rate:" << audioSampleRate;
|
||||
// TODO: handle sample rate change
|
||||
}
|
||||
|
||||
if (settingsKeys.contains("enableDenoiser") || settingsKeys.contains("denoiserType") || force) {
|
||||
m_rnnoiseFill = 0;
|
||||
}
|
||||
|
||||
if (force) {
|
||||
m_settings = settings;
|
||||
} else {
|
||||
m_settings.applySettings(settingsKeys, settings);
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserWorker::applySampleRate(int sampleRate)
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
m_sinkSampleRate = sampleRate;
|
||||
|
||||
if (m_wavFileRecord)
|
||||
{
|
||||
if (m_wavFileRecord->isRecording()) {
|
||||
m_wavFileRecord->stopRecording();
|
||||
}
|
||||
|
||||
m_wavFileRecord->setSampleRate(m_sinkSampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserWorker::handleData()
|
||||
{
|
||||
QMutexLocker mutexLocker(&m_mutex);
|
||||
|
||||
while ((m_dataFifo->fill() > 0) && (m_inputMessageQueue.size() == 0))
|
||||
{
|
||||
QByteArray::iterator part1begin;
|
||||
QByteArray::iterator part1end;
|
||||
QByteArray::iterator part2begin;
|
||||
QByteArray::iterator part2end;
|
||||
DataFifo::DataType dataType;
|
||||
|
||||
std::size_t count = m_dataFifo->readBegin(m_dataFifo->fill(), &part1begin, &part1end, &part2begin, &part2end, dataType);
|
||||
|
||||
// first part of FIFO data
|
||||
if (part1begin != part1end) {
|
||||
feedPart(part1begin, part1end, dataType);
|
||||
}
|
||||
|
||||
// second part of FIFO data (used when block wraps around)
|
||||
if (part2begin != part2end) {
|
||||
feedPart(part2begin, part2end, dataType);
|
||||
}
|
||||
|
||||
m_dataFifo->readCommit((unsigned int) count);
|
||||
}
|
||||
|
||||
qreal rmsLevel, peakLevel;
|
||||
int numSamples;
|
||||
getLevels(rmsLevel, peakLevel, numSamples);
|
||||
emit levelChanged(rmsLevel, peakLevel, numSamples);
|
||||
}
|
||||
|
||||
void DenoiserWorker::processSample(
|
||||
DataFifo::DataType dataType,
|
||||
const QByteArray::const_iterator& begin,
|
||||
int i
|
||||
)
|
||||
{
|
||||
switch(dataType)
|
||||
{
|
||||
case DataFifo::DataTypeI16:
|
||||
{
|
||||
int16_t *s = (int16_t*) begin;
|
||||
double samplefp = s[i] * (m_settings.m_volumeTenths / 10.0);
|
||||
double re = samplefp / (double) std::numeric_limits<int16_t>::max();
|
||||
calculateLevel(re);
|
||||
m_magsq = re*re;
|
||||
m_channelPowerAvg(m_magsq);
|
||||
|
||||
if ((!m_settings.m_enableDenoiser || m_settings.m_denoiserType == DenoiserSettings::DenoiserType::DenoiserType_None) && !m_settings.m_audioMute) {
|
||||
processI16DenoiserNone(samplefp);
|
||||
}
|
||||
else if ((m_settings.m_denoiserType == DenoiserSettings::DenoiserType::DenoiserType_RNnoise) && !m_settings.m_audioMute) {
|
||||
processI16DenoiserRNNoise(samplefp);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DataFifo::DataTypeCI16:
|
||||
{
|
||||
int16_t *s = (int16_t*) begin;
|
||||
double samplefpRe = s[2*i] * (m_settings.m_volumeTenths / 10.0);
|
||||
double samplefpIm = s[2*i+1] * (m_settings.m_volumeTenths / 10.0);
|
||||
double re = samplefpRe / (double) std::numeric_limits<int16_t>::max();
|
||||
double im = samplefpIm / (double) std::numeric_limits<int16_t>::max();
|
||||
calculateLevel((re + im) / 2.0);
|
||||
m_magsq = re*re + im*im;
|
||||
m_channelPowerAvg(m_magsq);
|
||||
|
||||
if ((!m_settings.m_enableDenoiser || m_settings.m_denoiserType == DenoiserSettings::DenoiserType::DenoiserType_None) && !m_settings.m_audioMute) {
|
||||
processCI16DenoiserNone(samplefpRe, samplefpIm);
|
||||
}
|
||||
else if ((m_settings.m_denoiserType == DenoiserSettings::DenoiserType::DenoiserType_RNnoise) && !m_settings.m_audioMute) {
|
||||
processCI16DenoiserRNNoise(samplefpRe, samplefpIm);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserWorker::processI16DenoiserNone(const double& samplefp)
|
||||
{
|
||||
if (m_channelPowerAvg.asDouble() > 1e-4) { // -40 dB threshold
|
||||
m_sampleBuffer.push_back(Sample(samplefp, 0));
|
||||
}
|
||||
|
||||
m_audioBuffer[m_audioBufferFill].l = static_cast<int16_t>(samplefp);
|
||||
m_audioBuffer[m_audioBufferFill].r = static_cast<int16_t>(samplefp);
|
||||
++m_audioBufferFill;
|
||||
|
||||
if (m_audioBufferFill >= m_audioBuffer.size())
|
||||
{
|
||||
std::size_t res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
|
||||
|
||||
if (res != m_audioBufferFill)
|
||||
{
|
||||
qDebug("DenoiserWorker::processSample: %lu/%lu audio samples written", res, m_audioBufferFill);
|
||||
m_audioFifo.clear();
|
||||
}
|
||||
|
||||
m_audioBufferFill = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserWorker::processI16DenoiserRNNoise(const double& samplefp)
|
||||
{
|
||||
// feed RNNoise input buffer
|
||||
m_rnnoiseIn[m_rnnoiseFill] = static_cast<float>(samplefp); // already in [-32768..32767] range
|
||||
m_rnnoiseFill++;
|
||||
|
||||
if (m_rnnoiseFill >= 480)
|
||||
{
|
||||
// process RNNoise frame
|
||||
rnnoise_process_frame(m_rnnoiseState, m_rnnoiseOut, m_rnnoiseIn);
|
||||
|
||||
// output RNNoise processed samples
|
||||
for (int j = 0; j < 480; j++)
|
||||
{
|
||||
float outSample = m_rnnoiseOut[j];
|
||||
|
||||
if (m_channelPowerAvg.asDouble() > 1e-4) { // -40 dB threshold
|
||||
m_sampleBuffer.push_back(Sample(outSample * 181, 0)); // 181 = sqrt(32768)
|
||||
}
|
||||
|
||||
int16_t audioSample = static_cast<int16_t>(outSample);
|
||||
m_audioBuffer[m_audioBufferFill].l = audioSample;
|
||||
m_audioBuffer[m_audioBufferFill].r = audioSample;
|
||||
++m_audioBufferFill;
|
||||
|
||||
if (m_audioBufferFill >= m_audioBuffer.size())
|
||||
{
|
||||
std::size_t res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
|
||||
|
||||
if (res != m_audioBufferFill)
|
||||
{
|
||||
qDebug("DenoiserWorker::processSample: %lu/%lu audio samples written", res, m_audioBufferFill);
|
||||
m_audioFifo.clear();
|
||||
}
|
||||
|
||||
m_audioBufferFill = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_rnnoiseFill = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserWorker::processCI16DenoiserNone(const double& samplefpRe, const double& samplefpIm)
|
||||
{
|
||||
if (m_channelPowerAvg.asDouble() > 1e-4) { // -40 dB threshold
|
||||
m_sampleBuffer.push_back(Sample(samplefpRe, samplefpIm));
|
||||
}
|
||||
|
||||
m_audioBuffer[m_audioBufferFill].l = static_cast<int16_t>(samplefpRe);
|
||||
m_audioBuffer[m_audioBufferFill].r = static_cast<int16_t>(samplefpIm);
|
||||
++m_audioBufferFill;
|
||||
|
||||
if (m_audioBufferFill >= m_audioBuffer.size())
|
||||
{
|
||||
std::size_t res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
|
||||
|
||||
if (res != m_audioBufferFill)
|
||||
{
|
||||
qDebug("DenoiserWorker::processSample: %lu/%lu audio samples written", res, m_audioBufferFill);
|
||||
m_audioFifo.clear();
|
||||
}
|
||||
|
||||
m_audioBufferFill = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserWorker::processCI16DenoiserRNNoise(const double& samplefpRe, const double& samplefpIm)
|
||||
{
|
||||
Q_UNUSED(samplefpRe);
|
||||
Q_UNUSED(samplefpIm);
|
||||
// feed RNNoise input buffer
|
||||
m_rnnoiseIn[m_rnnoiseFill] = static_cast<float>((samplefpRe + samplefpIm) / 2.0f); // average I/Q in [-32768..32767] range
|
||||
m_rnnoiseFill++;
|
||||
|
||||
if (m_rnnoiseFill >= 480)
|
||||
{
|
||||
// process RNNoise frame
|
||||
rnnoise_process_frame(m_rnnoiseState, m_rnnoiseOut, m_rnnoiseIn);
|
||||
|
||||
// output RNNoise processed samples
|
||||
for (int j = 0; j < 480; j++)
|
||||
{
|
||||
float outSample = m_rnnoiseOut[j];
|
||||
|
||||
if (m_channelPowerAvg.asDouble() > 1e-4) { // -40 dB threshold
|
||||
m_sampleBuffer.push_back(Sample(outSample * 181, outSample * 181)); // 181 = sqrt(32768)
|
||||
}
|
||||
|
||||
int16_t audioSample = static_cast<int16_t>(outSample);
|
||||
m_audioBuffer[m_audioBufferFill].l = audioSample;
|
||||
m_audioBuffer[m_audioBufferFill].r = audioSample;
|
||||
++m_audioBufferFill;
|
||||
|
||||
if (m_audioBufferFill >= m_audioBuffer.size())
|
||||
{
|
||||
std::size_t res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
|
||||
|
||||
if (res != m_audioBufferFill)
|
||||
{
|
||||
qDebug("DenoiserWorker::processSample: %lu/%lu audio samples written", res, m_audioBufferFill);
|
||||
m_audioFifo.clear();
|
||||
}
|
||||
|
||||
m_audioBufferFill = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_rnnoiseFill = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DenoiserWorker::calculateLevel(const Real& sample)
|
||||
{
|
||||
if (m_levelCalcCount < m_levelNbSamples)
|
||||
{
|
||||
m_peakLevel = std::max(std::fabs(m_peakLevel), sample);
|
||||
m_levelSum += sample * sample;
|
||||
m_levelCalcCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rmsLevel = sqrt(m_levelSum / m_levelNbSamples);
|
||||
m_peakLevelOut = m_peakLevel;
|
||||
m_peakLevel = 0.0f;
|
||||
m_levelSum = 0.0f;
|
||||
m_levelCalcCount = 0;
|
||||
}
|
||||
}
|
||||
164
plugins/feature/denoiser/denoiserworker.h
Normal file
164
plugins/feature/denoiser/denoiserworker.h
Normal file
@ -0,0 +1,164 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2026 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef INCLUDE_FEATURE_DENOISER_DENOISERWORKER_H_
|
||||
#define INCLUDE_FEATURE_DENOISER_DENOISERWORKER_H_
|
||||
|
||||
#include <QObject>
|
||||
#include <QRecursiveMutex>
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
|
||||
#include "util/movingaverage.h"
|
||||
#include "util/message.h"
|
||||
#include "util/messagequeue.h"
|
||||
#include "dsp/dsptypes.h"
|
||||
#include "dsp/datafifo.h"
|
||||
#include "audio/audiofifo.h"
|
||||
|
||||
#include "denoisersettings.h"
|
||||
|
||||
class WavFileRecord;
|
||||
struct DenoiseState;
|
||||
|
||||
class DenoiserWorker : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
class MsgConfigureDenoiserWorker : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
public:
|
||||
const DenoiserSettings& getSettings() const { return m_settings; }
|
||||
const QStringList& getSettingsKeys() const { return m_settingsKeys; }
|
||||
bool getForce() const { return m_force; }
|
||||
static MsgConfigureDenoiserWorker* create(const DenoiserSettings& settings, const QStringList& settingsKeys, bool force)
|
||||
{
|
||||
return new MsgConfigureDenoiserWorker(settings, settingsKeys, force);
|
||||
}
|
||||
private:
|
||||
DenoiserSettings m_settings;
|
||||
QStringList m_settingsKeys;
|
||||
bool m_force;
|
||||
MsgConfigureDenoiserWorker(const DenoiserSettings& settings, const QStringList& settingsKeys, bool force) :
|
||||
Message(),
|
||||
m_settings(settings),
|
||||
m_settingsKeys(settingsKeys),
|
||||
m_force(force)
|
||||
{ }
|
||||
};
|
||||
|
||||
class MsgConnectFifo : public Message {
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
public:
|
||||
DataFifo *getFifo() { return m_fifo; }
|
||||
bool getConnect() const { return m_connect; }
|
||||
static MsgConnectFifo* create(DataFifo *fifo, bool connect) {
|
||||
return new MsgConnectFifo(fifo, connect);
|
||||
}
|
||||
private:
|
||||
DataFifo *m_fifo;
|
||||
bool m_connect;
|
||||
MsgConnectFifo(DataFifo *fifo, bool connect) :
|
||||
Message(),
|
||||
m_fifo(fifo),
|
||||
m_connect(connect)
|
||||
{ }
|
||||
};
|
||||
|
||||
explicit DenoiserWorker(QObject *parent = nullptr);
|
||||
~DenoiserWorker() override;
|
||||
void reset();
|
||||
void startWork();
|
||||
void stopWork();
|
||||
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||
void setMessageQueueToFeature(MessageQueue *messageQueue) { m_msgQueueToFeature = messageQueue; }
|
||||
void applySampleRate(int sampleRate);
|
||||
void applySettings(const DenoiserSettings& settings, const QStringList& settingsKeys, bool force = false);
|
||||
double getMagSq() const { return m_magsq; }
|
||||
double getMagSqAvg() const { return (double) m_channelPowerAvg; }
|
||||
void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const
|
||||
{
|
||||
rmsLevel = m_rmsLevel;
|
||||
peakLevel = m_peakLevelOut;
|
||||
numSamples = m_levelNbSamples;
|
||||
}
|
||||
|
||||
signals:
|
||||
/**
|
||||
* Level changed
|
||||
* \param rmsLevel RMS level in range 0.0 - 1.0
|
||||
* \param peakLevel Peak level in range 0.0 - 1.0
|
||||
* \param numSamples Number of audio samples analyzed
|
||||
*/
|
||||
void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples);
|
||||
|
||||
private:
|
||||
DataFifo *m_dataFifo;
|
||||
int m_sinkSampleRate;
|
||||
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
|
||||
MessageQueue *m_msgQueueToFeature; //!< Queue to report channel change to main feature object
|
||||
DenoiserSettings m_settings;
|
||||
double m_magsq;
|
||||
SampleVector m_sampleBuffer;
|
||||
int m_sampleBufferSize;
|
||||
MovingAverageUtil<double, double, 480> m_channelPowerAvg;
|
||||
WavFileRecord* m_wavFileRecord;
|
||||
int m_recordSilenceNbSamples;
|
||||
int m_recordSilenceCount;
|
||||
int m_nbBytes;
|
||||
AudioVector m_audioBuffer;
|
||||
AudioFifo m_audioFifo;
|
||||
std::size_t m_audioBufferFill;
|
||||
DenoiseState *m_rnnoiseState;
|
||||
float m_rnnoiseIn[480];
|
||||
float m_rnnoiseOut[480];
|
||||
int m_rnnoiseFill;
|
||||
|
||||
quint32 m_levelCalcCount = 0;
|
||||
qreal m_rmsLevel;
|
||||
qreal m_peakLevelOut;
|
||||
Real m_peakLevel = 0.0f;
|
||||
Real m_levelSum = 0.0f;
|
||||
|
||||
QRecursiveMutex m_mutex;
|
||||
|
||||
static const int m_levelNbSamples;
|
||||
|
||||
AudioFifo *getAudioFifo() { return &m_audioFifo; }
|
||||
void feedPart(
|
||||
const QByteArray::const_iterator& begin,
|
||||
const QByteArray::const_iterator& end,
|
||||
DataFifo::DataType dataType
|
||||
);
|
||||
|
||||
bool handleMessage(const Message& cmd);
|
||||
void writeSampleToFile(const Sample& sample);
|
||||
void processSample(
|
||||
DataFifo::DataType dataType,
|
||||
const QByteArray::const_iterator& begin,
|
||||
int i
|
||||
);
|
||||
void processI16DenoiserNone(const double& samplefp);
|
||||
void processI16DenoiserRNNoise(const double& samplefp);
|
||||
void processCI16DenoiserNone(const double& samplefpRe, const double& samplefpIm);
|
||||
void processCI16DenoiserRNNoise(const double& samplefpRe, const double& samplefpIm);
|
||||
void calculateLevel(const Real& sample);
|
||||
|
||||
private slots:
|
||||
void handleInputMessages();
|
||||
void handleData(); //!< Handle data when samples have to be processed
|
||||
};
|
||||
|
||||
#endif // INCLUDE_FEATURE_DENOISER_DENOISERWORKER_H_
|
||||
106
plugins/feature/denoiser/readme.md
Normal file
106
plugins/feature/denoiser/readme.md
Normal file
@ -0,0 +1,106 @@
|
||||
<h1>Demoiser</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
This audio denoiser plugin can be used to reduce or remove noise from audio. For now it only implements the RNNoise noise reduction (more details next)
|
||||
|
||||
It connects to the "demod" stream of Rx channels similarly to the Demod analyzer plugin. Hence it covers:
|
||||
|
||||
- AM demodulator
|
||||
- Broadcast FM demodulator
|
||||
- NFM demodulator
|
||||
- SSB demodulator
|
||||
- WFM demodulator
|
||||
- WDSP plugin (multimode)
|
||||
|
||||
Note that this plugin is available only in Linux
|
||||
|
||||
The following noise reduction schemes are covered. It can be selected via the (6) combo box:
|
||||
|
||||
<h3>RNNoise</h3>
|
||||
|
||||
Noise reduction based on the RNnoise library originally from J.M. Valin. It uses a fork for easier integration in the build system (Cmake support with download of the model file): https://github.com/f4exb/rnnoise
|
||||
|
||||
The noise reduction is based on a mix of DSP functions and a recursive neural network (RNN). Basically the RNN helps the DSP functions to adjust the gain in various spectral bands thus very efficiently cancelling the background noise in many situations. Although the model was not particularly trained on radio transmissions it can do a pretty good job at AM, SSB noise reduction however you will need a reasonable SNR to get something out of it else it will consider the audio is just noise. Do not expect it to dig signals out of the noise the goal is to reduce ear fatigue by removing background white noise and other noises e.g birdies. Results for FM signals may vary.
|
||||
|
||||
You will find all the details about RNnoise here: https://jmvalin.ca/demo/rnnoise/
|
||||
|
||||
Please note the following points:
|
||||
|
||||
- Audio sample rate must be 48 kS/s (check 4)
|
||||
- When taking the audio source from the WDSP plugin it should be used without noise reduction
|
||||
- You should have enough input level but not exceed 100% on peaks (check 9 and 10). An average level between 10 and 20% should already provide good results
|
||||
- The model has been trained on human voice therefore anything else like music is considered to be noise. It may however be successful at selecting the voice from songs.
|
||||
- It should have enough original spectral components therefore any noise processing before the input will only deteriorate its performance. It should also have enough bandwidth it is recommended to have at least 100-3000 Hz. It is not an issue to extend beyond 3000 Hz because any high frequency hiss will be cancelled and it may benefit from the extra bandwidth on some transmissions.
|
||||
- With SSB transmisions the pitch should be as close as possible to the natural pitch of the voice. In any case prefer a higher pitch to a lower one. Note that some voices are better processed than others which may also depend on voice processing before transmission.
|
||||
|
||||
<h2>Interface</h2>
|
||||
|
||||

|
||||
|
||||
<h3>1: Start/Stop plugin</h3>
|
||||
|
||||
This button starts or stops the plugin
|
||||
|
||||
<h3>2: Channel selection</h3>
|
||||
|
||||
Use this combo to select which channel to use for display. Channel is selected at start time and upon change. You may use button (3) to force association with the channel if necessary.
|
||||
|
||||
<h3>3: (Re)apply channel selection</h3>
|
||||
|
||||
Applies or re-applies channel association (2) so that the channel gets effectively (re)connected to the denoiser. Normally it should not be necessary to use it.
|
||||
|
||||
<h3>4: Input sample rate</h3>
|
||||
|
||||
This is the input audio stream sample rate and for RNNoise it should always be 48 kS/s
|
||||
|
||||
<h3>5: Input power</h4>
|
||||
|
||||
Indication of the input audio stream power
|
||||
|
||||
<h3>6: Noise reduction scheme</h3>
|
||||
|
||||
Selects the noise reduction scheme
|
||||
|
||||
- **None**: No noise reduction (passthrough)
|
||||
- **RNnoise**: RNNoise (see introduction)
|
||||
|
||||
<h3>7: Noise reduction enable</h3>
|
||||
|
||||
Enable or disable noise reduction. When disabled it just passes audio through
|
||||
|
||||
<h3>8: Audio mute and device selection</h3>
|
||||
|
||||
- Left click: Mute or unmute audio
|
||||
- Right click: opens a dialog to select audio output device
|
||||
|
||||
<h3>9: Input volume</h3>
|
||||
|
||||
This button lets you adjust the input volume. Adjust for best dynamic but the peaks should not exceed 100% as displayed in the VU meter next (10)
|
||||
|
||||
<h3>10: Input VU meter</h3>
|
||||
|
||||
This is the VU meter of the audio entering the noise reduction block. The peaks should not exceed 100%
|
||||
|
||||
<h3>11: Record audio output</h3>
|
||||
|
||||
Start/stop recording. Each start -> stop creates a new record file (see next)
|
||||
|
||||
<h3>12: Select output record file</h3>
|
||||
|
||||
Click on this icon to open a file selection dialog that lets you specify the location and name of the output files.
|
||||
|
||||
Each recording is written in a new file with the starting timestamp before the `.wav` extension in `yyyy-MM-ddTHH_mm_ss_zzz` format. It keeps the first dot limited groups of the filename before the `.wav` extension if there are two such groups or before the two last groups if there are more than two groups. Examples:
|
||||
|
||||
- Given file name: `test.wav` then a recording file will be like: `test.2020-08-05T21_39_07_974.wav`
|
||||
- Given file name: `test.2020-08-05T20_36_15_974.wav` then a recording file will be like (with timestamp updated): `test.2020-08-05T21_41_21_173.wav`
|
||||
- Given file name: `test.first.wav` then a recording file will be like: `test.2020-08-05T22_00_07_974.wav`
|
||||
- Given file name: `record.test.first.wav` then a recording file will be like: `record.test.2020-08-05T21_39_52_974.wav`
|
||||
|
||||
If a filename is given without `.wav` extension then the `.wav` extension is appended automatically before the above algorithm is applied. If a filename is given with an extension different of `.wav` then the extension is replaced by `.wav` automatically before the above algorithm is applied.
|
||||
|
||||
The file path currently being written (or last closed) appears at the right of the button (13).
|
||||
|
||||
<h3>13: Output record file name</h3>
|
||||
|
||||
File path currently being written (or last closed)
|
||||
@ -40,6 +40,7 @@
|
||||
<file>webapi/doc/swagger/include/DATVDemod.yaml</file>
|
||||
<file>webapi/doc/swagger/include/DATVMod.yaml</file>
|
||||
<file>webapi/doc/swagger/include/DemodAnalyzer.yaml</file>
|
||||
<file>webapi/doc/swagger/include/Denoiser.yaml</file>
|
||||
<file>webapi/doc/swagger/include/DeviceActions.yaml</file>
|
||||
<file>webapi/doc/swagger/include/DeviceReports.yaml</file>
|
||||
<file>webapi/doc/swagger/include/DeviceSettings.yaml</file>
|
||||
|
||||
@ -5631,6 +5631,78 @@ margin-bottom: 20px;
|
||||
}
|
||||
},
|
||||
"description" : "DemodAnalyzer"
|
||||
};
|
||||
defs.DenoiserActions = {
|
||||
"required" : [ "channelId", "deviceId" ],
|
||||
"properties" : {
|
||||
"deviceId" : {
|
||||
"type" : "integer",
|
||||
"description" : "Set source device Id/Number that channel belongs to"
|
||||
},
|
||||
"channelId" : {
|
||||
"type" : "integer",
|
||||
"description" : "Set source channel Id/Number of the channel within the device"
|
||||
}
|
||||
},
|
||||
"description" : "Denoiser actions"
|
||||
};
|
||||
defs.DenoiserSettings = {
|
||||
"properties" : {
|
||||
"denoiserType" : {
|
||||
"type" : "integer",
|
||||
"description" : "Denoiser type\n * 0 - none\n * 1 - RNnoise\n"
|
||||
},
|
||||
"enableDenoiser" : {
|
||||
"type" : "integer",
|
||||
"description" : "Enable denoiser\n * 1 - enable\n * 0 - disable\n"
|
||||
},
|
||||
"volumeTenths" : {
|
||||
"type" : "integer",
|
||||
"description" : "Output volume in tenths (e.g., 10 = 1.0)\n"
|
||||
},
|
||||
"audioDeviceName" : {
|
||||
"type" : "string",
|
||||
"description" : "Audio output device name"
|
||||
},
|
||||
"audioMute" : {
|
||||
"type" : "integer",
|
||||
"description" : "Audio mute\n * 1 - mute\n * 0 - unmute\n"
|
||||
},
|
||||
"title" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"rgbColor" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"fileRecordName" : {
|
||||
"type" : "string",
|
||||
"description" : "Output wave file name"
|
||||
},
|
||||
"recordToFile" : {
|
||||
"type" : "integer",
|
||||
"description" : "Recording status\n * 1 - recording\n * 0 - not recording\n"
|
||||
},
|
||||
"useReverseAPI" : {
|
||||
"type" : "integer",
|
||||
"description" : "Synchronize with reverse API\n * 1 - yes\n * 0 - no\n"
|
||||
},
|
||||
"reverseAPIAddress" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"reverseAPIPort" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"reverseAPIFeatureSetIndex" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"reverseAPIFeatureIndex" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"rollupState" : {
|
||||
"$ref" : "#/definitions/RollupState"
|
||||
}
|
||||
},
|
||||
"description" : "Denoiser"
|
||||
};
|
||||
defs.DeviceActions = {
|
||||
"required" : [ "deviceHwType", "direction" ],
|
||||
@ -6524,6 +6596,9 @@ margin-bottom: 20px;
|
||||
},
|
||||
"DemodAnalyzerActions" : {
|
||||
"$ref" : "#/definitions/DemodAnalyzerActions"
|
||||
},
|
||||
"DenoiserActions" : {
|
||||
"$ref" : "#/definitions/DenoiserActions"
|
||||
}
|
||||
},
|
||||
"description" : "Base feature actions. Only the feature actions corresponding to the feature specified in the featureType field is or should be present."
|
||||
@ -6741,6 +6816,9 @@ margin-bottom: 20px;
|
||||
"DemodAnalyzerSettings" : {
|
||||
"$ref" : "#/definitions/DemodAnalyzerSettings"
|
||||
},
|
||||
"DenoiserSettings" : {
|
||||
"$ref" : "#/definitions/DenoiserSettings"
|
||||
},
|
||||
"JogdialControllerSettings" : {
|
||||
"$ref" : "#/definitions/JogdialControllerSettings"
|
||||
},
|
||||
@ -59754,7 +59832,7 @@ except ApiException as e:
|
||||
</div>
|
||||
<div id="generator">
|
||||
<div class="content">
|
||||
Generated 2026-01-04T12:41:15.650+01:00
|
||||
Generated 2026-01-10T11:16:10.140+01:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
70
sdrbase/resources/webapi/doc/swagger/include/Denoiser.yaml
Normal file
70
sdrbase/resources/webapi/doc/swagger/include/Denoiser.yaml
Normal file
@ -0,0 +1,70 @@
|
||||
DenoiserSettings:
|
||||
description: Denoiser
|
||||
properties:
|
||||
denoiserType:
|
||||
type: integer
|
||||
description: >
|
||||
Denoiser type
|
||||
* 0 - none
|
||||
* 1 - RNnoise
|
||||
enableDenoiser:
|
||||
type: integer
|
||||
description: >
|
||||
Enable denoiser
|
||||
* 1 - enable
|
||||
* 0 - disable
|
||||
volumeTenths:
|
||||
type: integer
|
||||
description: >
|
||||
Output volume in tenths (e.g., 10 = 1.0)
|
||||
audioDeviceName:
|
||||
type: string
|
||||
description: Audio output device name
|
||||
audioMute:
|
||||
type: integer
|
||||
description: >
|
||||
Audio mute
|
||||
* 1 - mute
|
||||
* 0 - unmute
|
||||
title:
|
||||
type: string
|
||||
rgbColor:
|
||||
type: integer
|
||||
fileRecordName:
|
||||
type: string
|
||||
description: Output wave file name
|
||||
recordToFile:
|
||||
type: integer
|
||||
description: >
|
||||
Recording status
|
||||
* 1 - recording
|
||||
* 0 - not recording
|
||||
useReverseAPI:
|
||||
type: integer
|
||||
description: >
|
||||
Synchronize with reverse API
|
||||
* 1 - yes
|
||||
* 0 - no
|
||||
reverseAPIAddress:
|
||||
type: string
|
||||
reverseAPIPort:
|
||||
type: integer
|
||||
reverseAPIFeatureSetIndex:
|
||||
type: integer
|
||||
reverseAPIFeatureIndex:
|
||||
type: integer
|
||||
rollupState:
|
||||
$ref: "/doc/swagger/include/RollupState.yaml#/RollupState"
|
||||
|
||||
DenoiserActions:
|
||||
description: "Denoiser actions"
|
||||
required:
|
||||
- deviceId
|
||||
- channelId
|
||||
properties:
|
||||
deviceId:
|
||||
type: integer
|
||||
description: "Set source device Id/Number that channel belongs to"
|
||||
channelId:
|
||||
type: integer
|
||||
description: "Set source channel Id/Number of the channel within the device"
|
||||
@ -41,3 +41,5 @@ FeatureActions:
|
||||
$ref: "/doc/swagger/include/VORLocalizer.yaml#/VORLocalizerActions"
|
||||
DemodAnalyzerActions:
|
||||
$ref: "/doc/swagger/include/DemodAnalyzer.yaml#/DemodAnalyzerActions"
|
||||
DenoiserActions:
|
||||
$ref: "/doc/swagger/include/Denoiser.yaml#/DenoiserActions"
|
||||
|
||||
@ -25,6 +25,8 @@ FeatureSettings:
|
||||
$ref: "/doc/swagger/include/APRS.yaml#/APRSSettings"
|
||||
DemodAnalyzerSettings:
|
||||
$ref: "/doc/swagger/include/DemodAnalyzer.yaml#/DemodAnalyzerSettings"
|
||||
DenoiserSettings:
|
||||
$ref: "/doc/swagger/include/Denoiser.yaml#/DenoiserSettings"
|
||||
JogdialControllerSettings:
|
||||
$ref: "/doc/swagger/include/JogdialController.yaml#/JogdialControllerSettings"
|
||||
GS232ControllerSettings:
|
||||
|
||||
70
swagger/sdrangel/api/swagger/include/Denoiser.yaml
Normal file
70
swagger/sdrangel/api/swagger/include/Denoiser.yaml
Normal file
@ -0,0 +1,70 @@
|
||||
DenoiserSettings:
|
||||
description: Denoiser
|
||||
properties:
|
||||
denoiserType:
|
||||
type: integer
|
||||
description: >
|
||||
Denoiser type
|
||||
* 0 - none
|
||||
* 1 - RNnoise
|
||||
enableDenoiser:
|
||||
type: integer
|
||||
description: >
|
||||
Enable denoiser
|
||||
* 1 - enable
|
||||
* 0 - disable
|
||||
volumeTenths:
|
||||
type: integer
|
||||
description: >
|
||||
Output volume in tenths (e.g., 10 = 1.0)
|
||||
audioDeviceName:
|
||||
type: string
|
||||
description: Audio output device name
|
||||
audioMute:
|
||||
type: integer
|
||||
description: >
|
||||
Audio mute
|
||||
* 1 - mute
|
||||
* 0 - unmute
|
||||
title:
|
||||
type: string
|
||||
rgbColor:
|
||||
type: integer
|
||||
fileRecordName:
|
||||
type: string
|
||||
description: Output wave file name
|
||||
recordToFile:
|
||||
type: integer
|
||||
description: >
|
||||
Recording status
|
||||
* 1 - recording
|
||||
* 0 - not recording
|
||||
useReverseAPI:
|
||||
type: integer
|
||||
description: >
|
||||
Synchronize with reverse API
|
||||
* 1 - yes
|
||||
* 0 - no
|
||||
reverseAPIAddress:
|
||||
type: string
|
||||
reverseAPIPort:
|
||||
type: integer
|
||||
reverseAPIFeatureSetIndex:
|
||||
type: integer
|
||||
reverseAPIFeatureIndex:
|
||||
type: integer
|
||||
rollupState:
|
||||
$ref: "http://swgserver:8081/api/swagger/include/RollupState.yaml#/RollupState"
|
||||
|
||||
DenoiserActions:
|
||||
description: "Denoiser actions"
|
||||
required:
|
||||
- deviceId
|
||||
- channelId
|
||||
properties:
|
||||
deviceId:
|
||||
type: integer
|
||||
description: "Set source device Id/Number that channel belongs to"
|
||||
channelId:
|
||||
type: integer
|
||||
description: "Set source channel Id/Number of the channel within the device"
|
||||
@ -41,3 +41,5 @@ FeatureActions:
|
||||
$ref: "http://swgserver:8081/api/swagger/include/VORLocalizer.yaml#/VORLocalizerActions"
|
||||
DemodAnalyzerActions:
|
||||
$ref: "http://swgserver:8081/api/swagger/include/DemodAnalyzer.yaml#/DemodAnalyzerActions"
|
||||
DenoiserActions:
|
||||
$ref: "http://swgserver:8081/api/swagger/include/Denoiser.yaml#/DenoiserActions"
|
||||
|
||||
@ -25,6 +25,8 @@ FeatureSettings:
|
||||
$ref: "http://swgserver:8081/api/swagger/include/APRS.yaml#/APRSSettings"
|
||||
DemodAnalyzerSettings:
|
||||
$ref: "http://swgserver:8081/api/swagger/include/DemodAnalyzer.yaml#/DemodAnalyzerSettings"
|
||||
DenoiserSettings:
|
||||
$ref: "http://swgserver:8081/api/swagger/include/Denoiser.yaml#/DenoiserSettings"
|
||||
JogdialControllerSettings:
|
||||
$ref: "http://swgserver:8081/api/swagger/include/JogdialController.yaml#/JogdialControllerSettings"
|
||||
GS232ControllerSettings:
|
||||
|
||||
@ -5631,6 +5631,78 @@ margin-bottom: 20px;
|
||||
}
|
||||
},
|
||||
"description" : "DemodAnalyzer"
|
||||
};
|
||||
defs.DenoiserActions = {
|
||||
"required" : [ "channelId", "deviceId" ],
|
||||
"properties" : {
|
||||
"deviceId" : {
|
||||
"type" : "integer",
|
||||
"description" : "Set source device Id/Number that channel belongs to"
|
||||
},
|
||||
"channelId" : {
|
||||
"type" : "integer",
|
||||
"description" : "Set source channel Id/Number of the channel within the device"
|
||||
}
|
||||
},
|
||||
"description" : "Denoiser actions"
|
||||
};
|
||||
defs.DenoiserSettings = {
|
||||
"properties" : {
|
||||
"denoiserType" : {
|
||||
"type" : "integer",
|
||||
"description" : "Denoiser type\n * 0 - none\n * 1 - RNnoise\n"
|
||||
},
|
||||
"enableDenoiser" : {
|
||||
"type" : "integer",
|
||||
"description" : "Enable denoiser\n * 1 - enable\n * 0 - disable\n"
|
||||
},
|
||||
"volumeTenths" : {
|
||||
"type" : "integer",
|
||||
"description" : "Output volume in tenths (e.g., 10 = 1.0)\n"
|
||||
},
|
||||
"audioDeviceName" : {
|
||||
"type" : "string",
|
||||
"description" : "Audio output device name"
|
||||
},
|
||||
"audioMute" : {
|
||||
"type" : "integer",
|
||||
"description" : "Audio mute\n * 1 - mute\n * 0 - unmute\n"
|
||||
},
|
||||
"title" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"rgbColor" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"fileRecordName" : {
|
||||
"type" : "string",
|
||||
"description" : "Output wave file name"
|
||||
},
|
||||
"recordToFile" : {
|
||||
"type" : "integer",
|
||||
"description" : "Recording status\n * 1 - recording\n * 0 - not recording\n"
|
||||
},
|
||||
"useReverseAPI" : {
|
||||
"type" : "integer",
|
||||
"description" : "Synchronize with reverse API\n * 1 - yes\n * 0 - no\n"
|
||||
},
|
||||
"reverseAPIAddress" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"reverseAPIPort" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"reverseAPIFeatureSetIndex" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"reverseAPIFeatureIndex" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"rollupState" : {
|
||||
"$ref" : "#/definitions/RollupState"
|
||||
}
|
||||
},
|
||||
"description" : "Denoiser"
|
||||
};
|
||||
defs.DeviceActions = {
|
||||
"required" : [ "deviceHwType", "direction" ],
|
||||
@ -6524,6 +6596,9 @@ margin-bottom: 20px;
|
||||
},
|
||||
"DemodAnalyzerActions" : {
|
||||
"$ref" : "#/definitions/DemodAnalyzerActions"
|
||||
},
|
||||
"DenoiserActions" : {
|
||||
"$ref" : "#/definitions/DenoiserActions"
|
||||
}
|
||||
},
|
||||
"description" : "Base feature actions. Only the feature actions corresponding to the feature specified in the featureType field is or should be present."
|
||||
@ -6741,6 +6816,9 @@ margin-bottom: 20px;
|
||||
"DemodAnalyzerSettings" : {
|
||||
"$ref" : "#/definitions/DemodAnalyzerSettings"
|
||||
},
|
||||
"DenoiserSettings" : {
|
||||
"$ref" : "#/definitions/DenoiserSettings"
|
||||
},
|
||||
"JogdialControllerSettings" : {
|
||||
"$ref" : "#/definitions/JogdialControllerSettings"
|
||||
},
|
||||
@ -59754,7 +59832,7 @@ except ApiException as e:
|
||||
</div>
|
||||
<div id="generator">
|
||||
<div class="content">
|
||||
Generated 2026-01-04T12:41:15.650+01:00
|
||||
Generated 2026-01-10T11:16:10.140+01:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
131
swagger/sdrangel/code/qt5/client/SWGDenoiserActions.cpp
Normal file
131
swagger/sdrangel/code/qt5/client/SWGDenoiserActions.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
/**
|
||||
* SDRangel
|
||||
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
|
||||
*
|
||||
* OpenAPI spec version: 7.0.0
|
||||
* Contact: f4exb06@gmail.com
|
||||
*
|
||||
* NOTE: This class is auto generated by the swagger code generator program.
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
#include "SWGDenoiserActions.h"
|
||||
|
||||
#include "SWGHelpers.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
|
||||
namespace SWGSDRangel {
|
||||
|
||||
SWGDenoiserActions::SWGDenoiserActions(QString* json) {
|
||||
init();
|
||||
this->fromJson(*json);
|
||||
}
|
||||
|
||||
SWGDenoiserActions::SWGDenoiserActions() {
|
||||
device_id = 0;
|
||||
m_device_id_isSet = false;
|
||||
channel_id = 0;
|
||||
m_channel_id_isSet = false;
|
||||
}
|
||||
|
||||
SWGDenoiserActions::~SWGDenoiserActions() {
|
||||
this->cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
SWGDenoiserActions::init() {
|
||||
device_id = 0;
|
||||
m_device_id_isSet = false;
|
||||
channel_id = 0;
|
||||
m_channel_id_isSet = false;
|
||||
}
|
||||
|
||||
void
|
||||
SWGDenoiserActions::cleanup() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
SWGDenoiserActions*
|
||||
SWGDenoiserActions::fromJson(QString &json) {
|
||||
QByteArray array (json.toStdString().c_str());
|
||||
QJsonDocument doc = QJsonDocument::fromJson(array);
|
||||
QJsonObject jsonObject = doc.object();
|
||||
this->fromJsonObject(jsonObject);
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
SWGDenoiserActions::fromJsonObject(QJsonObject &pJson) {
|
||||
::SWGSDRangel::setValue(&device_id, pJson["deviceId"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&channel_id, pJson["channelId"], "qint32", "");
|
||||
|
||||
}
|
||||
|
||||
QString
|
||||
SWGDenoiserActions::asJson ()
|
||||
{
|
||||
QJsonObject* obj = this->asJsonObject();
|
||||
|
||||
QJsonDocument doc(*obj);
|
||||
QByteArray bytes = doc.toJson();
|
||||
delete obj;
|
||||
return QString(bytes);
|
||||
}
|
||||
|
||||
QJsonObject*
|
||||
SWGDenoiserActions::asJsonObject() {
|
||||
QJsonObject* obj = new QJsonObject();
|
||||
if(m_device_id_isSet){
|
||||
obj->insert("deviceId", QJsonValue(device_id));
|
||||
}
|
||||
if(m_channel_id_isSet){
|
||||
obj->insert("channelId", QJsonValue(channel_id));
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGDenoiserActions::getDeviceId() {
|
||||
return device_id;
|
||||
}
|
||||
void
|
||||
SWGDenoiserActions::setDeviceId(qint32 device_id) {
|
||||
this->device_id = device_id;
|
||||
this->m_device_id_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGDenoiserActions::getChannelId() {
|
||||
return channel_id;
|
||||
}
|
||||
void
|
||||
SWGDenoiserActions::setChannelId(qint32 channel_id) {
|
||||
this->channel_id = channel_id;
|
||||
this->m_channel_id_isSet = true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SWGDenoiserActions::isSet(){
|
||||
bool isObjectUpdated = false;
|
||||
do{
|
||||
if(m_device_id_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_channel_id_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
}while(false);
|
||||
return isObjectUpdated;
|
||||
}
|
||||
}
|
||||
|
||||
64
swagger/sdrangel/code/qt5/client/SWGDenoiserActions.h
Normal file
64
swagger/sdrangel/code/qt5/client/SWGDenoiserActions.h
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* SDRangel
|
||||
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
|
||||
*
|
||||
* OpenAPI spec version: 7.0.0
|
||||
* Contact: f4exb06@gmail.com
|
||||
*
|
||||
* NOTE: This class is auto generated by the swagger code generator program.
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SWGDenoiserActions.h
|
||||
*
|
||||
* Denoiser actions
|
||||
*/
|
||||
|
||||
#ifndef SWGDenoiserActions_H_
|
||||
#define SWGDenoiserActions_H_
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
|
||||
|
||||
#include "SWGObject.h"
|
||||
#include "export.h"
|
||||
|
||||
namespace SWGSDRangel {
|
||||
|
||||
class SWG_API SWGDenoiserActions: public SWGObject {
|
||||
public:
|
||||
SWGDenoiserActions();
|
||||
SWGDenoiserActions(QString* json);
|
||||
virtual ~SWGDenoiserActions();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
virtual QString asJson () override;
|
||||
virtual QJsonObject* asJsonObject() override;
|
||||
virtual void fromJsonObject(QJsonObject &json) override;
|
||||
virtual SWGDenoiserActions* fromJson(QString &jsonString) override;
|
||||
|
||||
qint32 getDeviceId();
|
||||
void setDeviceId(qint32 device_id);
|
||||
|
||||
qint32 getChannelId();
|
||||
void setChannelId(qint32 channel_id);
|
||||
|
||||
|
||||
virtual bool isSet() override;
|
||||
|
||||
private:
|
||||
qint32 device_id;
|
||||
bool m_device_id_isSet;
|
||||
|
||||
qint32 channel_id;
|
||||
bool m_channel_id_isSet;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SWGDenoiserActions_H_ */
|
||||
440
swagger/sdrangel/code/qt5/client/SWGDenoiserSettings.cpp
Normal file
440
swagger/sdrangel/code/qt5/client/SWGDenoiserSettings.cpp
Normal file
@ -0,0 +1,440 @@
|
||||
/**
|
||||
* SDRangel
|
||||
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
|
||||
*
|
||||
* OpenAPI spec version: 7.0.0
|
||||
* Contact: f4exb06@gmail.com
|
||||
*
|
||||
* NOTE: This class is auto generated by the swagger code generator program.
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
#include "SWGDenoiserSettings.h"
|
||||
|
||||
#include "SWGHelpers.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
|
||||
namespace SWGSDRangel {
|
||||
|
||||
SWGDenoiserSettings::SWGDenoiserSettings(QString* json) {
|
||||
init();
|
||||
this->fromJson(*json);
|
||||
}
|
||||
|
||||
SWGDenoiserSettings::SWGDenoiserSettings() {
|
||||
denoiser_type = 0;
|
||||
m_denoiser_type_isSet = false;
|
||||
enable_denoiser = 0;
|
||||
m_enable_denoiser_isSet = false;
|
||||
volume_tenths = 0;
|
||||
m_volume_tenths_isSet = false;
|
||||
audio_device_name = nullptr;
|
||||
m_audio_device_name_isSet = false;
|
||||
audio_mute = 0;
|
||||
m_audio_mute_isSet = false;
|
||||
title = nullptr;
|
||||
m_title_isSet = false;
|
||||
rgb_color = 0;
|
||||
m_rgb_color_isSet = false;
|
||||
file_record_name = nullptr;
|
||||
m_file_record_name_isSet = false;
|
||||
record_to_file = 0;
|
||||
m_record_to_file_isSet = false;
|
||||
use_reverse_api = 0;
|
||||
m_use_reverse_api_isSet = false;
|
||||
reverse_api_address = nullptr;
|
||||
m_reverse_api_address_isSet = false;
|
||||
reverse_api_port = 0;
|
||||
m_reverse_api_port_isSet = false;
|
||||
reverse_api_feature_set_index = 0;
|
||||
m_reverse_api_feature_set_index_isSet = false;
|
||||
reverse_api_feature_index = 0;
|
||||
m_reverse_api_feature_index_isSet = false;
|
||||
rollup_state = nullptr;
|
||||
m_rollup_state_isSet = false;
|
||||
}
|
||||
|
||||
SWGDenoiserSettings::~SWGDenoiserSettings() {
|
||||
this->cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
SWGDenoiserSettings::init() {
|
||||
denoiser_type = 0;
|
||||
m_denoiser_type_isSet = false;
|
||||
enable_denoiser = 0;
|
||||
m_enable_denoiser_isSet = false;
|
||||
volume_tenths = 0;
|
||||
m_volume_tenths_isSet = false;
|
||||
audio_device_name = new QString("");
|
||||
m_audio_device_name_isSet = false;
|
||||
audio_mute = 0;
|
||||
m_audio_mute_isSet = false;
|
||||
title = new QString("");
|
||||
m_title_isSet = false;
|
||||
rgb_color = 0;
|
||||
m_rgb_color_isSet = false;
|
||||
file_record_name = new QString("");
|
||||
m_file_record_name_isSet = false;
|
||||
record_to_file = 0;
|
||||
m_record_to_file_isSet = false;
|
||||
use_reverse_api = 0;
|
||||
m_use_reverse_api_isSet = false;
|
||||
reverse_api_address = new QString("");
|
||||
m_reverse_api_address_isSet = false;
|
||||
reverse_api_port = 0;
|
||||
m_reverse_api_port_isSet = false;
|
||||
reverse_api_feature_set_index = 0;
|
||||
m_reverse_api_feature_set_index_isSet = false;
|
||||
reverse_api_feature_index = 0;
|
||||
m_reverse_api_feature_index_isSet = false;
|
||||
rollup_state = new SWGRollupState();
|
||||
m_rollup_state_isSet = false;
|
||||
}
|
||||
|
||||
void
|
||||
SWGDenoiserSettings::cleanup() {
|
||||
|
||||
|
||||
|
||||
if(audio_device_name != nullptr) {
|
||||
delete audio_device_name;
|
||||
}
|
||||
|
||||
if(title != nullptr) {
|
||||
delete title;
|
||||
}
|
||||
|
||||
if(file_record_name != nullptr) {
|
||||
delete file_record_name;
|
||||
}
|
||||
|
||||
|
||||
if(reverse_api_address != nullptr) {
|
||||
delete reverse_api_address;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(rollup_state != nullptr) {
|
||||
delete rollup_state;
|
||||
}
|
||||
}
|
||||
|
||||
SWGDenoiserSettings*
|
||||
SWGDenoiserSettings::fromJson(QString &json) {
|
||||
QByteArray array (json.toStdString().c_str());
|
||||
QJsonDocument doc = QJsonDocument::fromJson(array);
|
||||
QJsonObject jsonObject = doc.object();
|
||||
this->fromJsonObject(jsonObject);
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
SWGDenoiserSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
::SWGSDRangel::setValue(&denoiser_type, pJson["denoiserType"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&enable_denoiser, pJson["enableDenoiser"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&volume_tenths, pJson["volumeTenths"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&audio_device_name, pJson["audioDeviceName"], "QString", "QString");
|
||||
|
||||
::SWGSDRangel::setValue(&audio_mute, pJson["audioMute"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
|
||||
|
||||
::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&file_record_name, pJson["fileRecordName"], "QString", "QString");
|
||||
|
||||
::SWGSDRangel::setValue(&record_to_file, pJson["recordToFile"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString");
|
||||
|
||||
::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&reverse_api_feature_set_index, pJson["reverseAPIFeatureSetIndex"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&reverse_api_feature_index, pJson["reverseAPIFeatureIndex"], "qint32", "");
|
||||
|
||||
::SWGSDRangel::setValue(&rollup_state, pJson["rollupState"], "SWGRollupState", "SWGRollupState");
|
||||
|
||||
}
|
||||
|
||||
QString
|
||||
SWGDenoiserSettings::asJson ()
|
||||
{
|
||||
QJsonObject* obj = this->asJsonObject();
|
||||
|
||||
QJsonDocument doc(*obj);
|
||||
QByteArray bytes = doc.toJson();
|
||||
delete obj;
|
||||
return QString(bytes);
|
||||
}
|
||||
|
||||
QJsonObject*
|
||||
SWGDenoiserSettings::asJsonObject() {
|
||||
QJsonObject* obj = new QJsonObject();
|
||||
if(m_denoiser_type_isSet){
|
||||
obj->insert("denoiserType", QJsonValue(denoiser_type));
|
||||
}
|
||||
if(m_enable_denoiser_isSet){
|
||||
obj->insert("enableDenoiser", QJsonValue(enable_denoiser));
|
||||
}
|
||||
if(m_volume_tenths_isSet){
|
||||
obj->insert("volumeTenths", QJsonValue(volume_tenths));
|
||||
}
|
||||
if(audio_device_name != nullptr && *audio_device_name != QString("")){
|
||||
toJsonValue(QString("audioDeviceName"), audio_device_name, obj, QString("QString"));
|
||||
}
|
||||
if(m_audio_mute_isSet){
|
||||
obj->insert("audioMute", QJsonValue(audio_mute));
|
||||
}
|
||||
if(title != nullptr && *title != QString("")){
|
||||
toJsonValue(QString("title"), title, obj, QString("QString"));
|
||||
}
|
||||
if(m_rgb_color_isSet){
|
||||
obj->insert("rgbColor", QJsonValue(rgb_color));
|
||||
}
|
||||
if(file_record_name != nullptr && *file_record_name != QString("")){
|
||||
toJsonValue(QString("fileRecordName"), file_record_name, obj, QString("QString"));
|
||||
}
|
||||
if(m_record_to_file_isSet){
|
||||
obj->insert("recordToFile", QJsonValue(record_to_file));
|
||||
}
|
||||
if(m_use_reverse_api_isSet){
|
||||
obj->insert("useReverseAPI", QJsonValue(use_reverse_api));
|
||||
}
|
||||
if(reverse_api_address != nullptr && *reverse_api_address != QString("")){
|
||||
toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString"));
|
||||
}
|
||||
if(m_reverse_api_port_isSet){
|
||||
obj->insert("reverseAPIPort", QJsonValue(reverse_api_port));
|
||||
}
|
||||
if(m_reverse_api_feature_set_index_isSet){
|
||||
obj->insert("reverseAPIFeatureSetIndex", QJsonValue(reverse_api_feature_set_index));
|
||||
}
|
||||
if(m_reverse_api_feature_index_isSet){
|
||||
obj->insert("reverseAPIFeatureIndex", QJsonValue(reverse_api_feature_index));
|
||||
}
|
||||
if((rollup_state != nullptr) && (rollup_state->isSet())){
|
||||
toJsonValue(QString("rollupState"), rollup_state, obj, QString("SWGRollupState"));
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGDenoiserSettings::getDenoiserType() {
|
||||
return denoiser_type;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setDenoiserType(qint32 denoiser_type) {
|
||||
this->denoiser_type = denoiser_type;
|
||||
this->m_denoiser_type_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGDenoiserSettings::getEnableDenoiser() {
|
||||
return enable_denoiser;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setEnableDenoiser(qint32 enable_denoiser) {
|
||||
this->enable_denoiser = enable_denoiser;
|
||||
this->m_enable_denoiser_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGDenoiserSettings::getVolumeTenths() {
|
||||
return volume_tenths;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setVolumeTenths(qint32 volume_tenths) {
|
||||
this->volume_tenths = volume_tenths;
|
||||
this->m_volume_tenths_isSet = true;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGDenoiserSettings::getAudioDeviceName() {
|
||||
return audio_device_name;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setAudioDeviceName(QString* audio_device_name) {
|
||||
this->audio_device_name = audio_device_name;
|
||||
this->m_audio_device_name_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGDenoiserSettings::getAudioMute() {
|
||||
return audio_mute;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setAudioMute(qint32 audio_mute) {
|
||||
this->audio_mute = audio_mute;
|
||||
this->m_audio_mute_isSet = true;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGDenoiserSettings::getTitle() {
|
||||
return title;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setTitle(QString* title) {
|
||||
this->title = title;
|
||||
this->m_title_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGDenoiserSettings::getRgbColor() {
|
||||
return rgb_color;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setRgbColor(qint32 rgb_color) {
|
||||
this->rgb_color = rgb_color;
|
||||
this->m_rgb_color_isSet = true;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGDenoiserSettings::getFileRecordName() {
|
||||
return file_record_name;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setFileRecordName(QString* file_record_name) {
|
||||
this->file_record_name = file_record_name;
|
||||
this->m_file_record_name_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGDenoiserSettings::getRecordToFile() {
|
||||
return record_to_file;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setRecordToFile(qint32 record_to_file) {
|
||||
this->record_to_file = record_to_file;
|
||||
this->m_record_to_file_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGDenoiserSettings::getUseReverseApi() {
|
||||
return use_reverse_api;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setUseReverseApi(qint32 use_reverse_api) {
|
||||
this->use_reverse_api = use_reverse_api;
|
||||
this->m_use_reverse_api_isSet = true;
|
||||
}
|
||||
|
||||
QString*
|
||||
SWGDenoiserSettings::getReverseApiAddress() {
|
||||
return reverse_api_address;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setReverseApiAddress(QString* reverse_api_address) {
|
||||
this->reverse_api_address = reverse_api_address;
|
||||
this->m_reverse_api_address_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGDenoiserSettings::getReverseApiPort() {
|
||||
return reverse_api_port;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setReverseApiPort(qint32 reverse_api_port) {
|
||||
this->reverse_api_port = reverse_api_port;
|
||||
this->m_reverse_api_port_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGDenoiserSettings::getReverseApiFeatureSetIndex() {
|
||||
return reverse_api_feature_set_index;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setReverseApiFeatureSetIndex(qint32 reverse_api_feature_set_index) {
|
||||
this->reverse_api_feature_set_index = reverse_api_feature_set_index;
|
||||
this->m_reverse_api_feature_set_index_isSet = true;
|
||||
}
|
||||
|
||||
qint32
|
||||
SWGDenoiserSettings::getReverseApiFeatureIndex() {
|
||||
return reverse_api_feature_index;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setReverseApiFeatureIndex(qint32 reverse_api_feature_index) {
|
||||
this->reverse_api_feature_index = reverse_api_feature_index;
|
||||
this->m_reverse_api_feature_index_isSet = true;
|
||||
}
|
||||
|
||||
SWGRollupState*
|
||||
SWGDenoiserSettings::getRollupState() {
|
||||
return rollup_state;
|
||||
}
|
||||
void
|
||||
SWGDenoiserSettings::setRollupState(SWGRollupState* rollup_state) {
|
||||
this->rollup_state = rollup_state;
|
||||
this->m_rollup_state_isSet = true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SWGDenoiserSettings::isSet(){
|
||||
bool isObjectUpdated = false;
|
||||
do{
|
||||
if(m_denoiser_type_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_enable_denoiser_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_volume_tenths_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(audio_device_name && *audio_device_name != QString("")){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_audio_mute_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(title && *title != QString("")){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_rgb_color_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(file_record_name && *file_record_name != QString("")){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_record_to_file_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_use_reverse_api_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(reverse_api_address && *reverse_api_address != QString("")){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_reverse_api_port_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_reverse_api_feature_set_index_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(m_reverse_api_feature_index_isSet){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(rollup_state && rollup_state->isSet()){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
}while(false);
|
||||
return isObjectUpdated;
|
||||
}
|
||||
}
|
||||
|
||||
144
swagger/sdrangel/code/qt5/client/SWGDenoiserSettings.h
Normal file
144
swagger/sdrangel/code/qt5/client/SWGDenoiserSettings.h
Normal file
@ -0,0 +1,144 @@
|
||||
/**
|
||||
* SDRangel
|
||||
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
|
||||
*
|
||||
* OpenAPI spec version: 7.0.0
|
||||
* Contact: f4exb06@gmail.com
|
||||
*
|
||||
* NOTE: This class is auto generated by the swagger code generator program.
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SWGDenoiserSettings.h
|
||||
*
|
||||
* Denoiser
|
||||
*/
|
||||
|
||||
#ifndef SWGDenoiserSettings_H_
|
||||
#define SWGDenoiserSettings_H_
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
|
||||
#include "SWGRollupState.h"
|
||||
#include <QString>
|
||||
|
||||
#include "SWGObject.h"
|
||||
#include "export.h"
|
||||
|
||||
namespace SWGSDRangel {
|
||||
|
||||
class SWG_API SWGDenoiserSettings: public SWGObject {
|
||||
public:
|
||||
SWGDenoiserSettings();
|
||||
SWGDenoiserSettings(QString* json);
|
||||
virtual ~SWGDenoiserSettings();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
virtual QString asJson () override;
|
||||
virtual QJsonObject* asJsonObject() override;
|
||||
virtual void fromJsonObject(QJsonObject &json) override;
|
||||
virtual SWGDenoiserSettings* fromJson(QString &jsonString) override;
|
||||
|
||||
qint32 getDenoiserType();
|
||||
void setDenoiserType(qint32 denoiser_type);
|
||||
|
||||
qint32 getEnableDenoiser();
|
||||
void setEnableDenoiser(qint32 enable_denoiser);
|
||||
|
||||
qint32 getVolumeTenths();
|
||||
void setVolumeTenths(qint32 volume_tenths);
|
||||
|
||||
QString* getAudioDeviceName();
|
||||
void setAudioDeviceName(QString* audio_device_name);
|
||||
|
||||
qint32 getAudioMute();
|
||||
void setAudioMute(qint32 audio_mute);
|
||||
|
||||
QString* getTitle();
|
||||
void setTitle(QString* title);
|
||||
|
||||
qint32 getRgbColor();
|
||||
void setRgbColor(qint32 rgb_color);
|
||||
|
||||
QString* getFileRecordName();
|
||||
void setFileRecordName(QString* file_record_name);
|
||||
|
||||
qint32 getRecordToFile();
|
||||
void setRecordToFile(qint32 record_to_file);
|
||||
|
||||
qint32 getUseReverseApi();
|
||||
void setUseReverseApi(qint32 use_reverse_api);
|
||||
|
||||
QString* getReverseApiAddress();
|
||||
void setReverseApiAddress(QString* reverse_api_address);
|
||||
|
||||
qint32 getReverseApiPort();
|
||||
void setReverseApiPort(qint32 reverse_api_port);
|
||||
|
||||
qint32 getReverseApiFeatureSetIndex();
|
||||
void setReverseApiFeatureSetIndex(qint32 reverse_api_feature_set_index);
|
||||
|
||||
qint32 getReverseApiFeatureIndex();
|
||||
void setReverseApiFeatureIndex(qint32 reverse_api_feature_index);
|
||||
|
||||
SWGRollupState* getRollupState();
|
||||
void setRollupState(SWGRollupState* rollup_state);
|
||||
|
||||
|
||||
virtual bool isSet() override;
|
||||
|
||||
private:
|
||||
qint32 denoiser_type;
|
||||
bool m_denoiser_type_isSet;
|
||||
|
||||
qint32 enable_denoiser;
|
||||
bool m_enable_denoiser_isSet;
|
||||
|
||||
qint32 volume_tenths;
|
||||
bool m_volume_tenths_isSet;
|
||||
|
||||
QString* audio_device_name;
|
||||
bool m_audio_device_name_isSet;
|
||||
|
||||
qint32 audio_mute;
|
||||
bool m_audio_mute_isSet;
|
||||
|
||||
QString* title;
|
||||
bool m_title_isSet;
|
||||
|
||||
qint32 rgb_color;
|
||||
bool m_rgb_color_isSet;
|
||||
|
||||
QString* file_record_name;
|
||||
bool m_file_record_name_isSet;
|
||||
|
||||
qint32 record_to_file;
|
||||
bool m_record_to_file_isSet;
|
||||
|
||||
qint32 use_reverse_api;
|
||||
bool m_use_reverse_api_isSet;
|
||||
|
||||
QString* reverse_api_address;
|
||||
bool m_reverse_api_address_isSet;
|
||||
|
||||
qint32 reverse_api_port;
|
||||
bool m_reverse_api_port_isSet;
|
||||
|
||||
qint32 reverse_api_feature_set_index;
|
||||
bool m_reverse_api_feature_set_index_isSet;
|
||||
|
||||
qint32 reverse_api_feature_index;
|
||||
bool m_reverse_api_feature_index_isSet;
|
||||
|
||||
SWGRollupState* rollup_state;
|
||||
bool m_rollup_state_isSet;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SWGDenoiserSettings_H_ */
|
||||
@ -62,6 +62,8 @@ SWGFeatureActions::SWGFeatureActions() {
|
||||
m_vor_localizer_actions_isSet = false;
|
||||
demod_analyzer_actions = nullptr;
|
||||
m_demod_analyzer_actions_isSet = false;
|
||||
denoiser_actions = nullptr;
|
||||
m_denoiser_actions_isSet = false;
|
||||
}
|
||||
|
||||
SWGFeatureActions::~SWGFeatureActions() {
|
||||
@ -104,6 +106,8 @@ SWGFeatureActions::init() {
|
||||
m_vor_localizer_actions_isSet = false;
|
||||
demod_analyzer_actions = new SWGDemodAnalyzerActions();
|
||||
m_demod_analyzer_actions_isSet = false;
|
||||
denoiser_actions = new SWGDenoiserActions();
|
||||
m_denoiser_actions_isSet = false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -155,6 +159,9 @@ SWGFeatureActions::cleanup() {
|
||||
if(demod_analyzer_actions != nullptr) {
|
||||
delete demod_analyzer_actions;
|
||||
}
|
||||
if(denoiser_actions != nullptr) {
|
||||
delete denoiser_actions;
|
||||
}
|
||||
}
|
||||
|
||||
SWGFeatureActions*
|
||||
@ -202,6 +209,8 @@ SWGFeatureActions::fromJsonObject(QJsonObject &pJson) {
|
||||
|
||||
::SWGSDRangel::setValue(&demod_analyzer_actions, pJson["DemodAnalyzerActions"], "SWGDemodAnalyzerActions", "SWGDemodAnalyzerActions");
|
||||
|
||||
::SWGSDRangel::setValue(&denoiser_actions, pJson["DenoiserActions"], "SWGDenoiserActions", "SWGDenoiserActions");
|
||||
|
||||
}
|
||||
|
||||
QString
|
||||
@ -269,6 +278,9 @@ SWGFeatureActions::asJsonObject() {
|
||||
if((demod_analyzer_actions != nullptr) && (demod_analyzer_actions->isSet())){
|
||||
toJsonValue(QString("DemodAnalyzerActions"), demod_analyzer_actions, obj, QString("SWGDemodAnalyzerActions"));
|
||||
}
|
||||
if((denoiser_actions != nullptr) && (denoiser_actions->isSet())){
|
||||
toJsonValue(QString("DenoiserActions"), denoiser_actions, obj, QString("SWGDenoiserActions"));
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
@ -443,6 +455,16 @@ SWGFeatureActions::setDemodAnalyzerActions(SWGDemodAnalyzerActions* demod_analyz
|
||||
this->m_demod_analyzer_actions_isSet = true;
|
||||
}
|
||||
|
||||
SWGDenoiserActions*
|
||||
SWGFeatureActions::getDenoiserActions() {
|
||||
return denoiser_actions;
|
||||
}
|
||||
void
|
||||
SWGFeatureActions::setDenoiserActions(SWGDenoiserActions* denoiser_actions) {
|
||||
this->denoiser_actions = denoiser_actions;
|
||||
this->m_denoiser_actions_isSet = true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SWGFeatureActions::isSet(){
|
||||
@ -499,6 +521,9 @@ SWGFeatureActions::isSet(){
|
||||
if(demod_analyzer_actions && demod_analyzer_actions->isSet()){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(denoiser_actions && denoiser_actions->isSet()){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
}while(false);
|
||||
return isObjectUpdated;
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "SWGAFCActions.h"
|
||||
#include "SWGAMBEActions.h"
|
||||
#include "SWGDemodAnalyzerActions.h"
|
||||
#include "SWGDenoiserActions.h"
|
||||
#include "SWGGS232ControllerActions.h"
|
||||
#include "SWGLimeRFEActions.h"
|
||||
#include "SWGMapActions.h"
|
||||
@ -107,6 +108,9 @@ public:
|
||||
SWGDemodAnalyzerActions* getDemodAnalyzerActions();
|
||||
void setDemodAnalyzerActions(SWGDemodAnalyzerActions* demod_analyzer_actions);
|
||||
|
||||
SWGDenoiserActions* getDenoiserActions();
|
||||
void setDenoiserActions(SWGDenoiserActions* denoiser_actions);
|
||||
|
||||
|
||||
virtual bool isSet() override;
|
||||
|
||||
@ -162,6 +166,9 @@ private:
|
||||
SWGDemodAnalyzerActions* demod_analyzer_actions;
|
||||
bool m_demod_analyzer_actions_isSet;
|
||||
|
||||
SWGDenoiserActions* denoiser_actions;
|
||||
bool m_denoiser_actions_isSet;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -46,6 +46,8 @@ SWGFeatureSettings::SWGFeatureSettings() {
|
||||
m_aprs_settings_isSet = false;
|
||||
demod_analyzer_settings = nullptr;
|
||||
m_demod_analyzer_settings_isSet = false;
|
||||
denoiser_settings = nullptr;
|
||||
m_denoiser_settings_isSet = false;
|
||||
jogdial_controller_settings = nullptr;
|
||||
m_jogdial_controller_settings_isSet = false;
|
||||
gs232_controller_settings = nullptr;
|
||||
@ -100,6 +102,8 @@ SWGFeatureSettings::init() {
|
||||
m_aprs_settings_isSet = false;
|
||||
demod_analyzer_settings = new SWGDemodAnalyzerSettings();
|
||||
m_demod_analyzer_settings_isSet = false;
|
||||
denoiser_settings = new SWGDenoiserSettings();
|
||||
m_denoiser_settings_isSet = false;
|
||||
jogdial_controller_settings = new SWGJogdialControllerSettings();
|
||||
m_jogdial_controller_settings_isSet = false;
|
||||
gs232_controller_settings = new SWGGS232ControllerSettings();
|
||||
@ -155,6 +159,9 @@ SWGFeatureSettings::cleanup() {
|
||||
if(demod_analyzer_settings != nullptr) {
|
||||
delete demod_analyzer_settings;
|
||||
}
|
||||
if(denoiser_settings != nullptr) {
|
||||
delete denoiser_settings;
|
||||
}
|
||||
if(jogdial_controller_settings != nullptr) {
|
||||
delete jogdial_controller_settings;
|
||||
}
|
||||
@ -228,6 +235,8 @@ SWGFeatureSettings::fromJsonObject(QJsonObject &pJson) {
|
||||
|
||||
::SWGSDRangel::setValue(&demod_analyzer_settings, pJson["DemodAnalyzerSettings"], "SWGDemodAnalyzerSettings", "SWGDemodAnalyzerSettings");
|
||||
|
||||
::SWGSDRangel::setValue(&denoiser_settings, pJson["DenoiserSettings"], "SWGDenoiserSettings", "SWGDenoiserSettings");
|
||||
|
||||
::SWGSDRangel::setValue(&jogdial_controller_settings, pJson["JogdialControllerSettings"], "SWGJogdialControllerSettings", "SWGJogdialControllerSettings");
|
||||
|
||||
::SWGSDRangel::setValue(&gs232_controller_settings, pJson["GS232ControllerSettings"], "SWGGS232ControllerSettings", "SWGGS232ControllerSettings");
|
||||
@ -299,6 +308,9 @@ SWGFeatureSettings::asJsonObject() {
|
||||
if((demod_analyzer_settings != nullptr) && (demod_analyzer_settings->isSet())){
|
||||
toJsonValue(QString("DemodAnalyzerSettings"), demod_analyzer_settings, obj, QString("SWGDemodAnalyzerSettings"));
|
||||
}
|
||||
if((denoiser_settings != nullptr) && (denoiser_settings->isSet())){
|
||||
toJsonValue(QString("DenoiserSettings"), denoiser_settings, obj, QString("SWGDenoiserSettings"));
|
||||
}
|
||||
if((jogdial_controller_settings != nullptr) && (jogdial_controller_settings->isSet())){
|
||||
toJsonValue(QString("JogdialControllerSettings"), jogdial_controller_settings, obj, QString("SWGJogdialControllerSettings"));
|
||||
}
|
||||
@ -435,6 +447,16 @@ SWGFeatureSettings::setDemodAnalyzerSettings(SWGDemodAnalyzerSettings* demod_ana
|
||||
this->m_demod_analyzer_settings_isSet = true;
|
||||
}
|
||||
|
||||
SWGDenoiserSettings*
|
||||
SWGFeatureSettings::getDenoiserSettings() {
|
||||
return denoiser_settings;
|
||||
}
|
||||
void
|
||||
SWGFeatureSettings::setDenoiserSettings(SWGDenoiserSettings* denoiser_settings) {
|
||||
this->denoiser_settings = denoiser_settings;
|
||||
this->m_denoiser_settings_isSet = true;
|
||||
}
|
||||
|
||||
SWGJogdialControllerSettings*
|
||||
SWGFeatureSettings::getJogdialControllerSettings() {
|
||||
return jogdial_controller_settings;
|
||||
@ -607,6 +629,9 @@ SWGFeatureSettings::isSet(){
|
||||
if(demod_analyzer_settings && demod_analyzer_settings->isSet()){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(denoiser_settings && denoiser_settings->isSet()){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
if(jogdial_controller_settings && jogdial_controller_settings->isSet()){
|
||||
isObjectUpdated = true; break;
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "SWGAPRSSettings.h"
|
||||
#include "SWGAntennaToolsSettings.h"
|
||||
#include "SWGDemodAnalyzerSettings.h"
|
||||
#include "SWGDenoiserSettings.h"
|
||||
#include "SWGGS232ControllerSettings.h"
|
||||
#include "SWGJogdialControllerSettings.h"
|
||||
#include "SWGLimeRFESettings.h"
|
||||
@ -89,6 +90,9 @@ public:
|
||||
SWGDemodAnalyzerSettings* getDemodAnalyzerSettings();
|
||||
void setDemodAnalyzerSettings(SWGDemodAnalyzerSettings* demod_analyzer_settings);
|
||||
|
||||
SWGDenoiserSettings* getDenoiserSettings();
|
||||
void setDenoiserSettings(SWGDenoiserSettings* denoiser_settings);
|
||||
|
||||
SWGJogdialControllerSettings* getJogdialControllerSettings();
|
||||
void setJogdialControllerSettings(SWGJogdialControllerSettings* jogdial_controller_settings);
|
||||
|
||||
@ -162,6 +166,9 @@ private:
|
||||
SWGDemodAnalyzerSettings* demod_analyzer_settings;
|
||||
bool m_demod_analyzer_settings_isSet;
|
||||
|
||||
SWGDenoiserSettings* denoiser_settings;
|
||||
bool m_denoiser_settings_isSet;
|
||||
|
||||
SWGJogdialControllerSettings* jogdial_controller_settings;
|
||||
bool m_jogdial_controller_settings_isSet;
|
||||
|
||||
|
||||
@ -115,6 +115,8 @@
|
||||
#include "SWGDVSerialDevices.h"
|
||||
#include "SWGDemodAnalyzerActions.h"
|
||||
#include "SWGDemodAnalyzerSettings.h"
|
||||
#include "SWGDenoiserActions.h"
|
||||
#include "SWGDenoiserSettings.h"
|
||||
#include "SWGDeviceActions.h"
|
||||
#include "SWGDeviceConfig.h"
|
||||
#include "SWGDeviceListItem.h"
|
||||
@ -899,6 +901,16 @@ namespace SWGSDRangel {
|
||||
obj->init();
|
||||
return obj;
|
||||
}
|
||||
if(QString("SWGDenoiserActions").compare(type) == 0) {
|
||||
SWGDenoiserActions *obj = new SWGDenoiserActions();
|
||||
obj->init();
|
||||
return obj;
|
||||
}
|
||||
if(QString("SWGDenoiserSettings").compare(type) == 0) {
|
||||
SWGDenoiserSettings *obj = new SWGDenoiserSettings();
|
||||
obj->init();
|
||||
return obj;
|
||||
}
|
||||
if(QString("SWGDeviceActions").compare(type) == 0) {
|
||||
SWGDeviceActions *obj = new SWGDeviceActions();
|
||||
obj->init();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user