From b65bddc1b3b76f5e9cd82bcd7cef23712d2d847f Mon Sep 17 00:00:00 2001 From: Ryzerth Date: Mon, 10 Aug 2020 02:30:25 +0200 Subject: [PATCH] multi-vfo --- src/dsp/demodulator.h | 8 +- src/main.cpp | 2 + src/main_window.cpp | 89 +++++++++++----- src/vfo_manager.h | 5 + src/waterfall.cpp | 233 ++++++++++++++++++++++++++++-------------- src/waterfall.h | 54 +++++++--- 6 files changed, 268 insertions(+), 123 deletions(-) create mode 100644 src/vfo_manager.h diff --git a/src/dsp/demodulator.h b/src/dsp/demodulator.h index 30600de1..059faedf 100644 --- a/src/dsp/demodulator.h +++ b/src/dsp/demodulator.h @@ -14,15 +14,13 @@ #define FAST_ATAN2_COEF2 3.0f * FAST_ATAN2_COEF1 inline float fast_arctan2(float y, float x) { - float abs_y = fabs(y)+1e-10; + float abs_y = fabs(y) + (1e-10); float r, angle; - if (x>=0) - { + if (x>=0) { r = (x - abs_y) / (x + abs_y); angle = FAST_ATAN2_COEF1 - FAST_ATAN2_COEF1 * r; } - else - { + else { r = (x + abs_y) / (abs_y - x); angle = FAST_ATAN2_COEF2 - FAST_ATAN2_COEF1 * r; } diff --git a/src/main.cpp b/src/main.cpp index 29c7323a..8902e10f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -78,6 +78,8 @@ int main() { //mod::loadModule("../modules/demo/build/Release/demo.dll", "Demo Module 2"); //mod::loadModule("../modules/demo/build/Release/demo.dll", "Demo Module 3"); + + spdlog::info("Ready."); // Main loop diff --git a/src/main_window.cpp b/src/main_window.cpp index b70f9e21..38e1f1d9 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -40,8 +40,20 @@ void windowInit() { int sampleRate = 8000000; wtf.setBandwidth(sampleRate); wtf.setCenterFrequency(90500000); - wtf.setVFOBandwidth(200000); - wtf.setVFOOffset(0); + // wtf.setVFOBandwidth(200000); + // wtf.setVFOOffset(0); + + wtf.vfos["Radio"] = new ImGui::WaterfallVFO; + wtf.vfos["Radio"]->setReference(ImGui::WaterfallVFO::REF_CENTER); + wtf.vfos["Radio"]->setBandwidth(200000); + wtf.vfos["Radio"]->setOffset(0); + + wtf.vfos["Radio 2"] = new ImGui::WaterfallVFO; + wtf.vfos["Radio 2"]->setReference(ImGui::WaterfallVFO::REF_CENTER); + wtf.vfos["Radio 2"]->setBandwidth(200000); + wtf.vfos["Radio 2"]->setOffset(300000); + + wtf.selectedVFO = "Radio"; fSel.init(); fSel.setFrequency(90500000); @@ -71,14 +83,20 @@ int sampleRate = 1000000; bool playing = false; watcher dcbias(false, false); watcher bandPlanEnabled(true, false); +bool selectedVFOChanged = false; void setVFO(float freq) { - float currentOff = wtf.getVFOOfset(); - float currentTune = wtf.getCenterFrequency() + currentOff; + if (wtf.selectedVFO == "") { + return; + } + ImGui::WaterfallVFO* vfo = wtf.vfos[wtf.selectedVFO]; + + float currentOff = vfo->centerOffset; + float currentTune = wtf.getCenterFrequency() + vfo->generalOffset; float delta = freq - currentTune; float newVFO = currentOff + delta; - float vfoBW = wtf.getVFOBandwidth(); + float vfoBW = vfo->bandwidth; float vfoBottom = newVFO - (vfoBW / 2.0f); float vfoTop = newVFO + (vfoBW / 2.0f); @@ -95,7 +113,7 @@ void setVFO(float freq) { // VFO still fints in the view if (vfoBottom > viewBottom && vfoTop < viewTop) { sigPath.setVFOFrequency(newVFO); - wtf.setVFOOffset(newVFO); + vfo->setCenterOffset(newVFO); return; } @@ -104,7 +122,7 @@ void setVFO(float freq) { wtf.setViewOffset((BW / 2.0f) - (viewBW / 2.0f)); float newVFOOffset = (BW / 2.0f) - (vfoBW / 2.0f) - (viewBW / 10.0f); sigPath.setVFOFrequency(newVFOOffset); - wtf.setVFOOffset(newVFOOffset); + vfo->setCenterOffset(newVFOOffset); wtf.setCenterFrequency(freq - newVFOOffset); soapy.setFrequency(freq - newVFOOffset); return; @@ -115,7 +133,7 @@ void setVFO(float freq) { wtf.setViewOffset((viewBW / 2.0f) - (BW / 2.0f)); float newVFOOffset = (vfoBW / 2.0f) - (BW / 2.0f) + (viewBW / 10.0f); sigPath.setVFOFrequency(newVFOOffset); - wtf.setVFOOffset(newVFOOffset); + vfo->setCenterOffset(newVFOOffset); wtf.setCenterFrequency(freq - newVFOOffset); soapy.setFrequency(freq - newVFOOffset); return; @@ -128,7 +146,7 @@ void setVFO(float freq) { float newViewTop = newViewOff + (viewBW / 2.0f); if (newViewBottom > bottom) { - wtf.setVFOOffset(newVFO); + vfo->setCenterOffset(newVFO); wtf.setViewOffset(newViewOff); sigPath.setVFOFrequency(newVFO); return; @@ -137,7 +155,7 @@ void setVFO(float freq) { wtf.setViewOffset((BW / 2.0f) - (viewBW / 2.0f)); float newVFOOffset = (BW / 2.0f) - (vfoBW / 2.0f) - (viewBW / 10.0f); sigPath.setVFOFrequency(newVFOOffset); - wtf.setVFOOffset(newVFOOffset); + vfo->setCenterOffset(newVFOOffset); wtf.setCenterFrequency(freq - newVFOOffset); soapy.setFrequency(freq - newVFOOffset); } @@ -147,7 +165,7 @@ void setVFO(float freq) { float newViewTop = newViewOff + (viewBW / 2.0f); if (newViewTop < top) { - wtf.setVFOOffset(newVFO); + vfo->setCenterOffset(newVFO); wtf.setViewOffset(newViewOff); sigPath.setVFOFrequency(newVFO); return; @@ -156,13 +174,20 @@ void setVFO(float freq) { wtf.setViewOffset((viewBW / 2.0f) - (BW / 2.0f)); float newVFOOffset = (vfoBW / 2.0f) - (BW / 2.0f) + (viewBW / 10.0f); sigPath.setVFOFrequency(newVFOOffset); - wtf.setVFOOffset(newVFOOffset); + vfo->setCenterOffset(newVFOOffset); wtf.setCenterFrequency(freq - newVFOOffset); soapy.setFrequency(freq - newVFOOffset); } } void drawWindow() { + ImGui::WaterfallVFO* vfo = wtf.vfos[wtf.selectedVFO]; + + if (selectedVFOChanged) { + selectedVFOChanged = false; + fSel.setFrequency(vfo->generalOffset + wtf.getCenterFrequency()); + } + if (fSel.frequencyChanged) { fSel.frequencyChanged = false; setVFO(fSel.frequency); @@ -171,12 +196,12 @@ void drawWindow() { if (wtf.centerFreqMoved) { wtf.centerFreqMoved = false; soapy.setFrequency(wtf.getCenterFrequency()); - fSel.setFrequency(wtf.getCenterFrequency() + wtf.getVFOOfset()); + fSel.setFrequency(wtf.getCenterFrequency() + vfo->generalOffset); } if (wtf.vfoFreqChanged) { wtf.vfoFreqChanged = false; - sigPath.setVFOFrequency(wtf.getVFOOfset()); - fSel.setFrequency(wtf.getCenterFrequency() + wtf.getVFOOfset()); + sigPath.setVFOFrequency(vfo->centerOffset); + fSel.setFrequency(wtf.getCenterFrequency() + vfo->generalOffset); } if (volume.changed()) { @@ -303,42 +328,41 @@ void drawWindow() { ImGui::Columns(4, "RadioModeColumns", false); if (ImGui::RadioButton("NFM", demod == 0) && demod != 0) { sigPath.setDemodulator(SignalPath::DEMOD_NFM); demod = 0; - wtf.setVFOBandwidth(12500); - wtf.setVFOReference(ImGui::WaterFall::REF_CENTER); + vfo->setBandwidth(12500); + vfo->setReference(ImGui::WaterFall::REF_CENTER); } if (ImGui::RadioButton("WFM", demod == 1) && demod != 1) { sigPath.setDemodulator(SignalPath::DEMOD_FM); demod = 1; - wtf.setVFOBandwidth(200000); - wtf.setVFOReference(ImGui::WaterFall::REF_CENTER); + vfo->setBandwidth(200000); + vfo->setReference(ImGui::WaterFall::REF_CENTER); } ImGui::NextColumn(); if (ImGui::RadioButton("AM", demod == 2) && demod != 2) { sigPath.setDemodulator(SignalPath::DEMOD_AM); demod = 2; - wtf.setVFOBandwidth(12500); - wtf.setVFOReference(ImGui::WaterFall::REF_CENTER); + vfo->setBandwidth(12500); + vfo->setReference(ImGui::WaterFall::REF_CENTER); } if (ImGui::RadioButton("DSB", demod == 3) && demod != 3) { demod = 3; }; ImGui::NextColumn(); if (ImGui::RadioButton("USB", demod == 4) && demod != 4) { sigPath.setDemodulator(SignalPath::DEMOD_USB); demod = 4; - wtf.setVFOBandwidth(3000); - wtf.setVFOReference(ImGui::WaterFall::REF_LOWER); + vfo->setBandwidth(3000); + vfo->setReference(ImGui::WaterFall::REF_LOWER); } if (ImGui::RadioButton("CW", demod == 5) && demod != 5) { demod = 5; }; ImGui::NextColumn(); if (ImGui::RadioButton("LSB", demod == 6) && demod != 6) { sigPath.setDemodulator(SignalPath::DEMOD_LSB); demod = 6; - wtf.setVFOBandwidth(3000); - wtf.setVFOReference(ImGui::WaterFall::REF_UPPER); + vfo->setBandwidth(3000); + vfo->setReference(ImGui::WaterFall::REF_UPPER); } if (ImGui::RadioButton("RAW", demod == 7) && demod != 7) { demod = 7; }; ImGui::Columns(1, "EndRadioModeColumns", false); - //ImGui::InputInt("Frequency (kHz)", &freq); ImGui::Checkbox("DC Bias Removal", &dcbias.val); ImGui::EndGroup(); @@ -363,6 +387,17 @@ void drawWindow() { if(ImGui::CollapsingHeader("Debug")) { ImGui::Text("Frame time: %.3f ms/frame", 1000.0f / ImGui::GetIO().Framerate); ImGui::Text("Framerate: %.1f FPS", ImGui::GetIO().Framerate); + ImGui::Text("Center Frequency: %.1f FPS", wtf.getCenterFrequency()); + + if (ImGui::Button("Radio##__sdsd__")) { + wtf.selectedVFO = "Radio"; + selectedVFOChanged = true; + } + ImGui::SameLine(); + if (ImGui::Button("Radio 2")) { + wtf.selectedVFO = "Radio 2"; + selectedVFOChanged = true; + } } ImGui::EndChild(); @@ -391,7 +426,7 @@ void drawWindow() { if (bw.changed()) { wtf.setViewBandwidth(bw.val); - wtf.setViewOffset(wtf.getVFOOfset()); + wtf.setViewOffset(vfo->centerOffset); } wtf.setFFTMin(fftMin); diff --git a/src/vfo_manager.h b/src/vfo_manager.h new file mode 100644 index 00000000..20f8807d --- /dev/null +++ b/src/vfo_manager.h @@ -0,0 +1,5 @@ +#pragma once + +namespace vfoman { + +}; \ No newline at end of file diff --git a/src/waterfall.cpp b/src/waterfall.cpp index ab2124c7..0664985c 100644 --- a/src/waterfall.cpp +++ b/src/waterfall.cpp @@ -173,38 +173,35 @@ namespace ImGui { ImVec2(widgetPos.x + 50 + dataWidth, widgetPos.y + fftHeight + 51 + waterfallHeight)); } - void WaterFall::drawVFO() { - float width = (vfoBandwidth / viewBandwidth) * (float)dataWidth; - int center = roundf((((vfoOffset - viewOffset) / (viewBandwidth / 2.0f)) + 1.0f) * ((float)dataWidth / 2.0f)); - int left; - int right; + void WaterFall::drawVFOs() { + for (auto const& [name, vfo] : vfos) { + if (vfo->redrawRequired) { + vfo->redrawRequired = false; + vfo->updateDrawingVars(viewBandwidth, dataWidth, viewOffset, widgetPos, fftHeight); + } + vfo->draw(window, name == selectedVFO); + } + } + void WaterFall::processInputs() { ImVec2 mousePos = ImGui::GetMousePos(); ImVec2 drag = ImGui::GetMouseDragDelta(ImGuiMouseButton_Left); ImVec2 dragOrigin(mousePos.x - drag.x, mousePos.y - drag.y); + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { + spdlog::info("Clicked!"); + } + bool freqDrag = ImGui::IsMouseDragging(ImGuiMouseButton_Left) && IS_IN_AREA(dragOrigin, freqAreaMin, freqAreaMax); - if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && IS_IN_AREA(mousePos, fftAreaMin, fftAreaMax) && !freqDrag) { - int refCenter = mousePos.x - (widgetPos.x + 50); - if (refCenter >= 0 && refCenter < dataWidth && mousePos.y > widgetPos.y && mousePos.y < (widgetPos.y + widgetSize.y)) { - vfoOffset = ((((float)refCenter / ((float)dataWidth / 2.0f)) - 1.0f) * (viewBandwidth / 2.0f)) + viewOffset; - center = refCenter; - } - vfoFreqChanged = true; - } - - // if (vfoRef == REF_CENTER) { - // left = center - (width / 2.0f) + 1; - // right = center + (width / 2.0f) + 1; - // } - // if (vfoRef == REF_LOWER) { - // left = center; - // right = center + width + 1; - // } - // if (vfoRef == REF_UPPER) { - // left = center; - // right = center - width + 1; + // TODO: Process VFO drag + + // if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && IS_IN_AREA(mousePos, fftAreaMin, fftAreaMax) && !freqDrag) { + // int refCenter = mousePos.x - (widgetPos.x + 50); + // if (refCenter >= 0 && refCenter < dataWidth && mousePos.y > widgetPos.y && mousePos.y < (widgetPos.y + widgetSize.y)) { + // vfoOffset = ((((float)refCenter / ((float)dataWidth / 2.0f)) - 1.0f) * (viewBandwidth / 2.0f)) + viewOffset; + // } + // vfoFreqChanged = true; // } if (freqDrag) { @@ -234,35 +231,6 @@ namespace ImGui { else { lastDrag = 0; } - - left = center - (width / 2.0f) + 1; - right = center + (width / 2.0f) + 1; - - if ((left < 0 && right < 0) || (left >= dataWidth && right >= dataWidth)) { - return; - } - left = std::clamp(left, 0, dataWidth - 1); - right = std::clamp(right, 0, dataWidth - 1); - window->DrawList->AddRectFilled(ImVec2(widgetPos.x + 50 + left, widgetPos.y + 10), - ImVec2(widgetPos.x + 50 + right, widgetPos.y + fftHeight + 10), IM_COL32(255, 255, 255, 50)); - if (center >= 0 && center < dataWidth) { - if (vfoRef == REF_CENTER) { - window->DrawList->AddLine(ImVec2(widgetPos.x + 50 + center, widgetPos.y + 9), - ImVec2(widgetPos.x + 50 + center, widgetPos.y + fftHeight + 9), - IM_COL32(255, 0, 0, 255), 1.0f); - } - else if (vfoRef == REF_LOWER) { - window->DrawList->AddLine(ImVec2(widgetPos.x + 50 + left, widgetPos.y + 9), - ImVec2(widgetPos.x + 50 + left, widgetPos.y + fftHeight + 9), - IM_COL32(255, 0, 0, 255), 1.0f); - } - else if (vfoRef == REF_UPPER) { - window->DrawList->AddLine(ImVec2(widgetPos.x + 50 + right, widgetPos.y + 9), - ImVec2(widgetPos.x + 50 + right, widgetPos.y + fftHeight + 9), - IM_COL32(255, 0, 0, 255), 1.0f); - } - - } } void WaterFall::updateWaterfallFb() { @@ -382,6 +350,7 @@ namespace ImGui { vRange = 10.0f; updateWaterfallFb(); + updateAllVFOs(); } void WaterFall::draw() { @@ -408,9 +377,11 @@ namespace ImGui { window->DrawList->AddRect(widgetPos, widgetEndPos, IM_COL32( 50, 50, 50, 255 )); window->DrawList->AddLine(ImVec2(widgetPos.x, widgetPos.y + fftHeight + 50), ImVec2(widgetPos.x + widgetSize.x, widgetPos.y + fftHeight + 50), IM_COL32(50, 50, 50, 255), 1.0f); + processInputs(); + drawFFT(); drawWaterfall(); - drawVFO(); + drawVFOs(); if (bandplan != NULL) { drawBandPlan(); } @@ -475,6 +446,7 @@ namespace ImGui { centerFreq = freq; lowerFreq = (centerFreq + viewOffset) - (viewBandwidth / 2.0f); upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0f); + updateAllVFOs(); } float WaterFall::getCenterFrequency() { @@ -485,35 +457,13 @@ namespace ImGui { float currentRatio = viewBandwidth / wholeBandwidth; wholeBandwidth = bandWidth; setViewBandwidth(bandWidth * currentRatio); + updateAllVFOs(); } float WaterFall::getBandwidth() { return wholeBandwidth; } - void WaterFall::setVFOOffset(float offset) { - vfoOffset = offset; - } - - float WaterFall::getVFOOfset() { - return vfoOffset; - } - - void WaterFall::setVFOBandwidth(float bandwidth) { - vfoBandwidth = bandwidth; - } - - float WaterFall::getVFOBandwidth() { - return vfoBandwidth; - } - - void WaterFall::setVFOReference(int ref) { - if (ref < 0 || ref >= _REF_COUNT) { - return; - } - vfoRef = ref; - } - void WaterFall::setViewBandwidth(float bandWidth) { if (bandWidth == viewBandwidth) { return; @@ -531,6 +481,7 @@ namespace ImGui { upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0f); range = findBestRange(bandWidth, maxHSteps); updateWaterfallFb(); + updateAllVFOs(); } float WaterFall::getViewBandwidth() { @@ -551,6 +502,7 @@ namespace ImGui { lowerFreq = (centerFreq + viewOffset) - (viewBandwidth / 2.0f); upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0f); updateWaterfallFb(); + updateAllVFOs(); } float WaterFall::getViewOffset() { @@ -598,5 +550,130 @@ namespace ImGui { float WaterFall::getWaterfallMax() { return waterfallMax; } + + void WaterFall::updateAllVFOs() { + for (auto const& [name, vfo] : vfos) { + vfo->updateDrawingVars(viewBandwidth, dataWidth, viewOffset, widgetPos, fftHeight); + } + } + + void WaterfallVFO::setOffset(float offset) { + generalOffset = offset; + if (reference == REF_CENTER) { + centerOffset = offset; + lowerOffset = offset - (bandwidth / 2.0f); + upperOffset = offset + (bandwidth / 2.0f); + } + else if (reference == REF_LOWER) { + lowerOffset = offset; + centerOffset = offset + (bandwidth / 2.0f); + upperOffset = offset + bandwidth; + } + else if (reference == REF_UPPER) { + upperOffset = offset; + centerOffset = offset - (bandwidth / 2.0f); + lowerOffset = offset - bandwidth; + } + centerOffsetChanged = true; + upperOffsetChanged = true; + lowerOffsetChanged = true; + redrawRequired = true; + } + + void WaterfallVFO::setCenterOffset(float offset) { + if (reference == REF_CENTER) { + generalOffset = offset; + } + else if (reference == REF_LOWER) { + generalOffset = offset - (bandwidth / 2.0f); + } + else if (reference == REF_UPPER) { + generalOffset = offset + (bandwidth / 2.0f); + } + centerOffset = offset; + lowerOffset = offset - (bandwidth / 2.0f); + upperOffset = offset + (bandwidth / 2.0f); + centerOffsetChanged = true; + upperOffsetChanged = true; + lowerOffsetChanged = true; + redrawRequired = true; + } + + void WaterfallVFO::setBandwidth(float bw) { + if (bandwidth == bw || bw < 0) { + return; + } + bandwidth = bw; + if (reference == REF_CENTER) { + lowerOffset = centerOffset - (bandwidth / 2.0f); + upperOffset = centerOffset + (bandwidth / 2.0f); + } + else if (reference == REF_LOWER) { + centerOffset = lowerOffset + (bandwidth / 2.0f); + upperOffset = lowerOffset + bandwidth; + centerOffsetChanged; + } + else if (reference == REF_UPPER) { + centerOffset = upperOffset - (bandwidth / 2.0f); + lowerOffset = upperOffset - bandwidth; + centerOffsetChanged; + } + redrawRequired = true; + } + + void WaterfallVFO::setReference(int ref) { + if (reference == ref || ref < 0 || ref >= _REF_COUNT) { + return; + } + reference = ref; + if (reference == REF_CENTER) { + setOffset(centerOffset); + } + else if (reference == REF_LOWER) { + setOffset(lowerOffset); + } + else if (reference == REF_UPPER) { + setOffset(upperOffset); + } + } + + void WaterfallVFO::updateDrawingVars(float viewBandwidth, float dataWidth, float viewOffset, ImVec2 widgetPos, int fftHeight) { + float width = (bandwidth / viewBandwidth) * (float)dataWidth; + int center = roundf((((centerOffset - viewOffset) / (viewBandwidth / 2.0f)) + 1.0f) * ((float)dataWidth / 2.0f)); + int left = roundf((((lowerOffset - viewOffset) / (viewBandwidth / 2.0f)) + 1.0f) * ((float)dataWidth / 2.0f)); + int right = roundf((((upperOffset - viewOffset) / (viewBandwidth / 2.0f)) + 1.0f) * ((float)dataWidth / 2.0f)); + + if (left >= 0 && left < dataWidth && reference == REF_LOWER) { + lineMin = ImVec2(widgetPos.x + 50 + left, widgetPos.y + 9); + lineMax = ImVec2(widgetPos.x + 50 + left, widgetPos.y + fftHeight + 9); + lineVisible = true; + } + else if (center >= 0 && center < dataWidth && reference == REF_CENTER) { + lineMin = ImVec2(widgetPos.x + 50 + center, widgetPos.y + 9); + lineMax = ImVec2(widgetPos.x + 50 + center, widgetPos.y + fftHeight + 9); + lineVisible = true; + } + else if (right >= 0 && right < dataWidth && reference == REF_UPPER) { + lineMin = ImVec2(widgetPos.x + 50 + right, widgetPos.y + 9); + lineMax = ImVec2(widgetPos.x + 50 + right, widgetPos.y + fftHeight + 9); + lineVisible = true; + } + else { + lineVisible = false; + } + + left = std::clamp(left, 0, dataWidth - 1); + right = std::clamp(right, 0, dataWidth - 1); + + rectMin = ImVec2(widgetPos.x + 50 + left, widgetPos.y + 10); + rectMax = ImVec2(widgetPos.x + 51 + right, widgetPos.y + fftHeight + 10); + } + + void WaterfallVFO::draw(ImGuiWindow* window, bool selected) { + window->DrawList->AddRectFilled(rectMin, rectMax, IM_COL32(255, 255, 255, 50)); + if (lineVisible) { + window->DrawList->AddLine(lineMin, lineMax, selected ? IM_COL32(255, 0, 0, 255) : IM_COL32(255, 255, 0, 255)); + } + }; }; diff --git a/src/waterfall.h b/src/waterfall.h index 4edd907c..6729838b 100644 --- a/src/waterfall.h +++ b/src/waterfall.h @@ -12,6 +12,41 @@ namespace ImGui { + class WaterfallVFO { + public: + void setOffset(float offset); + void setCenterOffset(float offset); + void setBandwidth(float bw); + void setReference(int ref); + void updateDrawingVars(float viewBandwidth, float dataWidth, float viewOffset, ImVec2 widgetPos, int fftHeight); + void draw(ImGuiWindow* window, bool selected); + + enum { + REF_LOWER, + REF_CENTER, + REF_UPPER, + _REF_COUNT + }; + + float generalOffset; + float centerOffset; + float lowerOffset; + float upperOffset; + float bandwidth; + int reference = REF_CENTER; + + ImVec2 rectMin; + ImVec2 rectMax; + ImVec2 lineMin; + ImVec2 lineMax; + + bool centerOffsetChanged = false; + bool lowerOffsetChanged = false; + bool upperOffsetChanged = false; + bool redrawRequired = true; + bool lineVisible = true; + }; + class WaterFall { public: WaterFall(); @@ -27,14 +62,6 @@ namespace ImGui { void setBandwidth(float bandWidth); float getBandwidth(); - void setVFOOffset(float offset); - float getVFOOfset(); - - void setVFOBandwidth(float bandwidth); - float getVFOBandwidth(); - - void setVFOReference(int ref); - void setViewBandwidth(float bandWidth); float getViewBandwidth(); @@ -63,6 +90,9 @@ namespace ImGui { bool bandplanEnabled = false; bandplan::BandPlan_t* bandplan = NULL; + std::map vfos; + std::string selectedVFO; + enum { REF_LOWER, REF_CENTER, @@ -74,12 +104,14 @@ namespace ImGui { private: void drawWaterfall(); void drawFFT(); - void drawVFO(); + void drawVFOs(); void drawBandPlan(); + void processInputs(); void onPositionChange(); void onResize(); void updateWaterfallFb(); void updateWaterfallTexture(); + void updateAllVFOs(); bool waterfallUpdate = false; @@ -129,10 +161,6 @@ namespace ImGui { float centerFreq; float wholeBandwidth; - // VFO - float vfoOffset; - float vfoBandwidth; - // Ranges float fftMin; float fftMax;