From ce75eed995abfc675ec9041bb1e6afeb20ac9591 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 1 Jan 2015 21:10:54 -0500 Subject: [PATCH] Experimental waterfall zoom --- src/AppFrame.cpp | 2 + src/visual/SpectrumCanvas.cpp | 43 ++++++-- src/visual/SpectrumCanvas.h | 5 + src/visual/WaterfallCanvas.cpp | 173 +++++++++++++++++++++------------ src/visual/WaterfallCanvas.h | 2 + 5 files changed, 153 insertions(+), 72 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 9dae70d..0f6d918 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -79,6 +79,7 @@ AppFrame::AppFrame() : demodWaterfallCanvas->Setup(1024, 256); demodWaterfallCanvas->SetView(DEFAULT_FREQ, 300000); demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas); + demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas); demodVisuals->Add(demodWaterfallCanvas, 3, wxEXPAND | wxALL, 0); demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0); @@ -103,6 +104,7 @@ AppFrame::AppFrame() : waterfallCanvas = new WaterfallCanvas(this, NULL); waterfallCanvas->Setup(2048, 512); waterfallCanvas->attachSpectrumCanvas(spectrumCanvas); + spectrumCanvas->attachWaterfallCanvas(waterfallCanvas); vbox->Add(waterfallCanvas, 4, wxEXPAND | wxALL, 0); this->SetSizer(vbox); diff --git a/src/visual/SpectrumCanvas.cpp b/src/visual/SpectrumCanvas.cpp index 6b9708e..69a23a6 100644 --- a/src/visual/SpectrumCanvas.cpp +++ b/src/visual/SpectrumCanvas.cpp @@ -15,6 +15,7 @@ #include "AppFrame.h" #include #include +#include "WaterfallCanvas.h" wxBEGIN_EVENT_TABLE(SpectrumCanvas, wxGLCanvas) EVT_PAINT(SpectrumCanvas::OnPaint) EVT_IDLE(SpectrumCanvas::OnIdle) @@ -27,7 +28,8 @@ wxEND_EVENT_TABLE() SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) : wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, - wxFULL_REPAINT_ON_RESIZE), parent(parent), fft_size(0), in(NULL), out(NULL), plan(NULL), center_freq(0), bandwidth(0), isView(0) { + wxFULL_REPAINT_ON_RESIZE), parent(parent), fft_size(0), in(NULL), out(NULL), plan(NULL), waterfallCanvas(NULL), center_freq(0), bandwidth(0), isView( + 0) { glContext = new SpectrumContext(this, &wxGetApp().GetContext(this)); @@ -57,7 +59,6 @@ void SpectrumCanvas::Setup(int fft_size_in) { } plan = fftw_plan_dft_1d(fft_size, in, out, FFTW_FORWARD, FFTW_MEASURE); - fft_ceil_ma = fft_ceil_maa = 100.0; fft_floor_ma = fft_floor_maa = 0.0; } @@ -171,8 +172,6 @@ void SpectrumCanvas::setData(DemodulatorThreadIQData *input) { } } - - void SpectrumCanvas::SetView(int center_freq_in, int bandwidth_in) { isView = true; center_freq = center_freq_in; @@ -181,7 +180,10 @@ void SpectrumCanvas::SetView(int center_freq_in, int bandwidth_in) { void SpectrumCanvas::DisableView() { isView = false; + center_freq = wxGetApp().getFrequency(); + bandwidth = SRATE; } + void SpectrumCanvas::SetCenterFrequency(unsigned int center_freq_in) { center_freq = center_freq_in; } @@ -217,12 +219,32 @@ void SpectrumCanvas::mouseMoved(wxMouseEvent& event) { if (freqChange != 0) { int freq = wxGetApp().getFrequency(); - freq -= freqChange; - wxGetApp().setFrequency(freq); - ((wxFrame*) parent)->GetStatusBar()->SetStatusText( - wxString::Format(wxT("Set center frequency: %s"), - wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep))); + if (isView) { + center_freq -= freqChange; + if (waterfallCanvas) { + waterfallCanvas->SetCenterFrequency(center_freq); + } + + if (SRATE/2 < (abs(freq-center_freq)+bandwidth/2)) { +// if (center_freq < freq) { +// freqChange = -((center_freq - (freq - bandwidth / 2)) - (SRATE/2)); +// } else { +// freqChange = ((freq + bandwidth / 2) - center_freq - (SRATE/2)); +// } + } else { + freqChange = 0; + } + } + + if (freqChange) { + freq -= freqChange; + wxGetApp().setFrequency(freq); + ((wxFrame*) parent)->GetStatusBar()->SetStatusText( + wxString::Format(wxT("Set center frequency: %s"), + wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep))); + } + } } } @@ -246,6 +268,9 @@ void SpectrumCanvas::mouseLeftWindow(wxMouseEvent& event) { SetCursor(wxCURSOR_SIZEWE); } +void SpectrumCanvas::attachWaterfallCanvas(WaterfallCanvas* canvas_in) { + waterfallCanvas = canvas_in; +} //void SpectrumCanvas::rightClick(wxMouseEvent& event) {} //void SpectrumCanvas::keyPressed(wxKeyEvent& event) {} //void SpectrumCanvas::keyReleased(wxKeyEvent& event) {} diff --git a/src/visual/SpectrumCanvas.h b/src/visual/SpectrumCanvas.h index 41b1a48..45e2d67 100644 --- a/src/visual/SpectrumCanvas.h +++ b/src/visual/SpectrumCanvas.h @@ -11,6 +11,8 @@ #include "fftw3.h" #include "MouseTracker.h" +class WaterfallCanvas; + class SpectrumCanvas: public wxGLCanvas { public: std::vector spectrum_points; @@ -30,6 +32,8 @@ public: void SetBandwidth(unsigned int bandwidth_in); unsigned int GetBandwidth(); + void attachWaterfallCanvas(WaterfallCanvas *canvas_in); + private: void OnPaint(wxPaintEvent& event); @@ -56,6 +60,7 @@ private: std::vector fft_result_maa; SpectrumContext *glContext; + WaterfallCanvas *waterfallCanvas; int fft_size; unsigned int center_freq; diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 19078c2..62de81f 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -35,7 +35,7 @@ WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) : wxFULL_REPAINT_ON_RESIZE), parent(parent), spectrumCanvas(NULL), activeDemodulatorBandwidth(0), activeDemodulatorFrequency(0), dragState( WF_DRAG_NONE), nextDragState(WF_DRAG_NONE), shiftDown(false), altDown(false), ctrlDown(false), fft_size(0), waterfall_lines(0), plan( NULL), in(NULL), out(NULL), center_freq(0), bandwidth(0), isView(false), resampler(NULL), resample_ratio(0), last_bandwidth(0), last_input_bandwidth( - 0) { + 0), zoom(0) { glContext = new WaterfallContext(this, &wxGetApp().GetContext(this)); @@ -62,6 +62,9 @@ void WaterfallCanvas::SetView(int center_freq_in, int bandwidth_in) { void WaterfallCanvas::DisableView() { isView = false; + center_freq = wxGetApp().getFrequency(); + bandwidth = SRATE; + last_bandwidth = 0; } void WaterfallCanvas::Setup(int fft_size_in, int waterfall_lines_in) { @@ -221,8 +224,14 @@ void WaterfallCanvas::OnKeyUp(wxKeyEvent& event) { shiftDown = event.ShiftDown(); altDown = event.AltDown(); ctrlDown = event.ControlDown(); -// switch (event.GetKeyCode()) { -// } + switch (event.GetKeyCode()) { + case 'A': + zoom = 0; + break; + case 'Z': + zoom = 0; + break; + } } void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { @@ -235,60 +244,65 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator(); unsigned int freq; - if (!isView) { - switch (event.GetKeyCode()) { - case WXK_RIGHT: - freq = wxGetApp().getFrequency(); - if (shiftDown) { - freq += SRATE * 10; - } else { - freq += SRATE / 2; - } - wxGetApp().setFrequency(freq); - ((wxFrame*) parent)->GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %i"), freq)); - break; - case WXK_LEFT: - freq = wxGetApp().getFrequency(); - if (shiftDown) { - freq -= SRATE * 10; - } else { - freq -= SRATE / 2; - } - wxGetApp().setFrequency(freq); - ((wxFrame*) parent)->GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %i"), freq)); - break; - case 'D': - case WXK_DELETE: - if (!activeDemod) { - break; - } - wxGetApp().removeDemodulator(activeDemod); - wxGetApp().getDemodMgr().deleteThread(activeDemod); - break; - case 'S': - if (!activeDemod) { - break; - } - if (activeDemod->isSquelchEnabled()) { - activeDemod->setSquelchEnabled(false); - } else { - activeDemod->squelchAuto(); - } - break; - case WXK_SPACE: - if (!activeDemod) { - break; - } - if (activeDemod->isStereo()) { - activeDemod->setStereo(false); - } else { - activeDemod->setStereo(true); - } - break; - default: - event.Skip(); - return; + unsigned int bw; + switch (event.GetKeyCode()) { + case 'A': + zoom = 1; + break; + case 'Z': + zoom = -1; + break; + case WXK_RIGHT: + freq = wxGetApp().getFrequency(); + if (shiftDown) { + freq += SRATE * 10; + } else { + freq += SRATE / 2; } + wxGetApp().setFrequency(freq); + ((wxFrame*) parent)->GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %i"), freq)); + break; + case WXK_LEFT: + freq = wxGetApp().getFrequency(); + if (shiftDown) { + freq -= SRATE * 10; + } else { + freq -= SRATE / 2; + } + wxGetApp().setFrequency(freq); + ((wxFrame*) parent)->GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %i"), freq)); + break; + case 'D': + case WXK_DELETE: + if (!activeDemod) { + break; + } + wxGetApp().removeDemodulator(activeDemod); + wxGetApp().getDemodMgr().deleteThread(activeDemod); + break; + case 'S': + if (!activeDemod) { + break; + } + if (activeDemod->isSquelchEnabled()) { + activeDemod->setSquelchEnabled(false); + } else { + activeDemod->squelchAuto(); + } + break; + case WXK_SPACE: + if (!activeDemod) { + break; + } + if (activeDemod->isStereo()) { + activeDemod->setStereo(false); + } else { + activeDemod->setStereo(true); + } + break; + default: + event.Skip(); + return; } } @@ -297,16 +311,49 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) { return; } + unsigned int bw; + if (zoom) { + if (zoom > 0) { + center_freq = GetCenterFrequency(); + bw = GetBandwidth(); + bw = (unsigned int) ceil((float) bw * 0.95); + if (bw < 80000) { + bw = 80000; + } + SetView(center_freq, bw); + if (spectrumCanvas) { + spectrumCanvas->SetView(center_freq, bw); + } + } else { + if (isView) { + bw = GetBandwidth(); + bw = (unsigned int) ceil((float) bw * 1.05); + if ((int) bw >= SRATE) { + bw = (unsigned int) SRATE; + DisableView(); + if (spectrumCanvas) { + spectrumCanvas->DisableView(); + } + } else { + SetView(GetCenterFrequency(), bw); + if (spectrumCanvas) { + spectrumCanvas->SetView(center_freq, bw); + } + } + } + } + } + std::vector *data = &input->data; if (data && data->size()) { - if (fft_size != data->size() && !isView) { - Setup(data->size(), waterfall_lines); - } +// if (fft_size != data->size() && !isView) { +// Setup(data->size(), waterfall_lines); +// } - if (last_bandwidth != bandwidth && !isView) { - Setup(bandwidth, waterfall_lines); - } +// if (last_bandwidth != bandwidth && !isView) { +// Setup(bandwidth, waterfall_lines); +// } if (spectrum_points.size() < fft_size * 2) { spectrum_points.resize(fft_size * 2); @@ -356,7 +403,7 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) { last_input_bandwidth = input->bandwidth; } - int out_size = ceil((double) (input->data.size()) * resample_ratio) + 32; + int out_size = ceil((double) (input->data.size()) * resample_ratio) + 512; if (resampler_buffer.size() != out_size) { if (resampler_buffer.capacity() < out_size) { diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index 556d50c..582109c 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -95,6 +95,8 @@ private: int last_input_bandwidth; int last_bandwidth; + int zoom; + std::vector shift_buffer; std::vector resampler_buffer;