multi-vfo

This commit is contained in:
Ryzerth 2020-08-10 02:30:25 +02:00
parent 7759de96da
commit b65bddc1b3
6 changed files with 268 additions and 123 deletions

View File

@ -14,15 +14,13 @@
#define FAST_ATAN2_COEF2 3.0f * FAST_ATAN2_COEF1 #define FAST_ATAN2_COEF2 3.0f * FAST_ATAN2_COEF1
inline float fast_arctan2(float y, float x) { 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; float r, angle;
if (x>=0) if (x>=0) {
{
r = (x - abs_y) / (x + abs_y); r = (x - abs_y) / (x + abs_y);
angle = FAST_ATAN2_COEF1 - FAST_ATAN2_COEF1 * r; angle = FAST_ATAN2_COEF1 - FAST_ATAN2_COEF1 * r;
} }
else else {
{
r = (x + abs_y) / (abs_y - x); r = (x + abs_y) / (abs_y - x);
angle = FAST_ATAN2_COEF2 - FAST_ATAN2_COEF1 * r; angle = FAST_ATAN2_COEF2 - FAST_ATAN2_COEF1 * r;
} }

View File

@ -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 2");
//mod::loadModule("../modules/demo/build/Release/demo.dll", "Demo Module 3"); //mod::loadModule("../modules/demo/build/Release/demo.dll", "Demo Module 3");
spdlog::info("Ready."); spdlog::info("Ready.");
// Main loop // Main loop

View File

@ -40,8 +40,20 @@ void windowInit() {
int sampleRate = 8000000; int sampleRate = 8000000;
wtf.setBandwidth(sampleRate); wtf.setBandwidth(sampleRate);
wtf.setCenterFrequency(90500000); wtf.setCenterFrequency(90500000);
wtf.setVFOBandwidth(200000); // wtf.setVFOBandwidth(200000);
wtf.setVFOOffset(0); // 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.init();
fSel.setFrequency(90500000); fSel.setFrequency(90500000);
@ -71,14 +83,20 @@ int sampleRate = 1000000;
bool playing = false; bool playing = false;
watcher<bool> dcbias(false, false); watcher<bool> dcbias(false, false);
watcher<bool> bandPlanEnabled(true, false); watcher<bool> bandPlanEnabled(true, false);
bool selectedVFOChanged = false;
void setVFO(float freq) { void setVFO(float freq) {
float currentOff = wtf.getVFOOfset(); if (wtf.selectedVFO == "") {
float currentTune = wtf.getCenterFrequency() + currentOff; return;
}
ImGui::WaterfallVFO* vfo = wtf.vfos[wtf.selectedVFO];
float currentOff = vfo->centerOffset;
float currentTune = wtf.getCenterFrequency() + vfo->generalOffset;
float delta = freq - currentTune; float delta = freq - currentTune;
float newVFO = currentOff + delta; float newVFO = currentOff + delta;
float vfoBW = wtf.getVFOBandwidth(); float vfoBW = vfo->bandwidth;
float vfoBottom = newVFO - (vfoBW / 2.0f); float vfoBottom = newVFO - (vfoBW / 2.0f);
float vfoTop = newVFO + (vfoBW / 2.0f); float vfoTop = newVFO + (vfoBW / 2.0f);
@ -95,7 +113,7 @@ void setVFO(float freq) {
// VFO still fints in the view // VFO still fints in the view
if (vfoBottom > viewBottom && vfoTop < viewTop) { if (vfoBottom > viewBottom && vfoTop < viewTop) {
sigPath.setVFOFrequency(newVFO); sigPath.setVFOFrequency(newVFO);
wtf.setVFOOffset(newVFO); vfo->setCenterOffset(newVFO);
return; return;
} }
@ -104,7 +122,7 @@ void setVFO(float freq) {
wtf.setViewOffset((BW / 2.0f) - (viewBW / 2.0f)); wtf.setViewOffset((BW / 2.0f) - (viewBW / 2.0f));
float newVFOOffset = (BW / 2.0f) - (vfoBW / 2.0f) - (viewBW / 10.0f); float newVFOOffset = (BW / 2.0f) - (vfoBW / 2.0f) - (viewBW / 10.0f);
sigPath.setVFOFrequency(newVFOOffset); sigPath.setVFOFrequency(newVFOOffset);
wtf.setVFOOffset(newVFOOffset); vfo->setCenterOffset(newVFOOffset);
wtf.setCenterFrequency(freq - newVFOOffset); wtf.setCenterFrequency(freq - newVFOOffset);
soapy.setFrequency(freq - newVFOOffset); soapy.setFrequency(freq - newVFOOffset);
return; return;
@ -115,7 +133,7 @@ void setVFO(float freq) {
wtf.setViewOffset((viewBW / 2.0f) - (BW / 2.0f)); wtf.setViewOffset((viewBW / 2.0f) - (BW / 2.0f));
float newVFOOffset = (vfoBW / 2.0f) - (BW / 2.0f) + (viewBW / 10.0f); float newVFOOffset = (vfoBW / 2.0f) - (BW / 2.0f) + (viewBW / 10.0f);
sigPath.setVFOFrequency(newVFOOffset); sigPath.setVFOFrequency(newVFOOffset);
wtf.setVFOOffset(newVFOOffset); vfo->setCenterOffset(newVFOOffset);
wtf.setCenterFrequency(freq - newVFOOffset); wtf.setCenterFrequency(freq - newVFOOffset);
soapy.setFrequency(freq - newVFOOffset); soapy.setFrequency(freq - newVFOOffset);
return; return;
@ -128,7 +146,7 @@ void setVFO(float freq) {
float newViewTop = newViewOff + (viewBW / 2.0f); float newViewTop = newViewOff + (viewBW / 2.0f);
if (newViewBottom > bottom) { if (newViewBottom > bottom) {
wtf.setVFOOffset(newVFO); vfo->setCenterOffset(newVFO);
wtf.setViewOffset(newViewOff); wtf.setViewOffset(newViewOff);
sigPath.setVFOFrequency(newVFO); sigPath.setVFOFrequency(newVFO);
return; return;
@ -137,7 +155,7 @@ void setVFO(float freq) {
wtf.setViewOffset((BW / 2.0f) - (viewBW / 2.0f)); wtf.setViewOffset((BW / 2.0f) - (viewBW / 2.0f));
float newVFOOffset = (BW / 2.0f) - (vfoBW / 2.0f) - (viewBW / 10.0f); float newVFOOffset = (BW / 2.0f) - (vfoBW / 2.0f) - (viewBW / 10.0f);
sigPath.setVFOFrequency(newVFOOffset); sigPath.setVFOFrequency(newVFOOffset);
wtf.setVFOOffset(newVFOOffset); vfo->setCenterOffset(newVFOOffset);
wtf.setCenterFrequency(freq - newVFOOffset); wtf.setCenterFrequency(freq - newVFOOffset);
soapy.setFrequency(freq - newVFOOffset); soapy.setFrequency(freq - newVFOOffset);
} }
@ -147,7 +165,7 @@ void setVFO(float freq) {
float newViewTop = newViewOff + (viewBW / 2.0f); float newViewTop = newViewOff + (viewBW / 2.0f);
if (newViewTop < top) { if (newViewTop < top) {
wtf.setVFOOffset(newVFO); vfo->setCenterOffset(newVFO);
wtf.setViewOffset(newViewOff); wtf.setViewOffset(newViewOff);
sigPath.setVFOFrequency(newVFO); sigPath.setVFOFrequency(newVFO);
return; return;
@ -156,13 +174,20 @@ void setVFO(float freq) {
wtf.setViewOffset((viewBW / 2.0f) - (BW / 2.0f)); wtf.setViewOffset((viewBW / 2.0f) - (BW / 2.0f));
float newVFOOffset = (vfoBW / 2.0f) - (BW / 2.0f) + (viewBW / 10.0f); float newVFOOffset = (vfoBW / 2.0f) - (BW / 2.0f) + (viewBW / 10.0f);
sigPath.setVFOFrequency(newVFOOffset); sigPath.setVFOFrequency(newVFOOffset);
wtf.setVFOOffset(newVFOOffset); vfo->setCenterOffset(newVFOOffset);
wtf.setCenterFrequency(freq - newVFOOffset); wtf.setCenterFrequency(freq - newVFOOffset);
soapy.setFrequency(freq - newVFOOffset); soapy.setFrequency(freq - newVFOOffset);
} }
} }
void drawWindow() { void drawWindow() {
ImGui::WaterfallVFO* vfo = wtf.vfos[wtf.selectedVFO];
if (selectedVFOChanged) {
selectedVFOChanged = false;
fSel.setFrequency(vfo->generalOffset + wtf.getCenterFrequency());
}
if (fSel.frequencyChanged) { if (fSel.frequencyChanged) {
fSel.frequencyChanged = false; fSel.frequencyChanged = false;
setVFO(fSel.frequency); setVFO(fSel.frequency);
@ -171,12 +196,12 @@ void drawWindow() {
if (wtf.centerFreqMoved) { if (wtf.centerFreqMoved) {
wtf.centerFreqMoved = false; wtf.centerFreqMoved = false;
soapy.setFrequency(wtf.getCenterFrequency()); soapy.setFrequency(wtf.getCenterFrequency());
fSel.setFrequency(wtf.getCenterFrequency() + wtf.getVFOOfset()); fSel.setFrequency(wtf.getCenterFrequency() + vfo->generalOffset);
} }
if (wtf.vfoFreqChanged) { if (wtf.vfoFreqChanged) {
wtf.vfoFreqChanged = false; wtf.vfoFreqChanged = false;
sigPath.setVFOFrequency(wtf.getVFOOfset()); sigPath.setVFOFrequency(vfo->centerOffset);
fSel.setFrequency(wtf.getCenterFrequency() + wtf.getVFOOfset()); fSel.setFrequency(wtf.getCenterFrequency() + vfo->generalOffset);
} }
if (volume.changed()) { if (volume.changed()) {
@ -303,42 +328,41 @@ void drawWindow() {
ImGui::Columns(4, "RadioModeColumns", false); ImGui::Columns(4, "RadioModeColumns", false);
if (ImGui::RadioButton("NFM", demod == 0) && demod != 0) { if (ImGui::RadioButton("NFM", demod == 0) && demod != 0) {
sigPath.setDemodulator(SignalPath::DEMOD_NFM); demod = 0; sigPath.setDemodulator(SignalPath::DEMOD_NFM); demod = 0;
wtf.setVFOBandwidth(12500); vfo->setBandwidth(12500);
wtf.setVFOReference(ImGui::WaterFall::REF_CENTER); vfo->setReference(ImGui::WaterFall::REF_CENTER);
} }
if (ImGui::RadioButton("WFM", demod == 1) && demod != 1) { if (ImGui::RadioButton("WFM", demod == 1) && demod != 1) {
sigPath.setDemodulator(SignalPath::DEMOD_FM); sigPath.setDemodulator(SignalPath::DEMOD_FM);
demod = 1; demod = 1;
wtf.setVFOBandwidth(200000); vfo->setBandwidth(200000);
wtf.setVFOReference(ImGui::WaterFall::REF_CENTER); vfo->setReference(ImGui::WaterFall::REF_CENTER);
} }
ImGui::NextColumn(); ImGui::NextColumn();
if (ImGui::RadioButton("AM", demod == 2) && demod != 2) { if (ImGui::RadioButton("AM", demod == 2) && demod != 2) {
sigPath.setDemodulator(SignalPath::DEMOD_AM); sigPath.setDemodulator(SignalPath::DEMOD_AM);
demod = 2; demod = 2;
wtf.setVFOBandwidth(12500); vfo->setBandwidth(12500);
wtf.setVFOReference(ImGui::WaterFall::REF_CENTER); vfo->setReference(ImGui::WaterFall::REF_CENTER);
} }
if (ImGui::RadioButton("DSB", demod == 3) && demod != 3) { demod = 3; }; if (ImGui::RadioButton("DSB", demod == 3) && demod != 3) { demod = 3; };
ImGui::NextColumn(); ImGui::NextColumn();
if (ImGui::RadioButton("USB", demod == 4) && demod != 4) { if (ImGui::RadioButton("USB", demod == 4) && demod != 4) {
sigPath.setDemodulator(SignalPath::DEMOD_USB); sigPath.setDemodulator(SignalPath::DEMOD_USB);
demod = 4; demod = 4;
wtf.setVFOBandwidth(3000); vfo->setBandwidth(3000);
wtf.setVFOReference(ImGui::WaterFall::REF_LOWER); vfo->setReference(ImGui::WaterFall::REF_LOWER);
} }
if (ImGui::RadioButton("CW", demod == 5) && demod != 5) { demod = 5; }; if (ImGui::RadioButton("CW", demod == 5) && demod != 5) { demod = 5; };
ImGui::NextColumn(); ImGui::NextColumn();
if (ImGui::RadioButton("LSB", demod == 6) && demod != 6) { if (ImGui::RadioButton("LSB", demod == 6) && demod != 6) {
sigPath.setDemodulator(SignalPath::DEMOD_LSB); sigPath.setDemodulator(SignalPath::DEMOD_LSB);
demod = 6; demod = 6;
wtf.setVFOBandwidth(3000); vfo->setBandwidth(3000);
wtf.setVFOReference(ImGui::WaterFall::REF_UPPER); vfo->setReference(ImGui::WaterFall::REF_UPPER);
} }
if (ImGui::RadioButton("RAW", demod == 7) && demod != 7) { demod = 7; }; if (ImGui::RadioButton("RAW", demod == 7) && demod != 7) { demod = 7; };
ImGui::Columns(1, "EndRadioModeColumns", false); ImGui::Columns(1, "EndRadioModeColumns", false);
//ImGui::InputInt("Frequency (kHz)", &freq);
ImGui::Checkbox("DC Bias Removal", &dcbias.val); ImGui::Checkbox("DC Bias Removal", &dcbias.val);
ImGui::EndGroup(); ImGui::EndGroup();
@ -363,6 +387,17 @@ void drawWindow() {
if(ImGui::CollapsingHeader("Debug")) { if(ImGui::CollapsingHeader("Debug")) {
ImGui::Text("Frame time: %.3f ms/frame", 1000.0f / ImGui::GetIO().Framerate); ImGui::Text("Frame time: %.3f ms/frame", 1000.0f / ImGui::GetIO().Framerate);
ImGui::Text("Framerate: %.1f FPS", 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(); ImGui::EndChild();
@ -391,7 +426,7 @@ void drawWindow() {
if (bw.changed()) { if (bw.changed()) {
wtf.setViewBandwidth(bw.val); wtf.setViewBandwidth(bw.val);
wtf.setViewOffset(wtf.getVFOOfset()); wtf.setViewOffset(vfo->centerOffset);
} }
wtf.setFFTMin(fftMin); wtf.setFFTMin(fftMin);

5
src/vfo_manager.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
namespace vfoman {
};

View File

@ -173,38 +173,35 @@ namespace ImGui {
ImVec2(widgetPos.x + 50 + dataWidth, widgetPos.y + fftHeight + 51 + waterfallHeight)); ImVec2(widgetPos.x + 50 + dataWidth, widgetPos.y + fftHeight + 51 + waterfallHeight));
} }
void WaterFall::drawVFO() { void WaterFall::drawVFOs() {
float width = (vfoBandwidth / viewBandwidth) * (float)dataWidth; for (auto const& [name, vfo] : vfos) {
int center = roundf((((vfoOffset - viewOffset) / (viewBandwidth / 2.0f)) + 1.0f) * ((float)dataWidth / 2.0f)); if (vfo->redrawRequired) {
int left; vfo->redrawRequired = false;
int right; vfo->updateDrawingVars(viewBandwidth, dataWidth, viewOffset, widgetPos, fftHeight);
}
vfo->draw(window, name == selectedVFO);
}
}
void WaterFall::processInputs() {
ImVec2 mousePos = ImGui::GetMousePos(); ImVec2 mousePos = ImGui::GetMousePos();
ImVec2 drag = ImGui::GetMouseDragDelta(ImGuiMouseButton_Left); ImVec2 drag = ImGui::GetMouseDragDelta(ImGuiMouseButton_Left);
ImVec2 dragOrigin(mousePos.x - drag.x, mousePos.y - drag.y); 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); bool freqDrag = ImGui::IsMouseDragging(ImGuiMouseButton_Left) && IS_IN_AREA(dragOrigin, freqAreaMin, freqAreaMax);
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && IS_IN_AREA(mousePos, fftAreaMin, fftAreaMax) && !freqDrag) { // TODO: Process VFO drag
int refCenter = mousePos.x - (widgetPos.x + 50);
if (refCenter >= 0 && refCenter < dataWidth && mousePos.y > widgetPos.y && mousePos.y < (widgetPos.y + widgetSize.y)) { // if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && IS_IN_AREA(mousePos, fftAreaMin, fftAreaMax) && !freqDrag) {
vfoOffset = ((((float)refCenter / ((float)dataWidth / 2.0f)) - 1.0f) * (viewBandwidth / 2.0f)) + viewOffset; // int refCenter = mousePos.x - (widgetPos.x + 50);
center = refCenter; // 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; // }
} // 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;
// } // }
if (freqDrag) { if (freqDrag) {
@ -234,35 +231,6 @@ namespace ImGui {
else { else {
lastDrag = 0; 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<int>(left, 0, dataWidth - 1);
right = std::clamp<int>(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() { void WaterFall::updateWaterfallFb() {
@ -382,6 +350,7 @@ namespace ImGui {
vRange = 10.0f; vRange = 10.0f;
updateWaterfallFb(); updateWaterfallFb();
updateAllVFOs();
} }
void WaterFall::draw() { void WaterFall::draw() {
@ -408,9 +377,11 @@ namespace ImGui {
window->DrawList->AddRect(widgetPos, widgetEndPos, IM_COL32( 50, 50, 50, 255 )); 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); 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(); drawFFT();
drawWaterfall(); drawWaterfall();
drawVFO(); drawVFOs();
if (bandplan != NULL) { if (bandplan != NULL) {
drawBandPlan(); drawBandPlan();
} }
@ -475,6 +446,7 @@ namespace ImGui {
centerFreq = freq; centerFreq = freq;
lowerFreq = (centerFreq + viewOffset) - (viewBandwidth / 2.0f); lowerFreq = (centerFreq + viewOffset) - (viewBandwidth / 2.0f);
upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0f); upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0f);
updateAllVFOs();
} }
float WaterFall::getCenterFrequency() { float WaterFall::getCenterFrequency() {
@ -485,35 +457,13 @@ namespace ImGui {
float currentRatio = viewBandwidth / wholeBandwidth; float currentRatio = viewBandwidth / wholeBandwidth;
wholeBandwidth = bandWidth; wholeBandwidth = bandWidth;
setViewBandwidth(bandWidth * currentRatio); setViewBandwidth(bandWidth * currentRatio);
updateAllVFOs();
} }
float WaterFall::getBandwidth() { float WaterFall::getBandwidth() {
return wholeBandwidth; 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) { void WaterFall::setViewBandwidth(float bandWidth) {
if (bandWidth == viewBandwidth) { if (bandWidth == viewBandwidth) {
return; return;
@ -531,6 +481,7 @@ namespace ImGui {
upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0f); upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0f);
range = findBestRange(bandWidth, maxHSteps); range = findBestRange(bandWidth, maxHSteps);
updateWaterfallFb(); updateWaterfallFb();
updateAllVFOs();
} }
float WaterFall::getViewBandwidth() { float WaterFall::getViewBandwidth() {
@ -551,6 +502,7 @@ namespace ImGui {
lowerFreq = (centerFreq + viewOffset) - (viewBandwidth / 2.0f); lowerFreq = (centerFreq + viewOffset) - (viewBandwidth / 2.0f);
upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0f); upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0f);
updateWaterfallFb(); updateWaterfallFb();
updateAllVFOs();
} }
float WaterFall::getViewOffset() { float WaterFall::getViewOffset() {
@ -598,5 +550,130 @@ namespace ImGui {
float WaterFall::getWaterfallMax() { float WaterFall::getWaterfallMax() {
return waterfallMax; 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<int>(left, 0, dataWidth - 1);
right = std::clamp<int>(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));
}
};
}; };

View File

@ -12,6 +12,41 @@
namespace ImGui { 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 { class WaterFall {
public: public:
WaterFall(); WaterFall();
@ -27,14 +62,6 @@ namespace ImGui {
void setBandwidth(float bandWidth); void setBandwidth(float bandWidth);
float getBandwidth(); float getBandwidth();
void setVFOOffset(float offset);
float getVFOOfset();
void setVFOBandwidth(float bandwidth);
float getVFOBandwidth();
void setVFOReference(int ref);
void setViewBandwidth(float bandWidth); void setViewBandwidth(float bandWidth);
float getViewBandwidth(); float getViewBandwidth();
@ -63,6 +90,9 @@ namespace ImGui {
bool bandplanEnabled = false; bool bandplanEnabled = false;
bandplan::BandPlan_t* bandplan = NULL; bandplan::BandPlan_t* bandplan = NULL;
std::map<std::string, WaterfallVFO*> vfos;
std::string selectedVFO;
enum { enum {
REF_LOWER, REF_LOWER,
REF_CENTER, REF_CENTER,
@ -74,12 +104,14 @@ namespace ImGui {
private: private:
void drawWaterfall(); void drawWaterfall();
void drawFFT(); void drawFFT();
void drawVFO(); void drawVFOs();
void drawBandPlan(); void drawBandPlan();
void processInputs();
void onPositionChange(); void onPositionChange();
void onResize(); void onResize();
void updateWaterfallFb(); void updateWaterfallFb();
void updateWaterfallTexture(); void updateWaterfallTexture();
void updateAllVFOs();
bool waterfallUpdate = false; bool waterfallUpdate = false;
@ -129,10 +161,6 @@ namespace ImGui {
float centerFreq; float centerFreq;
float wholeBandwidth; float wholeBandwidth;
// VFO
float vfoOffset;
float vfoBandwidth;
// Ranges // Ranges
float fftMin; float fftMin;
float fftMax; float fftMax;