mirror of
				https://github.com/AlexandreRouma/SDRPlusPlus.git
				synced 2025-10-31 00:48:11 +01:00 
			
		
		
		
	multi-vfo
This commit is contained in:
		| @@ -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; | ||||
|    } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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<bool> dcbias(false, false); | ||||
| watcher<bool> 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); | ||||
|   | ||||
							
								
								
									
										5
									
								
								src/vfo_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/vfo_manager.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| #pragma once | ||||
|  | ||||
| namespace vfoman { | ||||
|      | ||||
| }; | ||||
| @@ -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<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() { | ||||
| @@ -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<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)); | ||||
|         } | ||||
|     }; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -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<std::string, WaterfallVFO*> 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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user