From 979928ded8172ea96a20d4b9e6a649bab7be64fe Mon Sep 17 00:00:00 2001 From: Ryzerth Date: Thu, 31 Dec 2020 14:26:12 +0100 Subject: [PATCH] Fixed resampling bug + added waterfall colormap selection + general bugfix --- core/src/core.cpp | 11 ++++ core/src/dsp/convertion.h | 50 ++++++++++++++++++ core/src/dsp/processing.h | 34 ++++++++++--- core/src/dsp/resampling.h | 81 +++++++++++++++++++++++++++++- core/src/gui/colormaps.cpp | 49 ++++++++++++++++++ core/src/gui/colormaps.h | 18 +++++++ core/src/gui/main_window.cpp | 23 +++++++++ core/src/gui/menus/display.cpp | 37 ++++++++++++++ core/src/gui/widgets/waterfall.cpp | 29 +++++++++-- core/src/gui/widgets/waterfall.h | 1 + file_source/src/main.cpp | 2 +- plutosdr_source/src/main.cpp | 2 +- radio/src/am_demod.h | 7 ++- radio/src/cw_demod.h | 5 +- radio/src/dsb_demod.h | 2 +- radio/src/lsb_demod.h | 8 ++- radio/src/usb_demod.h | 8 ++- recorder/src/main.cpp | 4 +- root/res/colormaps/classic.json | 19 +++++++ rtl_tcp_source/src/main.cpp | 2 +- rx888_source/src/main.cpp | 53 +++++++++++-------- 21 files changed, 399 insertions(+), 46 deletions(-) create mode 100644 core/src/gui/colormaps.cpp create mode 100644 core/src/gui/colormaps.h create mode 100644 root/res/colormaps/classic.json diff --git a/core/src/core.cpp b/core/src/core.cpp index 1c11f795..d32bee67 100644 --- a/core/src/core.cpp +++ b/core/src/core.cpp @@ -102,6 +102,7 @@ int sdrpp_main(int argc, char *argv[]) { defConfig["bandPlan"] = "General"; defConfig["bandPlanEnabled"] = true; defConfig["centerTuning"] = false; + defConfig["colorMap"] = "Classic"; defConfig["fftHeight"] = 300; defConfig["frequency"] = 100000000.0; defConfig["max"] = 0.0; @@ -156,6 +157,16 @@ int sdrpp_main(int argc, char *argv[]) { core::configManager.load(defConfig); core::configManager.enableAutoSave(); + // Fix config + core::configManager.aquire(); + for (auto const& item : defConfig.items()) { + if (!core::configManager.conf.contains(item.key())) { + spdlog::warn("Missing key in config {0}, repairing", item.key()); + core::configManager.conf[item.key()] = defConfig[item.key()]; + } + } + core::configManager.release(true); + // Setup window glfwSetErrorCallback(glfw_error_callback); if (!glfwInit()) { diff --git a/core/src/dsp/convertion.h b/core/src/dsp/convertion.h index 0ece083e..52c47496 100644 --- a/core/src/dsp/convertion.h +++ b/core/src/dsp/convertion.h @@ -132,4 +132,54 @@ namespace dsp { stream* _in; }; + + + class RealToComplex : public generic_block { + public: + RealToComplex() {} + + RealToComplex(stream* in) { init(in); } + + ~RealToComplex() { + delete[] nullBuffer; + generic_block::stop(); + } + + void init(stream* in) { + _in = in; + nullBuffer = new float[STREAM_BUFFER_SIZE]; + memset(nullBuffer, 0, STREAM_BUFFER_SIZE * sizeof(float)); + generic_block::registerInput(_in); + generic_block::registerOutput(&out); + } + + void setInput(stream* in) { + std::lock_guard lck(generic_block::ctrlMtx); + generic_block::tempStop(); + generic_block::unregisterInput(_in); + _in = in; + generic_block::registerInput(_in); + generic_block::tempStart(); + } + + int run() { + count = _in->read(); + if (count < 0) { return -1; } + + volk_32f_x2_interleave_32fc((lv_32fc_t*)out.writeBuf, _in->readBuf, nullBuffer, count); + + _in->flush(); + if (!out.swap(count)) { return -1; } + return count; + } + + stream out; + + private: + float avg; + int count; + float* nullBuffer; + stream* _in; + + }; } \ No newline at end of file diff --git a/core/src/dsp/processing.h b/core/src/dsp/processing.h index cef9c6c2..7226b3c1 100644 --- a/core/src/dsp/processing.h +++ b/core/src/dsp/processing.h @@ -1,6 +1,5 @@ #pragma once #include -#include #include #include #include @@ -89,13 +88,15 @@ namespace dsp { public: AGC() {} - AGC(stream* in, float ratio) { init(in, ratio); } + AGC(stream* in, float fallRate, float sampleRate) { init(in, fallRate, sampleRate); } ~AGC() { generic_block::stop(); } - void init(stream* in, float ratio) { + void init(stream* in, float fallRate, float sampleRate) { _in = in; - _ratio = ratio; + _sampleRate = sampleRate; + _fallRate = fallRate; + _CorrectedFallRate = _fallRate / _sampleRate; generic_block::registerInput(_in); generic_block::registerOutput(&out); } @@ -109,15 +110,30 @@ namespace dsp { generic_block::tempStart(); } + void setSampleRate(float sampleRate) { + std::lock_guard lck(generic_block::ctrlMtx); + _sampleRate = sampleRate; + _CorrectedFallRate = _fallRate / _sampleRate; + } + + void setFallRate(float fallRate) { + std::lock_guard lck(generic_block::ctrlMtx); + _fallRate = fallRate; + _CorrectedFallRate = _fallRate / _sampleRate; + } + int run() { count = _in->read(); if (count < 0) { return -1; } + level = pow(10, ((10.0f * log10f(level)) - (_CorrectedFallRate * count)) / 10.0f); + for (int i = 0; i < count; i++) { - level = (fabsf(_in->readBuf[i]) * _ratio) + (level * (1.0f - _ratio)); - out.writeBuf[i] = _in->readBuf[i] / level; + if (_in->readBuf[i] > level) { level = _in->readBuf[i]; } } + volk_32f_s32f_multiply_32f(out.writeBuf, _in->readBuf, 1.0f / level, count); + _in->flush(); if (!out.swap(count)) { return -1; } return count; @@ -127,8 +143,10 @@ namespace dsp { private: int count; - float level = 1.0f; - float _ratio; + float level = 0.0f; + float _fallRate; + float _CorrectedFallRate; + float _sampleRate; stream* _in; }; diff --git a/core/src/dsp/resampling.h b/core/src/dsp/resampling.h index 9a65b6e6..cb801292 100644 --- a/core/src/dsp/resampling.h +++ b/core/src/dsp/resampling.h @@ -109,6 +109,7 @@ namespace dsp { // Write to output int outIndex = 0; + int _interp_m_1 = _interp - 1; if constexpr (std::is_same_v) { for (int i = 0; outIndex < outCount; i += _decim) { int phase = i % _interp; @@ -155,10 +156,10 @@ namespace dsp { for(int tap = 0; tap < tapsPerPhase; tap++) { for (int phase = 0; phase < phases; phase++) { if(currentTap < tapCount) { - tapPhases[phase][tap] = taps[currentTap++]; + tapPhases[(_interp - 1) - phase][tap] = taps[currentTap++]; } else{ - tapPhases[phase][tap] = 0; + tapPhases[(_interp - 1) - phase][tap] = 0; } } } @@ -187,4 +188,80 @@ namespace dsp { std::vector tapPhases; }; + + class PowerDecimator : public generic_block { + public: + PowerDecimator() {} + + PowerDecimator(stream* in, unsigned int power) { init(in, power); } + + ~PowerDecimator() { + generic_block::stop(); + } + + void init(stream* in, unsigned int power) { + _in = in; + _power = power; + generic_block::registerInput(_in); + generic_block::registerOutput(&out); + } + + void setInput(stream* in) { + std::lock_guard lck(generic_block::ctrlMtx); + generic_block::tempStop(); + generic_block::unregisterInput(_in); + _in = in; + generic_block::registerInput(_in); + generic_block::tempStart(); + } + + void setPower(unsigned int power) { + std::lock_guard lck(generic_block::ctrlMtx); + generic_block::tempStop(); + generic_block::unregisterInput(_in); + _power = power; + generic_block::registerInput(_in); + generic_block::tempStart(); + } + + int run() { + count = _in->read(); + if (count < 0) { return -1; } + + if (_power == 0) { + memcpy(out.writeBuf, _in->readBuf, count * sizeof(complex_t)); + } + else if (_power == 1) { + for (int j = 0; j < count; j += 2) { + out.writeBuf[j / 2].i = (_in->readBuf[j].i + _in->readBuf[j + 1].i) * 0.5f; + out.writeBuf[j / 2].q = (_in->readBuf[j].q + _in->readBuf[j + 1].q) * 0.5f; + } + count /= 2; + } + + _in->flush(); + + if (_power > 1) { + for (int i = 1; i < _power; i++) { + for (int j = 0; j < count; j += 2) { + out.writeBuf[j / 2].i = (_in->readBuf[j].i + _in->readBuf[j + 1].i) * 0.5f; + out.writeBuf[j / 2].q = (_in->readBuf[j].q + _in->readBuf[j + 1].q) * 0.5f; + } + count /= 2; + } + } + + if (!out.swap(count)) { return -1; } + return count; + } + + stream out; + + + private: + int count; + unsigned int _power = 0; + stream* _in; + + }; } \ No newline at end of file diff --git a/core/src/gui/colormaps.cpp b/core/src/gui/colormaps.cpp new file mode 100644 index 00000000..b1e00bcd --- /dev/null +++ b/core/src/gui/colormaps.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include + +using nlohmann::json; + +namespace colormaps { + std::map maps; + + void loadMap(std::string path) { + if (!std::filesystem::is_regular_file(path)) { + spdlog::error("Could not load {0}, file doesn't exist", path); + return; + } + + std::ifstream file(path.c_str()); + json data; + file >> data; + file.close(); + + Map map; + std::vector mapTxt; + + try { + map.name = data["name"]; + map.author = data["author"]; + mapTxt = data["map"].get>(); + } + catch (const std::exception&) { + spdlog::error("Could not load {0}", path); + return; + } + + map.entryCount = mapTxt.size(); + map.map = new float[mapTxt.size() * 3]; + int i = 0; + for(auto const& col : mapTxt) { + uint8_t r, g, b, a; + map.map[i * 3] = std::stoi(col.substr(1, 2), NULL, 16); + map.map[(i * 3) + 1] = std::stoi(col.substr(3, 2), NULL, 16); + map.map[(i * 3) + 2] = std::stoi(col.substr(5, 2), NULL, 16); + i++; + } + + maps[map.name] = map; + } +} \ No newline at end of file diff --git a/core/src/gui/colormaps.h b/core/src/gui/colormaps.h new file mode 100644 index 00000000..a2f2e51f --- /dev/null +++ b/core/src/gui/colormaps.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include +#include +#include + +namespace colormaps { + struct Map { + std::string name; + std::string author; + float* map; + int entryCount; + }; + + void loadMap(std::string path); + + SDRPP_EXPORT std::map maps; +} \ No newline at end of file diff --git a/core/src/gui/main_window.cpp b/core/src/gui/main_window.cpp index ada9929f..ca147e3d 100644 --- a/core/src/gui/main_window.cpp +++ b/core/src/gui/main_window.cpp @@ -31,6 +31,7 @@ #include #include #include +#include // const int FFTSizes[] = { // 65536, @@ -121,6 +122,7 @@ void windowInit() { core::configManager.aquire(); gui::menu.order = core::configManager.conf["menuOrder"].get>(); std::string modulesDir = core::configManager.conf["modulesDirectory"]; + std::string resourcesDir = core::configManager.conf["resourcesDirectory"]; core::configManager.release(); gui::menu.registerEntry("Source", sourecmenu::draw, NULL); @@ -181,6 +183,27 @@ void windowInit() { core::moduleManager.createInstance(name, module); } + // Load color maps + LoadingScreen::show("Loading color maps"); + spdlog::info("Loading color maps"); + if (std::filesystem::is_directory(resourcesDir + "/colormaps")) { + for (const auto & file : std::filesystem::directory_iterator(resourcesDir + "/colormaps")) { + std::string path = file.path().generic_string(); + LoadingScreen::show("Loading " + path); + spdlog::info("Loading {0}", path); + if (file.path().extension().generic_string() != ".json") { + continue; + } + if (!file.is_regular_file()) { continue; } + colormaps::loadMap(path); + } + } + else { + spdlog::warn("Color map directory {0} does not exist, not loading modules from directory", modulesDir); + } + + gui::waterfall.updatePalletteFromArray(colormaps::maps["Turbo"].map, colormaps::maps["Turbo"].entryCount); + sourecmenu::init(); sinkmenu::init(); scriptingmenu::init(); diff --git a/core/src/gui/menus/display.cpp b/core/src/gui/menus/display.cpp index cb1c9105..a0e3b8e7 100644 --- a/core/src/gui/menus/display.cpp +++ b/core/src/gui/menus/display.cpp @@ -2,21 +2,58 @@ #include #include #include +#include +#include namespace displaymenu { bool showWaterfall; + int colorMapId = 0; + std::vector colorMapNames; + std::string colorMapNamesTxt = ""; + std::string colorMapAuthor = ""; void init() { showWaterfall = core::configManager.conf["showWaterfall"]; showWaterfall ? gui::waterfall.showWaterfall() : gui::waterfall.hideWaterfall(); + std::string colormapName = core::configManager.conf["colorMap"]; + if (colormaps::maps.find(colormapName) != colormaps::maps.end()) { + colormaps::Map map = colormaps::maps[colormapName]; + gui::waterfall.updatePalletteFromArray(map.map, map.entryCount); + } + + for (auto const& [name, map] : colormaps::maps) { + colorMapNames.push_back(name); + colorMapNamesTxt += name; + colorMapNamesTxt += '\0'; + if (name == colormapName) { + colorMapId = (colorMapNames.size() - 1); + colorMapAuthor = map.author; + } + } } void draw(void* ctx) { + float menuWidth = ImGui::GetContentRegionAvailWidth(); if (ImGui::Checkbox("Show Waterfall", &showWaterfall)) { showWaterfall ? gui::waterfall.showWaterfall() : gui::waterfall.hideWaterfall(); core::configManager.aquire(); core::configManager.conf["showWaterfall"] = showWaterfall; core::configManager.release(true); } + + if (colorMapNames.size() > 0) { + ImGui::Text("Color Map"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); + if (ImGui::Combo("##_sdrpp_color_map_sel", &colorMapId, colorMapNamesTxt.c_str())) { + colormaps::Map map = colormaps::maps[colorMapNames[colorMapId]]; + gui::waterfall.updatePalletteFromArray(map.map, map.entryCount); + core::configManager.aquire(); + core::configManager.conf["colorMap"] = colorMapNames[colorMapId]; + core::configManager.release(true); + colorMapAuthor = map.author; + } + ImGui::Text("Color map Author: %s", colorMapAuthor.c_str()); + } } } \ No newline at end of file diff --git a/core/src/gui/widgets/waterfall.cpp b/core/src/gui/widgets/waterfall.cpp index 025f009a..dc23a1cd 100644 --- a/core/src/gui/widgets/waterfall.cpp +++ b/core/src/gui/widgets/waterfall.cpp @@ -7,7 +7,7 @@ #include -float COLOR_MAP[][3] = { +float DEFAULT_COLOR_MAP[][3] = { {0x00, 0x00, 0x20}, {0x00, 0x00, 0x30}, {0x00, 0x00, 0x50}, @@ -106,7 +106,7 @@ namespace ImGui { viewBandwidth = 1.0; wholeBandwidth = 1.0; - updatePallette(COLOR_MAP, 13); + updatePallette(DEFAULT_COLOR_MAP, 13); } void WaterFall::init() { @@ -568,6 +568,7 @@ namespace ImGui { } void WaterFall::updatePallette(float colors[][3], int colorCount) { + std::lock_guard lck(buf_mtx); for (int i = 0; i < WATERFALL_RESOLUTION; i++) { int lowerId = floorf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount); int upperId = ceilf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount); @@ -579,6 +580,23 @@ namespace ImGui { float b = (colors[lowerId][2] * (1.0 - ratio)) + (colors[upperId][2] * (ratio)); waterfallPallet[i] = ((uint32_t)255 << 24) | ((uint32_t)b << 16) | ((uint32_t)g << 8) | (uint32_t)r; } + updateWaterfallFb(); + } + + void WaterFall::updatePalletteFromArray(float* colors, int colorCount) { + std::lock_guard lck(buf_mtx); + for (int i = 0; i < WATERFALL_RESOLUTION; i++) { + int lowerId = floorf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount); + int upperId = ceilf(((float)i / (float)WATERFALL_RESOLUTION) * colorCount); + lowerId = std::clamp(lowerId, 0, colorCount - 1); + upperId = std::clamp(upperId, 0, colorCount - 1); + float ratio = (((float)i / (float)WATERFALL_RESOLUTION) * colorCount) - lowerId; + float r = (colors[(lowerId * 3) + 0] * (1.0 - ratio)) + (colors[(upperId * 3) + 0] * (ratio)); + float g = (colors[(lowerId * 3) + 1] * (1.0 - ratio)) + (colors[(upperId * 3) + 1] * (ratio)); + float b = (colors[(lowerId * 3) + 2] * (1.0 - ratio)) + (colors[(upperId * 3) + 2] * (ratio)); + waterfallPallet[i] = ((uint32_t)255 << 24) | ((uint32_t)b << 16) | ((uint32_t)g << 8) | (uint32_t)r; + } + updateWaterfallFb(); } void WaterFall::autoRange() { @@ -627,6 +645,7 @@ namespace ImGui { } void WaterFall::setViewBandwidth(double bandWidth) { + std::lock_guard lck(buf_mtx); if (bandWidth == viewBandwidth) { return; } @@ -651,6 +670,7 @@ namespace ImGui { } void WaterFall::setViewOffset(double offset) { + std::lock_guard lck(buf_mtx); if (offset == viewOffset) { return; } @@ -690,6 +710,7 @@ namespace ImGui { } void WaterFall::setWaterfallMin(float min) { + std::lock_guard lck(buf_mtx); if (min == waterfallMin) { return; } @@ -702,6 +723,7 @@ namespace ImGui { } void WaterFall::setWaterfallMax(float max) { + std::lock_guard lck(buf_mtx); if (max == waterfallMax) { return; } @@ -720,7 +742,7 @@ namespace ImGui { } void WaterFall::setRawFFTSize(int size, bool lock) { - if (lock) { buf_mtx.lock(); } + std::lock_guard lck(buf_mtx); rawFFTSize = size; if (rawFFTs != NULL) { rawFFTs = (float*)realloc(rawFFTs, rawFFTSize * waterfallHeight * sizeof(float)); @@ -729,7 +751,6 @@ namespace ImGui { rawFFTs = (float*)malloc(rawFFTSize * waterfallHeight * sizeof(float)); } memset(rawFFTs, 0, rawFFTSize * waterfallHeight * sizeof(float)); - if (lock) { buf_mtx.unlock(); } } void WaterfallVFO::setOffset(double offset) { diff --git a/core/src/gui/widgets/waterfall.h b/core/src/gui/widgets/waterfall.h index 08edbf23..0d08cbd9 100644 --- a/core/src/gui/widgets/waterfall.h +++ b/core/src/gui/widgets/waterfall.h @@ -57,6 +57,7 @@ namespace ImGui { void pushFFT(); void updatePallette(float colors[][3], int colorCount); + void updatePalletteFromArray(float* colors, int colorCount); void setCenterFrequency(double freq); double getCenterFrequency(); diff --git a/file_source/src/main.cpp b/file_source/src/main.cpp index bda7fa18..ad7d8799 100644 --- a/file_source/src/main.cpp +++ b/file_source/src/main.cpp @@ -80,7 +80,7 @@ private: static void worker(void* ctx) { FileSourceModule* _this = (FileSourceModule*)ctx; double sampleRate = _this->reader->getSampleRate(); - int blockSize = sampleRate / 200.0; + int blockSize = sampleRate / 200.0f; int16_t* inBuf = new int16_t[blockSize * 2]; while (true) { diff --git a/plutosdr_source/src/main.cpp b/plutosdr_source/src/main.cpp index b316ba55..e4a8222f 100644 --- a/plutosdr_source/src/main.cpp +++ b/plutosdr_source/src/main.cpp @@ -205,7 +205,7 @@ private: static void worker(void* ctx) { PlutoSDRSourceModule* _this = (PlutoSDRSourceModule*)ctx; - int blockSize = _this->sampleRate / 200.0; + int blockSize = _this->sampleRate / 200.0f; struct iio_channel *rx0_i, *rx0_q; struct iio_buffer *rxbuf; diff --git a/radio/src/am_demod.h b/radio/src/am_demod.h index debae935..41ac7b06 100644 --- a/radio/src/am_demod.h +++ b/radio/src/am_demod.h @@ -42,7 +42,7 @@ public: demod.init(&squelch.out); - agc.init(&demod.out, 1.0f / 125.0f); + agc.init(&demod.out, 20.0f, bbSampRate); float audioBW = std::min(audioSampRate / 2.0f, bw / 2.0f); win.init(audioBW, audioBW, bbSampRate); @@ -151,6 +151,11 @@ private: void setBandwidth(float bandWidth) { bw = bandWidth; _vfo->setBandwidth(bw); + float audioBW = std::min(audioSampRate / 2.0f, bw / 2.0f); + win.setSampleRate(bbSampRate * resamp.getInterpolation()); + win.setCutoff(audioBW); + win.setTransWidth(audioBW); + resamp.updateWindow(&win); } void setSnapInterval(float snapInt) { diff --git a/radio/src/cw_demod.h b/radio/src/cw_demod.h index 27d5da28..0213d26c 100644 --- a/radio/src/cw_demod.h +++ b/radio/src/cw_demod.h @@ -53,7 +53,7 @@ public: c2r.init(&xlator.out); - agc.init(&c2r.out, 1.0f / 125.0f); + agc.init(&c2r.out, 20.0f, audioSampRate); m2s.init(&agc.out); } @@ -104,6 +104,7 @@ public: } audioSampRate = sampleRate; float audioBW = std::min(audioSampRate / 2.0f, bw / 2.0f); + agc.setSampleRate(audioSampRate); resamp.setOutSampleRate(audioSampRate); win.setSampleRate(bbSampRate * resamp.getInterpolation()); win.setCutoff(audioBW); @@ -170,7 +171,7 @@ private: const float bwMax = 500; const float bwMin = 100; - const float bbSampRate = 500; + const float bbSampRate = 6000; std::string uiPrefix; float snapInterval = 10; diff --git a/radio/src/dsb_demod.h b/radio/src/dsb_demod.h index a0a4080d..fa146aa4 100644 --- a/radio/src/dsb_demod.h +++ b/radio/src/dsb_demod.h @@ -42,7 +42,7 @@ public: demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_DSB); - agc.init(&demod.out, 1.0f / 125.0f); + agc.init(&demod.out, 20.0f, bbSampRate); float audioBW = std::min(audioSampRate / 2.0f, bw / 2.0f); win.init(audioBW, audioBW, bbSampRate); diff --git a/radio/src/lsb_demod.h b/radio/src/lsb_demod.h index 4bf23398..9b484b17 100644 --- a/radio/src/lsb_demod.h +++ b/radio/src/lsb_demod.h @@ -42,7 +42,7 @@ public: demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_LSB); - agc.init(&demod.out, 1.0f / 125.0f); + agc.init(&demod.out, 20.0f, bbSampRate); float audioBW = std::min(audioSampRate / 2.0f, bw); win.init(audioBW, audioBW, bbSampRate); @@ -151,6 +151,12 @@ private: void setBandwidth(float bandWidth) { bw = bandWidth; _vfo->setBandwidth(bw); + demod.setBandWidth(bw); + float audioBW = std::min(audioSampRate / 2.0f, bw); + win.setSampleRate(bbSampRate * resamp.getInterpolation()); + win.setCutoff(audioBW); + win.setTransWidth(audioBW); + resamp.updateWindow(&win); } void setSnapInterval(float snapInt) { diff --git a/radio/src/usb_demod.h b/radio/src/usb_demod.h index f59663dc..fbde6bc4 100644 --- a/radio/src/usb_demod.h +++ b/radio/src/usb_demod.h @@ -42,7 +42,7 @@ public: demod.init(&squelch.out, bbSampRate, bandWidth, dsp::SSBDemod::MODE_USB); - agc.init(&demod.out, 1.0f / 125.0f); + agc.init(&demod.out, 20.0f, bbSampRate); float audioBW = std::min(audioSampRate / 2.0f, bw); win.init(audioBW, audioBW, bbSampRate); @@ -151,6 +151,12 @@ private: void setBandwidth(float bandWidth) { bw = bandWidth; _vfo->setBandwidth(bw); + demod.setBandWidth(bw); + float audioBW = std::min(audioSampRate / 2.0f, bw); + win.setSampleRate(bbSampRate * resamp.getInterpolation()); + win.setCutoff(audioBW); + win.setTransWidth(audioBW); + resamp.updateWindow(&win); } void setSnapInterval(float snapInt) { diff --git a/recorder/src/main.cpp b/recorder/src/main.cpp index 7e09478a..7ce1dd62 100644 --- a/recorder/src/main.cpp +++ b/recorder/src/main.cpp @@ -253,8 +253,8 @@ private: int count = _this->audioStream->read(); if (count < 0) { break; } for (int i = 0; i < count; i++) { - sampleBuf[(i * 2) + 0] = _this->audioStream->readBuf[i].l * 0x7FFF; - sampleBuf[(i * 2) + 1] = _this->audioStream->readBuf[i].r * 0x7FFF; + sampleBuf[(i * 2) + 0] = _this->audioStream->readBuf[i].l * 512; + sampleBuf[(i * 2) + 1] = _this->audioStream->readBuf[i].r * 512; } _this->audioStream->flush(); _this->samplesWritten += count; diff --git a/root/res/colormaps/classic.json b/root/res/colormaps/classic.json new file mode 100644 index 00000000..b6e4b236 --- /dev/null +++ b/root/res/colormaps/classic.json @@ -0,0 +1,19 @@ +{ + "name": "Classic", + "author": "Youssef Touil", + "map": [ + "#4A0000", + "#750000", + "#9F0000", + "#C60000", + "#FF0000", + "#FE6D16", + "#FFFF00", + "#FFFFFF", + "#1E90FF", + "#000091", + "#000050", + "#000030", + "#000020" + ] +} \ No newline at end of file diff --git a/rtl_tcp_source/src/main.cpp b/rtl_tcp_source/src/main.cpp index 1aa71896..6c2d5cb5 100644 --- a/rtl_tcp_source/src/main.cpp +++ b/rtl_tcp_source/src/main.cpp @@ -212,7 +212,7 @@ private: static void worker(void* ctx) { RTLTCPSourceModule* _this = (RTLTCPSourceModule*)ctx; - int blockSize = _this->sampleRate / 200.0; + int blockSize = _this->sampleRate / 200.0f; uint8_t* inBuf = new uint8_t[blockSize * 2]; while (true) { diff --git a/rx888_source/src/main.cpp b/rx888_source/src/main.cpp index 8350c0f4..80f72255 100644 --- a/rx888_source/src/main.cpp +++ b/rx888_source/src/main.cpp @@ -11,20 +11,21 @@ #define CONCAT(a, b) ((std::string(a) + b).c_str()) -#define ADC_RATE 128000000 +#define ADC_RATE 64000000 #define XFER_TIMEOUT 5000 #define SEL0 (8) // SEL0 GPIO26 #define SEL1 (16) // SEL1 GPIO27 -MOD_INFO { - /* Name: */ "rx888_source", - /* Description: */ "RX888 input module for SDR++", - /* Author: */ "Ryzerth", - /* Version: */ "0.1.0" +SDRPP_MOD_INFO { + /* Name: */ "rx888_source", + /* Description: */ "RX888 source module for SDR++", + /* Author: */ "Ryzerth", + /* Version: */ 0, 1, 0, + /* Max instances */ 1 }; -class RX888SourceModule { +class RX888SourceModule : public ModuleManager::Instance { public: RX888SourceModule(std::string name) { this->name = name; @@ -58,6 +59,18 @@ public: spdlog::info("RX888SourceModule '{0}': Instance deleted!", name); } + void enable() { + enabled = true; + } + + void disable() { + enabled = false; + } + + bool isEnabled() { + return enabled; + } + private: static void menuSelected(void* ctx) { @@ -125,7 +138,7 @@ private: static void _usbWorker(RX888SourceModule* _this) { // Calculate hardware block siz - int realBlockSize = ADC_RATE / 200; + int realBlockSize = ADC_RATE / 100; int i; for (i = 1; i < realBlockSize; i = (i << 1)); realBlockSize = (i >> 1); @@ -170,9 +183,8 @@ private: // Check if the incomming data is bulk I/Q and end transfer if (EndPt->Attributes == 2) { if (EndPt->FinishDataXfer((PUCHAR)buffer, rLen, &inOvLap, context)) { - if (_this->realStream.aquire() < 0) { break; } - memcpy(_this->realStream.data, buffer, rLen); - _this->realStream.write(rLen / 2); + memcpy(_this->realStream.writeBuf, buffer, rLen); + _this->realStream.swap(rLen / 2); } } @@ -196,7 +208,7 @@ private: while (count >= 0) { for (int i = 0; i < count; i++) { - iqbuffer[i].q = (float)_this->realStream.data[i] / 32768.0f; + iqbuffer[i].q = (float)_this->realStream.readBuf[i] / 32768.0f; } _this->realStream.flush(); @@ -205,21 +217,20 @@ private: lv_32fc_t phaseDelta = lv_cmake(std::cos(delta), std::sin(delta)); // Apply translation - if (_this->stream.aquire() < 0) { break; } - volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)_this->stream.data, (lv_32fc_t*)iqbuffer, phaseDelta, &phase, count); + volk_32fc_s32fc_x2_rotator_32fc((lv_32fc_t*)_this->stream.writeBuf, (lv_32fc_t*)iqbuffer, phaseDelta, &phase, count); // Decimate blockSize = count; for (int d = 0; d < (_this->decimation - 1); d++) { blockSize = (blockSize >> 1); for (int i = 0; i < blockSize; i++) { - _this->stream.data[i].i = (_this->stream.data[i*2].i + _this->stream.data[(i*2)+1].i) * 0.5f; - _this->stream.data[i].q = (_this->stream.data[i*2].q + _this->stream.data[(i*2)+1].q) * 0.5f; + _this->stream.writeBuf[i].i = (_this->stream.writeBuf[i*2].i + _this->stream.writeBuf[(i*2)+1].i) * 0.5f; + _this->stream.writeBuf[i].q = (_this->stream.writeBuf[i*2].q + _this->stream.writeBuf[(i*2)+1].q) * 0.5f; } } // Write to output stream - _this->stream.write(blockSize); + _this->stream.swap(blockSize); // Read from real stream count = _this->realStream.read(); @@ -242,20 +253,20 @@ private: double sampleRate; int decimation; bool running = false; + bool enabled = true; }; MOD_EXPORT void _INIT_() { } -MOD_EXPORT void* _CREATE_INSTANCE_(std::string name) { +MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) { return new RX888SourceModule(name); } -MOD_EXPORT void _DELETE_INSTANCE_(void* instance) { +MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) { delete (RX888SourceModule*)instance; } - -MOD_EXPORT void _STOP_() { +MOD_EXPORT void _END_() { } \ No newline at end of file