spectrogram decimation
This commit is contained in:
@@ -702,6 +702,7 @@ void Application::loadConfig() {
|
|||||||
cursors_.snapToPeaks = config_.getBool("snap_to_peaks", cursors_.snapToPeaks);
|
cursors_.snapToPeaks = config_.getBool("snap_to_peaks", cursors_.snapToPeaks);
|
||||||
measurements_.traceMinFreq = config_.getFloat("trace_min_freq", measurements_.traceMinFreq);
|
measurements_.traceMinFreq = config_.getFloat("trace_min_freq", measurements_.traceMinFreq);
|
||||||
measurements_.traceMaxFreq = config_.getFloat("trace_max_freq", measurements_.traceMaxFreq);
|
measurements_.traceMaxFreq = config_.getFloat("trace_max_freq", measurements_.traceMaxFreq);
|
||||||
|
ui_.specMinPixPerBin = config_.getInt("spec_min_pix_per_bin", ui_.specMinPixPerBin);
|
||||||
|
|
||||||
// Clamp
|
// Clamp
|
||||||
controlPanel_.fftSizeIdx = std::clamp(controlPanel_.fftSizeIdx, 0, ControlPanel::kNumFFTSizes - 1);
|
controlPanel_.fftSizeIdx = std::clamp(controlPanel_.fftSizeIdx, 0, ControlPanel::kNumFFTSizes - 1);
|
||||||
@@ -766,6 +767,7 @@ void Application::saveConfig() const {
|
|||||||
cfg.setBool("snap_to_peaks", cursors_.snapToPeaks);
|
cfg.setBool("snap_to_peaks", cursors_.snapToPeaks);
|
||||||
cfg.setFloat("trace_min_freq", measurements_.traceMinFreq);
|
cfg.setFloat("trace_min_freq", measurements_.traceMinFreq);
|
||||||
cfg.setFloat("trace_max_freq", measurements_.traceMaxFreq);
|
cfg.setFloat("trace_max_freq", measurements_.traceMaxFreq);
|
||||||
|
cfg.setInt("spec_min_pix_per_bin", ui_.specMinPixPerBin);
|
||||||
|
|
||||||
int devIdx = audio_.deviceIdx();
|
int devIdx = audio_.deviceIdx();
|
||||||
if (devIdx >= 0 && devIdx < static_cast<int>(devices.size()))
|
if (devIdx >= 0 && devIdx < static_cast<int>(devices.size()))
|
||||||
|
|||||||
@@ -178,6 +178,15 @@ void ControlPanel::render(AudioEngine& audio, UIState& ui,
|
|||||||
}
|
}
|
||||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Reset to 2x zoom");
|
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Reset to 2x zoom");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text("Decim:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
|
ImGui::SliderInt("##decimation", &ui.specMinPixPerBin, 1, 8, "%d px/bin");
|
||||||
|
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Spectrum frequency decimation (peak-detect)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Channels ──
|
// ── Channels ──
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ void DisplayPanel::renderSpectrum(AudioEngine& audio, UIState& ui,
|
|||||||
specDisplay.draw(allSpectraScratch_, stylesScratch_, ui.minDB, ui.maxDB,
|
specDisplay.draw(allSpectraScratch_, stylesScratch_, ui.minDB, ui.maxDB,
|
||||||
settings.sampleRate, settings.isIQ, ui.freqScale,
|
settings.sampleRate, settings.isIQ, ui.freqScale,
|
||||||
specPosX, specPosY, specSizeX, specSizeY,
|
specPosX, specPosY, specSizeX, specSizeY,
|
||||||
ui.viewLo, ui.viewHi);
|
ui.viewLo, ui.viewHi, ui.specMinPixPerBin);
|
||||||
|
|
||||||
cursors.draw(specDisplay, specPosX, specPosY, specSizeX, specSizeY,
|
cursors.draw(specDisplay, specPosX, specPosY, specSizeX, specSizeY,
|
||||||
settings.sampleRate, settings.isIQ, ui.freqScale, ui.minDB, ui.maxDB,
|
settings.sampleRate, settings.isIQ, ui.freqScale, ui.minDB, ui.maxDB,
|
||||||
|
|||||||
@@ -60,9 +60,11 @@ static void buildPolyline(const std::vector<float>& spectrumDB,
|
|||||||
bool isIQ, FreqScale freqScale,
|
bool isIQ, FreqScale freqScale,
|
||||||
float posX, float posY, float sizeX, float sizeY,
|
float posX, float posY, float sizeX, float sizeY,
|
||||||
float viewLo, float viewHi,
|
float viewLo, float viewHi,
|
||||||
std::vector<ImVec2>& outPoints) {
|
std::vector<ImVec2>& outPoints,
|
||||||
|
int minPixPerBin = 1) {
|
||||||
int bins = static_cast<int>(spectrumDB.size());
|
int bins = static_cast<int>(spectrumDB.size());
|
||||||
int displayPts = std::min(bins, static_cast<int>(sizeX));
|
int maxPts = std::max(1, static_cast<int>(sizeX) / std::max(1, minPixPerBin));
|
||||||
|
int displayPts = std::min(bins, maxPts);
|
||||||
if (displayPts < 2) displayPts = 2;
|
if (displayPts < 2) displayPts = 2;
|
||||||
|
|
||||||
outPoints.resize(displayPts);
|
outPoints.resize(displayPts);
|
||||||
@@ -108,7 +110,8 @@ void SpectrumDisplay::draw(const std::vector<std::vector<float>>& spectra,
|
|||||||
FreqScale freqScale,
|
FreqScale freqScale,
|
||||||
float posX, float posY,
|
float posX, float posY,
|
||||||
float sizeX, float sizeY,
|
float sizeX, float sizeY,
|
||||||
float viewLo, float viewHi) const {
|
float viewLo, float viewHi,
|
||||||
|
int minPixPerBin) const {
|
||||||
if (spectra.empty() || spectra[0].empty() || sizeX <= 0 || sizeY <= 0) return;
|
if (spectra.empty() || spectra[0].empty() || sizeX <= 0 || sizeY <= 0) return;
|
||||||
|
|
||||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||||
@@ -178,7 +181,7 @@ void SpectrumDisplay::draw(const std::vector<std::vector<float>>& spectra,
|
|||||||
if (spectra[ch].empty()) continue;
|
if (spectra[ch].empty()) continue;
|
||||||
buildPolyline(spectra[ch], minDB, maxDB,
|
buildPolyline(spectra[ch], minDB, maxDB,
|
||||||
isIQ, freqScale, posX, posY, sizeX, sizeY,
|
isIQ, freqScale, posX, posY, sizeX, sizeY,
|
||||||
viewLo, viewHi, allPoints[ch]);
|
viewLo, viewHi, allPoints[ch], minPixPerBin);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw spectra: all fills first, then all lines on top.
|
// Draw spectra: all fills first, then all lines on top.
|
||||||
@@ -237,7 +240,7 @@ void SpectrumDisplay::draw(const std::vector<std::vector<float>>& spectra,
|
|||||||
ImU32 col = (st.lineColor & 0x00FFFFFF) | 0x90000000;
|
ImU32 col = (st.lineColor & 0x00FFFFFF) | 0x90000000;
|
||||||
buildPolyline(peakHold_[ch], minDB, maxDB,
|
buildPolyline(peakHold_[ch], minDB, maxDB,
|
||||||
isIQ, freqScale, posX, posY, sizeX, sizeY,
|
isIQ, freqScale, posX, posY, sizeX, sizeY,
|
||||||
viewLo, viewHi, phPoints);
|
viewLo, viewHi, phPoints, minPixPerBin);
|
||||||
if (phPoints.size() >= 2)
|
if (phPoints.size() >= 2)
|
||||||
dl->AddPolyline(phPoints.data(), static_cast<int>(phPoints.size()),
|
dl->AddPolyline(phPoints.data(), static_cast<int>(phPoints.size()),
|
||||||
col, ImDrawFlags_None, 1.0f);
|
col, ImDrawFlags_None, 1.0f);
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ public:
|
|||||||
double sampleRate, bool isIQ,
|
double sampleRate, bool isIQ,
|
||||||
FreqScale freqScale,
|
FreqScale freqScale,
|
||||||
float posX, float posY, float sizeX, float sizeY,
|
float posX, float posY, float sizeX, float sizeY,
|
||||||
float viewLo = 0.0f, float viewHi = 1.0f) const;
|
float viewLo = 0.0f, float viewHi = 1.0f,
|
||||||
|
int minPixPerBin = 1) const;
|
||||||
|
|
||||||
// Convenience: single-channel draw (backward compat).
|
// Convenience: single-channel draw (backward compat).
|
||||||
void draw(const std::vector<float>& spectrumDB,
|
void draw(const std::vector<float>& spectrumDB,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ struct UIState {
|
|||||||
|
|
||||||
int waterfallChannel = 0;
|
int waterfallChannel = 0;
|
||||||
bool waterfallMultiCh = true;
|
bool waterfallMultiCh = true;
|
||||||
|
int specMinPixPerBin = 1; // min screen pixels per spectrum bin (1 = no decimation)
|
||||||
std::array<bool, kMaxChannels> channelEnabled = {true,true,true,true,true,true,true,true};
|
std::array<bool, kMaxChannels> channelEnabled = {true,true,true,true,true,true,true,true};
|
||||||
// Complementary pairs: colors at indices 0+1, 2+3, 4+5, 6+7 sum to white.
|
// Complementary pairs: colors at indices 0+1, 2+3, 4+5, 6+7 sum to white.
|
||||||
std::array<ImVec4, kMaxChannels> channelColors = {{
|
std::array<ImVec4, kMaxChannels> channelColors = {{
|
||||||
|
|||||||
Reference in New Issue
Block a user