diff --git a/CMakeLists.txt b/CMakeLists.txt index f2f72e9..209f2a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,7 +262,6 @@ SET (cubicsdr_sources src/process/VisualProcessor.cpp src/process/ScopeVisualProcessor.cpp src/process/SpectrumVisualProcessor.cpp - src/process/WaterfallVisualProcessor.cpp src/ui/GLPanel.cpp external/rtaudio/RtAudio.cpp external/lodepng/lodepng.cpp @@ -315,7 +314,6 @@ SET (cubicsdr_headers src/process/VisualProcessor.h src/process/ScopeVisualProcessor.h src/process/SpectrumVisualProcessor.h - src/process/WaterfallVisualProcessor.h src/ui/GLPanel.h src/ui/UITestCanvas.cpp src/ui/UITestCanvas.h diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index ea7910f..d758322 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -64,10 +64,11 @@ AppFrame::AppFrame() : // demodTray->AddSpacer(2); + wxGetApp().getDemodSpectrumProcesor()->setup(1024); demodSpectrumCanvas = new SpectrumCanvas(this, attribList); - demodSpectrumCanvas->setup(1024); demodSpectrumCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000); demodVisuals->Add(demodSpectrumCanvas, 3, wxEXPAND | wxALL, 0); + wxGetApp().getDemodSpectrumProcesor()->attachOutput(demodSpectrumCanvas->getVisualDataQueue()); demodVisuals->AddSpacer(1); @@ -77,6 +78,7 @@ AppFrame::AppFrame() : demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas); demodSpectrumCanvas->attachWaterfallCanvas(demodWaterfallCanvas); demodVisuals->Add(demodWaterfallCanvas, 6, wxEXPAND | wxALL, 0); + wxGetApp().getDemodSpectrumProcesor()->attachOutput(demodWaterfallCanvas->getVisualDataQueue()); demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0); @@ -110,17 +112,19 @@ AppFrame::AppFrame() : vbox->Add(demodTray, 12, wxEXPAND | wxALL, 0); vbox->AddSpacer(1); + + wxGetApp().getSpectrumProcesor()->setup(2048); spectrumCanvas = new SpectrumCanvas(this, attribList); - spectrumCanvas->setup(2048); vbox->Add(spectrumCanvas, 5, wxEXPAND | wxALL, 0); vbox->AddSpacer(1); + wxGetApp().getSpectrumProcesor()->attachOutput(spectrumCanvas->getVisualDataQueue()); + waterfallCanvas = new WaterfallCanvas(this, attribList); waterfallCanvas->setup(2048, 512); waterfallCanvas->attachSpectrumCanvas(spectrumCanvas); - waterfallCanvas->attachWaterfallCanvas(demodWaterfallCanvas); spectrumCanvas->attachWaterfallCanvas(waterfallCanvas); vbox->Add(waterfallCanvas, 20, wxEXPAND | wxALL, 0); - + wxGetApp().getSpectrumProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue()); /* vbox->AddSpacer(1); testCanvas = new UITestCanvas(this, attribList); @@ -674,7 +678,26 @@ void AppFrame::OnIdle(wxIdleEvent& event) { } scopeCanvas->setPPMMode(demodTuner->isAltDown()); - + + + wxGetApp().getSpectrumDistributor()->run(); + + SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcesor(); + + proc->setView(waterfallCanvas->getViewState()); + proc->setBandwidth(waterfallCanvas->getBandwidth()); + proc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); + + proc->run(); + + SpectrumVisualProcessor *dproc = wxGetApp().getDemodSpectrumProcesor(); + + dproc->setView(demodWaterfallCanvas->getViewState()); + dproc->setBandwidth(demodWaterfallCanvas->getBandwidth()); + dproc->setCenterFrequency(demodWaterfallCanvas->getCenterFrequency()); + + dproc->run(); + event.Skip(); } diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index f17cec3..3033b6e 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -54,6 +54,20 @@ bool CubicSDR::OnInit() { // Visual Data pipeIQVisualData = new DemodulatorThreadInputQueue(); pipeIQVisualData->set_max_num_items(1); + + spectrumDistributor.setInput(pipeIQVisualData); + + pipeDemodIQVisualData = new DemodulatorThreadInputQueue(); + pipeIQVisualData->set_max_num_items(1); + + pipeSpectrumIQVisualData = new DemodulatorThreadInputQueue(); + pipeIQVisualData->set_max_num_items(1); + + spectrumDistributor.attachOutput(pipeDemodIQVisualData); + spectrumDistributor.attachOutput(pipeSpectrumIQVisualData); + + demodSpectrumProcessor.setInput(pipeDemodIQVisualData); + spectrumProcessor.setInput(pipeSpectrumIQVisualData); pipeAudioVisualData = new DemodulatorThreadOutputQueue(); pipeAudioVisualData->set_max_num_items(1); @@ -254,6 +268,19 @@ ScopeVisualProcessor *CubicSDR::getScopeProcessor() { return &scopeProcessor; } +SpectrumVisualProcessor *CubicSDR::getSpectrumProcesor() { + return &spectrumProcessor; +} + +SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcesor() { + return &demodSpectrumProcessor; +} + +VisualDataDistributor *CubicSDR::getSpectrumDistributor() { + return &spectrumDistributor; +} + + DemodulatorThreadOutputQueue* CubicSDR::getAudioVisualQueue() { return pipeAudioVisualData; } diff --git a/src/CubicSDR.h b/src/CubicSDR.h index 6d4c4c8..c20d522 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -16,7 +16,9 @@ #include "DemodulatorMgr.h" #include "AppConfig.h" #include "AppFrame.h" + #include "ScopeVisualProcessor.h" +#include "SpectrumVisualProcessor.h" #include @@ -54,6 +56,9 @@ public: int getDevice(); ScopeVisualProcessor *getScopeProcessor(); + SpectrumVisualProcessor *getSpectrumProcesor(); + SpectrumVisualProcessor *getDemodSpectrumProcesor(); + VisualDataDistributor *getSpectrumDistributor(); DemodulatorThreadOutputQueue* getAudioVisualQueue(); DemodulatorThreadInputQueue* getIQVisualQueue(); @@ -94,8 +99,14 @@ private: SDRThreadIQDataQueue* pipeSDRIQData; DemodulatorThreadInputQueue* pipeIQVisualData; DemodulatorThreadOutputQueue* pipeAudioVisualData; + DemodulatorThreadInputQueue* pipeDemodIQVisualData; + DemodulatorThreadInputQueue* pipeSpectrumIQVisualData; ScopeVisualProcessor scopeProcessor; + SpectrumVisualProcessor spectrumProcessor; + SpectrumVisualProcessor demodSpectrumProcessor; + + VisualDataDistributor spectrumDistributor; std::thread *t_SDR; std::thread *t_PostSDR; diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index c92f5b5..d308327 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -1,7 +1,7 @@ #include "DemodulatorInstance.h" DemodulatorInstance::DemodulatorInstance() : - t_PreDemod(NULL), pipeIQInputData(NULL), demodulatorThread(NULL), t_Demod(NULL), t_Audio(NULL), currentAudioGain(1.0) { + t_PreDemod(NULL), t_Demod(NULL), t_Audio(NULL) { terminated.store(true); audioTerminated.store(true); @@ -16,7 +16,7 @@ DemodulatorInstance::DemodulatorInstance() : currentFrequency.store(0); currentBandwidth.store(0); currentOutputDevice.store(-1); - + currentAudioGain.store(1.0); label = new std::string("Unnamed"); pipeIQInputData = new DemodulatorThreadInputQueue; diff --git a/src/process/SpectrumVisualProcessor.cpp b/src/process/SpectrumVisualProcessor.cpp index dcd99b7..8defddc 100644 --- a/src/process/SpectrumVisualProcessor.cpp +++ b/src/process/SpectrumVisualProcessor.cpp @@ -1,80 +1,284 @@ #include "SpectrumVisualProcessor.h" +#include "CubicSDR.h" + + +SpectrumVisualProcessor::SpectrumVisualProcessor() : lastInputBandwidth(0), lastBandwidth(0), fftwInput(NULL), fftwOutput(NULL), fftInData(NULL), fftLastData(NULL), lastDataSize(0), fftw_plan(NULL), resampler(NULL), resamplerRatio(0) { + + is_view.store(false); + fftSize.store(0); + centerFreq.store(0); + bandwidth.store(0); + + freqShifter = nco_crcf_create(LIQUID_NCO); + shiftFrequency = 0; + + fft_ceil_ma = fft_ceil_maa = 100.0; + fft_floor_ma = fft_floor_maa = 0.0; +} + +SpectrumVisualProcessor::~SpectrumVisualProcessor() { + nco_crcf_destroy(freqShifter); +} + +bool SpectrumVisualProcessor::isView() { + return is_view.load(); +} + +void SpectrumVisualProcessor::setView(bool bView) { + is_view.store(bView); +} + + +void SpectrumVisualProcessor::setCenterFrequency(long long centerFreq_in) { + centerFreq.store(centerFreq_in); +} + +long long SpectrumVisualProcessor::getCenterFrequency() { + return centerFreq.load(); +} + +void SpectrumVisualProcessor::setBandwidth(long bandwidth_in) { + bandwidth.store(bandwidth_in); +} + +long SpectrumVisualProcessor::getBandwidth() { + return bandwidth.load(); +} + +void SpectrumVisualProcessor::setup(int fftSize_in) { + fftSize = fftSize_in; + + if (fftwInput) { + free(fftwInput); + } + fftwInput = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize); + if (fftInData) { + free(fftInData); + } + fftInData = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize); + if (fftLastData) { + free(fftLastData); + } + fftLastData = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize); + if (fftwOutput) { + free(fftwOutput); + } + fftwOutput = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize); + if (fftw_plan) { + fftwf_destroy_plan(fftw_plan); + } + fftw_plan = fftwf_plan_dft_1d(fftSize, fftwInput, fftwOutput, FFTW_FORWARD, FFTW_ESTIMATE); + +} void SpectrumVisualProcessor::process() { - /* - std::vector *data = &input->data; - if (data && data->size()) { - if (fft_size != data->size()) { - setup(data->size()); - } - if (spectrum_points.size() < fft_size * 2) { - if (spectrum_points.capacity() < fft_size * 2) { - spectrum_points.reserve(fft_size * 2); - } - spectrum_points.resize(fft_size * 2); - } - - for (int i = 0; i < fft_size; i++) { - in[i][0] = (*data)[i].real; - in[i][1] = (*data)[i].imag; - } - - fftwf_execute(plan); - - float fft_ceil = 0, fft_floor = 1; - - if (fft_result.size() != fft_size) { - if (fft_result.capacity() < fft_size) { - fft_result.reserve(fft_size); - fft_result_ma.reserve(fft_size); - fft_result_maa.reserve(fft_size); - } - fft_result.resize(fft_size); - fft_result_ma.resize(fft_size); - fft_result_maa.resize(fft_size); - } - - int n; - for (int i = 0, iMax = fft_size / 2; i < iMax; i++) { - float a = out[i][0]; - float b = out[i][1]; - float c = sqrt(a * a + b * b); - - float x = out[fft_size / 2 + i][0]; - float y = out[fft_size / 2 + i][1]; - float z = sqrt(x * x + y * y); - - fft_result[i] = (z); - fft_result[fft_size / 2 + i] = (c); - } - - for (int i = 0, iMax = fft_size; i < iMax; i++) { - fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65; - fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65; - - if (fft_result_maa[i] > fft_ceil) { - fft_ceil = fft_result_maa[i]; - } - if (fft_result_maa[i] < fft_floor) { - fft_floor = fft_result_maa[i]; - } - } - - fft_ceil += 1; - fft_floor -= 1; - - fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.01; - fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.01; - - fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.01; - fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.01; - - for (int i = 0, iMax = fft_size; i < iMax; i++) { - float v = (log10(fft_result_maa[i] - fft_floor_maa) / log10(fft_ceil_maa - fft_floor_maa)); - spectrum_points[i * 2] = ((float) i / (float) iMax); - spectrum_points[i * 2 + 1] = v; - } - - } - */ -} \ No newline at end of file + if (!isOutputEmpty()) { + return; + } + if (!input || input->empty()) { + return; + } + + DemodulatorThreadIQData *iqData; + + input->pop(iqData); + + std::vector *data = &iqData->data; + + if (data && data->size()) { + SpectrumVisualData *output = outputBuffers.getBuffer(); + + if (output->spectrum_points.size() < fftSize * 2) { + output->spectrum_points.resize(fftSize * 2); + } + + unsigned int num_written; + + if (is_view.load()) { + if (!iqData->frequency || !iqData->sampleRate) { + return; + } + + resamplerRatio = (double) (bandwidth) / (double) iqData->sampleRate; + + int desired_input_size = fftSize / resamplerRatio; + + if (iqData->data.size() < desired_input_size) { + // std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl; + desired_input_size = iqData->data.size(); + } + + if (centerFreq != iqData->frequency) { + if ((centerFreq - iqData->frequency) != shiftFrequency || lastInputBandwidth != iqData->sampleRate) { + if (abs(iqData->frequency - centerFreq) < (wxGetApp().getSampleRate() / 2)) { + shiftFrequency = centerFreq - iqData->frequency; + nco_crcf_reset(freqShifter); + nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) iqData->sampleRate))); + } + } + + if (shiftBuffer.size() != desired_input_size) { + if (shiftBuffer.capacity() < desired_input_size) { + shiftBuffer.reserve(desired_input_size); + } + shiftBuffer.resize(desired_input_size); + } + + if (shiftFrequency < 0) { + nco_crcf_mix_block_up(freqShifter, &iqData->data[0], &shiftBuffer[0], desired_input_size); + } else { + nco_crcf_mix_block_down(freqShifter, &iqData->data[0], &shiftBuffer[0], desired_input_size); + } + } else { + shiftBuffer.assign(iqData->data.begin(), iqData->data.end()); + } + + if (!resampler || bandwidth != lastBandwidth || lastInputBandwidth != iqData->sampleRate) { + float As = 60.0f; + + if (resampler) { + msresamp_crcf_destroy(resampler); + } + resampler = msresamp_crcf_create(resamplerRatio, As); + + lastBandwidth = bandwidth; + lastInputBandwidth = iqData->sampleRate; + } + + + int out_size = ceil((double) (desired_input_size) * resamplerRatio) + 512; + + if (resampleBuffer.size() != out_size) { + if (resampleBuffer.capacity() < out_size) { + resampleBuffer.reserve(out_size); + } + resampleBuffer.resize(out_size); + } + + + msresamp_crcf_execute(resampler, &shiftBuffer[0], desired_input_size, &resampleBuffer[0], &num_written); + + resampleBuffer.resize(fftSize); + + if (num_written < fftSize) { + for (int i = 0; i < num_written; i++) { + fftInData[i][0] = resampleBuffer[i].real; + fftInData[i][1] = resampleBuffer[i].imag; + } + for (int i = num_written; i < fftSize; i++) { + fftInData[i][0] = 0; + fftInData[i][1] = 0; + } + } else { + for (int i = 0; i < fftSize; i++) { + fftInData[i][0] = resampleBuffer[i].real; + fftInData[i][1] = resampleBuffer[i].imag; + } + } + } else { + num_written = data->size(); + if (data->size() < fftSize) { + for (int i = 0, iMax = data->size(); i < iMax; i++) { + fftInData[i][0] = (*data)[i].real; + fftInData[i][1] = (*data)[i].imag; + } + for (int i = data->size(); i < fftSize; i++) { + fftInData[i][0] = 0; + fftInData[i][1] = 0; + } + } else { + for (int i = 0; i < fftSize; i++) { + fftInData[i][0] = (*data)[i].real; + fftInData[i][1] = (*data)[i].imag; + } + } + } + + bool execute = false; + + if (num_written >= fftSize) { + execute = true; + memcpy(fftwInput, fftInData, fftSize * sizeof(fftwf_complex)); + memcpy(fftLastData, fftwInput, fftSize * sizeof(fftwf_complex)); + + } else { + if (lastDataSize + num_written < fftSize) { // priming + unsigned int num_copy = fftSize - lastDataSize; + if (num_written > num_copy) { + num_copy = num_written; + } + memcpy(fftLastData, fftInData, num_copy * sizeof(fftwf_complex)); + lastDataSize += num_copy; + } else { + unsigned int num_last = (fftSize - num_written); + memcpy(fftwInput, fftLastData + (lastDataSize - num_last), num_last * sizeof(fftwf_complex)); + memcpy(fftwInput + num_last, fftInData, num_written * sizeof(fftwf_complex)); + memcpy(fftLastData, fftwInput, fftSize * sizeof(fftwf_complex)); + execute = true; + } + } + + if (execute) { + fftwf_execute(fftw_plan); + + float fft_ceil = 0, fft_floor = 1; + + if (fft_result.size() < fftSize) { + fft_result.resize(fftSize); + fft_result_ma.resize(fftSize); + fft_result_maa.resize(fftSize); + } + + for (int i = 0, iMax = fftSize / 2; i < iMax; i++) { + float a = fftwOutput[i][0]; + float b = fftwOutput[i][1]; + float c = sqrt(a * a + b * b); + + float x = fftwOutput[fftSize / 2 + i][0]; + float y = fftwOutput[fftSize / 2 + i][1]; + float z = sqrt(x * x + y * y); + + fft_result[i] = (z); + fft_result[fftSize / 2 + i] = (c); + } + + for (int i = 0, iMax = fftSize; i < iMax; i++) { + if (is_view.load()) { + fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65; + fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65; + } else { + fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65; + fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65; + } + + if (fft_result_maa[i] > fft_ceil) { + fft_ceil = fft_result_maa[i]; + } + if (fft_result_maa[i] < fft_floor) { + fft_floor = fft_result_maa[i]; + } + } + + fft_ceil += 0.25; + fft_floor -= 1; + + fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.05; + fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.05; + + fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.05; + fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.05; + + for (int i = 0, iMax = fftSize; i < iMax; i++) { + float v = (log10(fft_result_maa[i] - fft_floor_maa) / log10(fft_ceil_maa - fft_floor_maa)); + output->spectrum_points[i * 2] = ((float) i / (float) iMax); + output->spectrum_points[i * 2 + 1] = v; + } + + output->fft_ceiling = fft_ceil_maa; + output->fft_floor = fft_floor_maa; + } + + distribute(output); + } + +} diff --git a/src/process/SpectrumVisualProcessor.h b/src/process/SpectrumVisualProcessor.h index 3fcc0ff..6ffe848 100644 --- a/src/process/SpectrumVisualProcessor.h +++ b/src/process/SpectrumVisualProcessor.h @@ -1,13 +1,62 @@ #pragma once #include "VisualProcessor.h" -#include "SpectrumCanvas.h" +#include "DemodDefs.h" +#include "fftw3.h" class SpectrumVisualData : public ReferenceCounter { - +public: + std::vector spectrum_points; + double fft_ceiling, fft_floor; }; +typedef ThreadQueue SpectrumVisualDataQueue; + class SpectrumVisualProcessor : public VisualProcessor { +public: + SpectrumVisualProcessor(); + ~SpectrumVisualProcessor(); + + bool isView(); + void setView(bool bView); + + void setCenterFrequency(long long centerFreq_in); + long long getCenterFrequency(); + + void setBandwidth(long bandwidth_in); + long getBandwidth(); + + void setup(int fftSize); + protected: void process(); + + ReBuffer outputBuffers; + std::atomic_bool is_view; + std::atomic_int fftSize; + std::atomic_llong centerFreq; + std::atomic_long bandwidth; + +private: + long lastInputBandwidth; + long lastBandwidth; + + fftwf_complex *fftwInput, *fftwOutput, *fftInData, *fftLastData; + unsigned int lastDataSize; + fftwf_plan fftw_plan; + + float fft_ceil_ma, fft_ceil_maa; + float fft_floor_ma, fft_floor_maa; + + std::vector fft_result; + std::vector fft_result_ma; + std::vector fft_result_maa; + + msresamp_crcf resampler; + double resamplerRatio; + nco_crcf freqShifter; + long shiftFrequency; + + std::vector shiftBuffer; + std::vector resampleBuffer; }; diff --git a/src/process/VisualProcessor.h b/src/process/VisualProcessor.h index 4f8c898..1f02bbe 100644 --- a/src/process/VisualProcessor.h +++ b/src/process/VisualProcessor.h @@ -86,16 +86,18 @@ protected: }; -template -class VisualDataDistributor : public VisualProcessor { +template +class VisualDataDistributor : public VisualProcessor { protected: void process() { - - while (!VisualProcessor::input->empty()) { - ReferenceCounter *inp; - VisualProcessor::input->pop(inp); + if (!VisualProcessor::isOutputEmpty()) { + return; + } + while (!VisualProcessor::input->empty()) { + OutputDataType *inp; + VisualProcessor::input->pop(inp); if (inp) { - VisualProcessor::distribute(inp); + VisualProcessor::distribute(inp); } } } diff --git a/src/process/WaterfallVisualProcessor.cpp b/src/process/WaterfallVisualProcessor.cpp deleted file mode 100644 index 153e489..0000000 --- a/src/process/WaterfallVisualProcessor.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include "WaterfallVisualProcessor.h" - -void WaterfallVisualProcessor::process() { - /* - long double currentZoom = zoom; - - if (mouseZoom != 1) { - currentZoom = mouseZoom; - mouseZoom = mouseZoom + (1.0 - mouseZoom) * 0.2; - if (fabs(mouseZoom-1.0)<0.01) { - mouseZoom = 1; - } - } - - long long bw; - if (currentZoom != 1) { - long long freq = wxGetApp().getFrequency(); - - if (currentZoom < 1) { - centerFreq = getCenterFrequency(); - bw = getBandwidth(); - bw = (long long) ceil((long double) bw * currentZoom); - if (bw < 100000) { - bw = 100000; - } - if (mouseTracker.mouseInView()) { - long long mfreqA = getFrequencyAt(mouseTracker.getMouseX()); - setBandwidth(bw); - long long mfreqB = getFrequencyAt(mouseTracker.getMouseX()); - centerFreq += mfreqA - mfreqB; - } - - setView(centerFreq, bw); - if (spectrumCanvas) { - spectrumCanvas->setView(centerFreq, bw); - } - } else { - if (isView) { - bw = getBandwidth(); - bw = (long long) ceil((long double) bw * currentZoom); - if (bw >= wxGetApp().getSampleRate()) { - disableView(); - if (spectrumCanvas) { - spectrumCanvas->disableView(); - } - } else { - if (mouseTracker.mouseInView()) { - long long mfreqA = getFrequencyAt(mouseTracker.getMouseX()); - setBandwidth(bw); - long long mfreqB = getFrequencyAt(mouseTracker.getMouseX()); - centerFreq += mfreqA - mfreqB; - } - - setView(getCenterFrequency(), bw); - if (spectrumCanvas) { - spectrumCanvas->setView(centerFreq, bw); - } - } - } - } - if (centerFreq < freq && (centerFreq - bandwidth / 2) < (freq - wxGetApp().getSampleRate() / 2)) { - centerFreq = (freq - wxGetApp().getSampleRate() / 2) + bandwidth / 2; - } - if (centerFreq > freq && (centerFreq + bandwidth / 2) > (freq + wxGetApp().getSampleRate() / 2)) { - centerFreq = (freq + wxGetApp().getSampleRate() / 2) - bandwidth / 2; - } - } - - std::vector *data = &input->data; - - if (data && data->size()) { - // if (fft_size != data->size() && !isView) { - // Setup(data->size(), waterfall_lines); - // } - - // if (last_bandwidth != bandwidth && !isView) { - // Setup(bandwidth, waterfall_lines); - // } - - if (spectrum_points.size() < fft_size * 2) { - spectrum_points.resize(fft_size * 2); - } - - unsigned int num_written; - - if (isView) { - if (!input->frequency || !input->sampleRate) { - return; - } - - resamplerRatio = (double) (bandwidth) / (double) input->sampleRate; - - int desired_input_size = fft_size / resamplerRatio; - - if (input->data.size() < desired_input_size) { - // std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl; - desired_input_size = input->data.size(); - } - - if (centerFreq != input->frequency) { - if ((centerFreq - input->frequency) != shiftFrequency || lastInputBandwidth != input->sampleRate) { - if (abs(input->frequency - centerFreq) < (wxGetApp().getSampleRate() / 2)) { - shiftFrequency = centerFreq - input->frequency; - nco_crcf_reset(freqShifter); - nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) input->sampleRate))); - } - } - - if (shiftBuffer.size() != desired_input_size) { - if (shiftBuffer.capacity() < desired_input_size) { - shiftBuffer.reserve(desired_input_size); - } - shiftBuffer.resize(desired_input_size); - } - - if (shiftFrequency < 0) { - nco_crcf_mix_block_up(freqShifter, &input->data[0], &shiftBuffer[0], desired_input_size); - } else { - nco_crcf_mix_block_down(freqShifter, &input->data[0], &shiftBuffer[0], desired_input_size); - } - } else { - shiftBuffer.assign(input->data.begin(), input->data.end()); - } - - if (!resampler || bandwidth != lastBandwidth || lastInputBandwidth != input->sampleRate) { - float As = 60.0f; - - if (resampler) { - msresamp_crcf_destroy(resampler); - } - resampler = msresamp_crcf_create(resamplerRatio, As); - - lastBandwidth = bandwidth; - lastInputBandwidth = input->sampleRate; - } - - - int out_size = ceil((double) (desired_input_size) * resamplerRatio) + 512; - - if (resampleBuffer.size() != out_size) { - if (resampleBuffer.capacity() < out_size) { - resampleBuffer.reserve(out_size); - } - resampleBuffer.resize(out_size); - } - - - msresamp_crcf_execute(resampler, &shiftBuffer[0], desired_input_size, &resampleBuffer[0], &num_written); - - resampleBuffer.resize(fft_size); - - if (num_written < fft_size) { - for (int i = 0; i < num_written; i++) { - fft_in_data[i][0] = resampleBuffer[i].real; - fft_in_data[i][1] = resampleBuffer[i].imag; - } - for (int i = num_written; i < fft_size; i++) { - fft_in_data[i][0] = 0; - fft_in_data[i][1] = 0; - } - } else { - for (int i = 0; i < fft_size; i++) { - fft_in_data[i][0] = resampleBuffer[i].real; - fft_in_data[i][1] = resampleBuffer[i].imag; - } - } - } else { - num_written = data->size(); - if (data->size() < fft_size) { - for (int i = 0, iMax = data->size(); i < iMax; i++) { - fft_in_data[i][0] = (*data)[i].real; - fft_in_data[i][1] = (*data)[i].imag; - } - for (int i = data->size(); i < fft_size; i++) { - fft_in_data[i][0] = 0; - fft_in_data[i][1] = 0; - } - } else { - for (int i = 0; i < fft_size; i++) { - fft_in_data[i][0] = (*data)[i].real; - fft_in_data[i][1] = (*data)[i].imag; - } - } - } - - bool execute = false; - - if (num_written >= fft_size) { - execute = true; - memcpy(in, fft_in_data, fft_size * sizeof(fftwf_complex)); - memcpy(fft_last_data, in, fft_size * sizeof(fftwf_complex)); - - } else { - if (last_data_size + num_written < fft_size) { // priming - unsigned int num_copy = fft_size - last_data_size; - if (num_written > num_copy) { - num_copy = num_written; - } - memcpy(fft_last_data, fft_in_data, num_copy * sizeof(fftwf_complex)); - last_data_size += num_copy; - } else { - unsigned int num_last = (fft_size - num_written); - memcpy(in, fft_last_data + (last_data_size - num_last), num_last * sizeof(fftwf_complex)); - memcpy(in + num_last, fft_in_data, num_written * sizeof(fftwf_complex)); - memcpy(fft_last_data, in, fft_size * sizeof(fftwf_complex)); - execute = true; - } - } - - if (execute) { - fftwf_execute(plan); - - float fft_ceil = 0, fft_floor = 1; - - if (fft_result.size() < fft_size) { - fft_result.resize(fft_size); - fft_result_ma.resize(fft_size); - fft_result_maa.resize(fft_size); - } - - int n; - for (int i = 0, iMax = fft_size / 2; i < iMax; i++) { - float a = out[i][0]; - float b = out[i][1]; - float c = sqrt(a * a + b * b); - - float x = out[fft_size / 2 + i][0]; - float y = out[fft_size / 2 + i][1]; - float z = sqrt(x * x + y * y); - - fft_result[i] = (z); - fft_result[fft_size / 2 + i] = (c); - } - - for (int i = 0, iMax = fft_size; i < iMax; i++) { - if (isView) { - fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65; - fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65; - } else { - fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65; - fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65; - } - - if (fft_result_maa[i] > fft_ceil) { - fft_ceil = fft_result_maa[i]; - } - if (fft_result_maa[i] < fft_floor) { - fft_floor = fft_result_maa[i]; - } - } - - fft_ceil += 0.25; - fft_floor -= 1; - - fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.05; - fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.05; - - fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.05; - fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.05; - - for (int i = 0, iMax = fft_size; i < iMax; i++) { - float v = (log10(fft_result_maa[i] - fft_floor_maa) / log10(fft_ceil_maa - fft_floor_maa)); - spectrum_points[i * 2] = ((float) i / (float) iMax); - spectrum_points[i * 2 + 1] = v; - } - - if (spectrumCanvas) { - spectrumCanvas->spectrum_points.assign(spectrum_points.begin(), spectrum_points.end()); - spectrumCanvas->getSpectrumContext()->setCeilValue(fft_ceil_maa); - spectrumCanvas->getSpectrumContext()->setFloorValue(fft_floor_maa); - } - } - } - */ -} \ No newline at end of file diff --git a/src/process/WaterfallVisualProcessor.h b/src/process/WaterfallVisualProcessor.h deleted file mode 100644 index 5c2aa62..0000000 --- a/src/process/WaterfallVisualProcessor.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "VisualProcessor.h" -#include "WaterfallCanvas.h" - -class WaterfallVisualData : public ReferenceCounter { - -}; - -class WaterfallVisualProcessor : public VisualProcessor { -protected: - void process(); -}; diff --git a/src/visual/SpectrumCanvas.cpp b/src/visual/SpectrumCanvas.cpp index 776b89a..65a52b2 100644 --- a/src/visual/SpectrumCanvas.cpp +++ b/src/visual/SpectrumCanvas.cpp @@ -27,8 +27,7 @@ EVT_MOUSEWHEEL(SpectrumCanvas::OnMouseWheelMoved) wxEND_EVENT_TABLE() SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) : - InteractiveCanvas(parent, attribList), fft_size(0), in(NULL), out(NULL), plan(NULL), fft_ceil_ma(1), fft_ceil_maa(1), fft_floor_ma(0), fft_floor_maa( - 0), waterfallCanvas(NULL), trackingRate(0) { + InteractiveCanvas(parent, attribList), fft_size(0), waterfallCanvas(NULL), trackingRate(0) { glContext = new SpectrumContext(this, &wxGetApp().GetContext(this)); @@ -37,30 +36,6 @@ SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) : SetCursor(wxCURSOR_SIZEWE); } -void SpectrumCanvas::setup(int fft_size_in) { - if (fft_size == fft_size_in) { - return; - } - - fft_size = fft_size_in; - - if (in) { - free(in); - } - in = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fft_size); - if (out) { - free(out); - } - out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fft_size); - if (plan) { - fftwf_destroy_plan(plan); - } - plan = fftwf_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; -} - SpectrumCanvas::~SpectrumCanvas() { } @@ -71,7 +46,23 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { glFinish(); #endif const wxSize ClientSize = GetClientSize(); - + + if (visualDataQueue.empty()) { + return; + } + + SpectrumVisualData *vData; + + visualDataQueue.pop(vData); + + if (!vData) { + return; + } + + spectrum_points.assign(vData->spectrum_points.begin(),vData->spectrum_points.end()); + + vData->decRefCount(); + glContext->SetCurrent(*this); initGLExtensions(); @@ -91,85 +82,6 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { SwapBuffers(); } -void SpectrumCanvas::setData(DemodulatorThreadIQData *input) { - if (!input) { - return; - } - std::vector *data = &input->data; - if (data && data->size()) { - if (fft_size != data->size()) { - setup(data->size()); - } - if (spectrum_points.size() < fft_size * 2) { - if (spectrum_points.capacity() < fft_size * 2) { - spectrum_points.reserve(fft_size * 2); - } - spectrum_points.resize(fft_size * 2); - } - - for (int i = 0; i < fft_size; i++) { - in[i][0] = (*data)[i].real; - in[i][1] = (*data)[i].imag; - } - - fftwf_execute(plan); - - float fft_ceil = 0, fft_floor = 1; - - if (fft_result.size() != fft_size) { - if (fft_result.capacity() < fft_size) { - fft_result.reserve(fft_size); - fft_result_ma.reserve(fft_size); - fft_result_maa.reserve(fft_size); - } - fft_result.resize(fft_size); - fft_result_ma.resize(fft_size); - fft_result_maa.resize(fft_size); - } - - int n; - for (int i = 0, iMax = fft_size / 2; i < iMax; i++) { - float a = out[i][0]; - float b = out[i][1]; - float c = sqrt(a * a + b * b); - - float x = out[fft_size / 2 + i][0]; - float y = out[fft_size / 2 + i][1]; - float z = sqrt(x * x + y * y); - - fft_result[i] = (z); - fft_result[fft_size / 2 + i] = (c); - } - - for (int i = 0, iMax = fft_size; i < iMax; i++) { - fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65; - fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65; - - if (fft_result_maa[i] > fft_ceil) { - fft_ceil = fft_result_maa[i]; - } - if (fft_result_maa[i] < fft_floor) { - fft_floor = fft_result_maa[i]; - } - } - - fft_ceil += 1; - fft_floor -= 1; - - fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.01; - fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.01; - - fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.01; - fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.01; - - for (int i = 0, iMax = fft_size; i < iMax; i++) { - float v = (log10(fft_result_maa[i] - fft_floor_maa) / log10(fft_ceil_maa - fft_floor_maa)); - spectrum_points[i * 2] = ((float) i / (float) iMax); - spectrum_points[i * 2 + 1] = v; - } - - } -} void SpectrumCanvas::OnIdle(wxIdleEvent &event) { Refresh(false); @@ -250,3 +162,7 @@ void SpectrumCanvas::attachWaterfallCanvas(WaterfallCanvas* canvas_in) { SpectrumContext* SpectrumCanvas::getSpectrumContext() { return glContext; } + +SpectrumVisualDataQueue *SpectrumCanvas::getVisualDataQueue() { + return &visualDataQueue; +} \ No newline at end of file diff --git a/src/visual/SpectrumCanvas.h b/src/visual/SpectrumCanvas.h index f1469a2..636296d 100644 --- a/src/visual/SpectrumCanvas.h +++ b/src/visual/SpectrumCanvas.h @@ -11,6 +11,7 @@ #include "fftw3.h" #include "MouseTracker.h" +#include "SpectrumVisualProcessor.h" class WaterfallCanvas; @@ -19,15 +20,15 @@ public: std::vector spectrum_points; SpectrumCanvas(wxWindow *parent, int *attribList = NULL); - void setup(int fft_size_in); +// void setup(int fft_size_in); ~SpectrumCanvas(); - void setData(DemodulatorThreadIQData *input); void attachWaterfallCanvas(WaterfallCanvas *canvas_in); void moveCenterFrequency(long long freqChange); SpectrumContext* getSpectrumContext(); - + SpectrumVisualDataQueue *getVisualDataQueue(); + private: void OnPaint(wxPaintEvent& event); @@ -39,20 +40,23 @@ private: void OnMouseReleased(wxMouseEvent& event); void OnMouseLeftWindow(wxMouseEvent& event); - fftwf_complex *in, *out; - fftwf_plan plan; - - float fft_ceil_ma, fft_ceil_maa; - float fft_floor_ma, fft_floor_maa; - - std::vector fft_result; - std::vector fft_result_ma; - std::vector fft_result_maa; +// fftwf_complex *in, *out; +// fftwf_plan plan; +// +// float fft_ceil_ma, fft_ceil_maa; +// float fft_floor_ma, fft_floor_maa; +// +// std::vector fft_result; +// std::vector fft_result_ma; +// std::vector fft_result_maa; SpectrumContext *glContext; WaterfallCanvas *waterfallCanvas; int fft_size; int trackingRate; + + SpectrumVisualDataQueue visualDataQueue; + // event table wxDECLARE_EVENT_TABLE(); }; diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index abbcf0e..c928d89 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -35,23 +35,15 @@ EVT_MOUSEWHEEL(WaterfallCanvas::OnMouseWheelMoved) wxEND_EVENT_TABLE() WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) : - InteractiveCanvas(parent, attribList), spectrumCanvas(NULL), dragState(WF_DRAG_NONE), nextDragState(WF_DRAG_NONE), fft_size(0), waterfall_lines( - 0), plan( - NULL), in(NULL), out(NULL), resampler(NULL), resamplerRatio(0), lastInputBandwidth(0), zoom(1), mouseZoom(1), otherWaterfallCanvas(NULL), polling(true), last_data_size(0), fft_in_data(NULL), fft_last_data(NULL), hoverAlpha(1.0), dragOfs(0) { + InteractiveCanvas(parent, attribList), dragState(WF_DRAG_NONE), nextDragState(WF_DRAG_NONE), fft_size(0), waterfall_lines( + 0), zoom(1), mouseZoom(1), hoverAlpha(1.0), dragOfs(0) { glContext = new WaterfallContext(this, &wxGetApp().GetContext(this)); - freqShifter = nco_crcf_create(LIQUID_NCO); - shiftFrequency = 0; - - fft_ceil_ma = fft_ceil_maa = 100.0; - fft_floor_ma = fft_floor_maa = 0.0; - SetCursor(wxCURSOR_CROSS); } WaterfallCanvas::~WaterfallCanvas() { - nco_crcf_destroy(freqShifter); } void WaterfallCanvas::setup(int fft_size_in, int waterfall_lines_in) { @@ -61,27 +53,6 @@ void WaterfallCanvas::setup(int fft_size_in, int waterfall_lines_in) { fft_size = fft_size_in; waterfall_lines = waterfall_lines_in; - if (in) { - free(in); - } - in = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fft_size); - if (fft_in_data) { - free(fft_in_data); - } - fft_in_data = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fft_size); - if (fft_last_data) { - free(fft_last_data); - } - fft_last_data = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fft_size); - if (out) { - free(out); - } - out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fft_size); - if (plan) { - fftwf_destroy_plan(plan); - } - plan = fftwf_plan_dft_1d(fft_size, in, out, FFTW_FORWARD, FFTW_ESTIMATE); - glContext->Setup(fft_size, waterfall_lines); } @@ -104,29 +75,89 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { #endif const wxSize ClientSize = GetClientSize(); - - - if (polling && !wxGetApp().getIQVisualQueue()->empty()) { - DemodulatorThreadIQData *iqData; - wxGetApp().getIQVisualQueue()->pop(iqData); - - iqData->busy_rw.lock(); - - if (iqData && iqData->data.size()) { - setData(iqData); - if (otherWaterfallCanvas) { - otherWaterfallCanvas->setData(iqData); + long double currentZoom = zoom; + + if (mouseZoom != 1) { + currentZoom = mouseZoom; + mouseZoom = mouseZoom + (1.0 - mouseZoom) * 0.2; + if (fabs(mouseZoom-1.0)<0.01) { + mouseZoom = 1; + } + } + + long long bw; + if (currentZoom != 1) { + long long freq = wxGetApp().getFrequency(); + + if (currentZoom < 1) { + centerFreq = getCenterFrequency(); + bw = getBandwidth(); + bw = (long long) ceil((long double) bw * currentZoom); + if (bw < 100000) { + bw = 100000; + } + if (mouseTracker.mouseInView()) { + long long mfreqA = getFrequencyAt(mouseTracker.getMouseX()); + setBandwidth(bw); + long long mfreqB = getFrequencyAt(mouseTracker.getMouseX()); + centerFreq += mfreqA - mfreqB; + } + + setView(centerFreq, bw); + if (spectrumCanvas) { + spectrumCanvas->setView(centerFreq, bw); } } else { - std::cout << "Incoming IQ data empty?" << std::endl; + if (isView) { + bw = getBandwidth(); + bw = (long long) ceil((long double) bw * currentZoom); + if (bw >= wxGetApp().getSampleRate()) { + disableView(); + if (spectrumCanvas) { + spectrumCanvas->disableView(); + } + } else { + if (mouseTracker.mouseInView()) { + long long mfreqA = getFrequencyAt(mouseTracker.getMouseX()); + setBandwidth(bw); + long long mfreqB = getFrequencyAt(mouseTracker.getMouseX()); + centerFreq += mfreqA - mfreqB; + } + + setView(getCenterFrequency(), bw); + if (spectrumCanvas) { + spectrumCanvas->setView(centerFreq, bw); + } + } + } + } + if (centerFreq < freq && (centerFreq - bandwidth / 2) < (freq - wxGetApp().getSampleRate() / 2)) { + centerFreq = (freq - wxGetApp().getSampleRate() / 2) + bandwidth / 2; + } + if (centerFreq > freq && (centerFreq + bandwidth / 2) > (freq + wxGetApp().getSampleRate() / 2)) { + centerFreq = (freq + wxGetApp().getSampleRate() / 2) - bandwidth / 2; } - - iqData->busy_rw.unlock(); } + if (visualDataQueue.empty()) { + return; + } + + SpectrumVisualData *vData; + + visualDataQueue.pop(vData); + + if (!vData) { + return; + } + + spectrum_points.assign(vData->spectrum_points.begin(),vData->spectrum_points.end()); + + vData->decRefCount(); + glContext->SetCurrent(*this); initGLExtensions(); - glViewport(0, 0, ClientSize.x, ClientSize.y); + glViewport(0, 0, ClientSize.x, ClientSize.y); glContext->BeginDraw(0,0,0); glContext->Draw(spectrum_points); @@ -323,283 +354,6 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { return; } } - -void WaterfallCanvas::setData(DemodulatorThreadIQData *input) { - if (!input) { - return; - } - - long double currentZoom = zoom; - - if (mouseZoom != 1) { - currentZoom = mouseZoom; - mouseZoom = mouseZoom + (1.0 - mouseZoom) * 0.2; - if (fabs(mouseZoom-1.0)<0.01) { - mouseZoom = 1; - } - } - - long long bw; - if (currentZoom != 1) { - long long freq = wxGetApp().getFrequency(); - - if (currentZoom < 1) { - centerFreq = getCenterFrequency(); - bw = getBandwidth(); - bw = (long long) ceil((long double) bw * currentZoom); - if (bw < 100000) { - bw = 100000; - } - if (mouseTracker.mouseInView()) { - long long mfreqA = getFrequencyAt(mouseTracker.getMouseX()); - setBandwidth(bw); - long long mfreqB = getFrequencyAt(mouseTracker.getMouseX()); - centerFreq += mfreqA - mfreqB; - } - - setView(centerFreq, bw); - if (spectrumCanvas) { - spectrumCanvas->setView(centerFreq, bw); - } - } else { - if (isView) { - bw = getBandwidth(); - bw = (long long) ceil((long double) bw * currentZoom); - if (bw >= wxGetApp().getSampleRate()) { - disableView(); - if (spectrumCanvas) { - spectrumCanvas->disableView(); - } - } else { - if (mouseTracker.mouseInView()) { - long long mfreqA = getFrequencyAt(mouseTracker.getMouseX()); - setBandwidth(bw); - long long mfreqB = getFrequencyAt(mouseTracker.getMouseX()); - centerFreq += mfreqA - mfreqB; - } - - setView(getCenterFrequency(), bw); - if (spectrumCanvas) { - spectrumCanvas->setView(centerFreq, bw); - } - } - } - } - if (centerFreq < freq && (centerFreq - bandwidth / 2) < (freq - wxGetApp().getSampleRate() / 2)) { - centerFreq = (freq - wxGetApp().getSampleRate() / 2) + bandwidth / 2; - } - if (centerFreq > freq && (centerFreq + bandwidth / 2) > (freq + wxGetApp().getSampleRate() / 2)) { - centerFreq = (freq + wxGetApp().getSampleRate() / 2) - bandwidth / 2; - } - } - - std::vector *data = &input->data; - - if (data && data->size()) { -// if (fft_size != data->size() && !isView) { -// Setup(data->size(), waterfall_lines); -// } - -// if (last_bandwidth != bandwidth && !isView) { -// Setup(bandwidth, waterfall_lines); -// } - - if (spectrum_points.size() < fft_size * 2) { - spectrum_points.resize(fft_size * 2); - } - - unsigned int num_written; - - if (isView) { - if (!input->frequency || !input->sampleRate) { - return; - } - - resamplerRatio = (double) (bandwidth) / (double) input->sampleRate; - - int desired_input_size = fft_size / resamplerRatio; - - if (input->data.size() < desired_input_size) { -// std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl; - desired_input_size = input->data.size(); - } - - if (centerFreq != input->frequency) { - if ((centerFreq - input->frequency) != shiftFrequency || lastInputBandwidth != input->sampleRate) { - if (abs(input->frequency - centerFreq) < (wxGetApp().getSampleRate() / 2)) { - shiftFrequency = centerFreq - input->frequency; - nco_crcf_reset(freqShifter); - nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) input->sampleRate))); - } - } - - if (shiftBuffer.size() != desired_input_size) { - if (shiftBuffer.capacity() < desired_input_size) { - shiftBuffer.reserve(desired_input_size); - } - shiftBuffer.resize(desired_input_size); - } - - if (shiftFrequency < 0) { - nco_crcf_mix_block_up(freqShifter, &input->data[0], &shiftBuffer[0], desired_input_size); - } else { - nco_crcf_mix_block_down(freqShifter, &input->data[0], &shiftBuffer[0], desired_input_size); - } - } else { - shiftBuffer.assign(input->data.begin(), input->data.end()); - } - - if (!resampler || bandwidth != lastBandwidth || lastInputBandwidth != input->sampleRate) { - float As = 60.0f; - - if (resampler) { - msresamp_crcf_destroy(resampler); - } - resampler = msresamp_crcf_create(resamplerRatio, As); - - lastBandwidth = bandwidth; - lastInputBandwidth = input->sampleRate; - } - - - int out_size = ceil((double) (desired_input_size) * resamplerRatio) + 512; - - if (resampleBuffer.size() != out_size) { - if (resampleBuffer.capacity() < out_size) { - resampleBuffer.reserve(out_size); - } - resampleBuffer.resize(out_size); - } - - - msresamp_crcf_execute(resampler, &shiftBuffer[0], desired_input_size, &resampleBuffer[0], &num_written); - - resampleBuffer.resize(fft_size); - - if (num_written < fft_size) { - for (int i = 0; i < num_written; i++) { - fft_in_data[i][0] = resampleBuffer[i].real; - fft_in_data[i][1] = resampleBuffer[i].imag; - } - for (int i = num_written; i < fft_size; i++) { - fft_in_data[i][0] = 0; - fft_in_data[i][1] = 0; - } - } else { - for (int i = 0; i < fft_size; i++) { - fft_in_data[i][0] = resampleBuffer[i].real; - fft_in_data[i][1] = resampleBuffer[i].imag; - } - } - } else { - num_written = data->size(); - if (data->size() < fft_size) { - for (int i = 0, iMax = data->size(); i < iMax; i++) { - fft_in_data[i][0] = (*data)[i].real; - fft_in_data[i][1] = (*data)[i].imag; - } - for (int i = data->size(); i < fft_size; i++) { - fft_in_data[i][0] = 0; - fft_in_data[i][1] = 0; - } - } else { - for (int i = 0; i < fft_size; i++) { - fft_in_data[i][0] = (*data)[i].real; - fft_in_data[i][1] = (*data)[i].imag; - } - } - } - - bool execute = false; - - if (num_written >= fft_size) { - execute = true; - memcpy(in, fft_in_data, fft_size * sizeof(fftwf_complex)); - memcpy(fft_last_data, in, fft_size * sizeof(fftwf_complex)); - - } else { - if (last_data_size + num_written < fft_size) { // priming - unsigned int num_copy = fft_size - last_data_size; - if (num_written > num_copy) { - num_copy = num_written; - } - memcpy(fft_last_data, fft_in_data, num_copy * sizeof(fftwf_complex)); - last_data_size += num_copy; - } else { - unsigned int num_last = (fft_size - num_written); - memcpy(in, fft_last_data + (last_data_size - num_last), num_last * sizeof(fftwf_complex)); - memcpy(in + num_last, fft_in_data, num_written * sizeof(fftwf_complex)); - memcpy(fft_last_data, in, fft_size * sizeof(fftwf_complex)); - execute = true; - } - } - - if (execute) { - fftwf_execute(plan); - - float fft_ceil = 0, fft_floor = 1; - - if (fft_result.size() < fft_size) { - fft_result.resize(fft_size); - fft_result_ma.resize(fft_size); - fft_result_maa.resize(fft_size); - } - - int n; - for (int i = 0, iMax = fft_size / 2; i < iMax; i++) { - float a = out[i][0]; - float b = out[i][1]; - float c = sqrt(a * a + b * b); - - float x = out[fft_size / 2 + i][0]; - float y = out[fft_size / 2 + i][1]; - float z = sqrt(x * x + y * y); - - fft_result[i] = (z); - fft_result[fft_size / 2 + i] = (c); - } - - for (int i = 0, iMax = fft_size; i < iMax; i++) { - if (isView) { - fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65; - fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65; - } else { - fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65; - fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65; - } - - if (fft_result_maa[i] > fft_ceil) { - fft_ceil = fft_result_maa[i]; - } - if (fft_result_maa[i] < fft_floor) { - fft_floor = fft_result_maa[i]; - } - } - - fft_ceil += 0.25; - fft_floor -= 1; - - fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.05; - fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.05; - - fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.05; - fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.05; - - for (int i = 0, iMax = fft_size; i < iMax; i++) { - float v = (log10(fft_result_maa[i] - fft_floor_maa) / log10(fft_ceil_maa - fft_floor_maa)); - spectrum_points[i * 2] = ((float) i / (float) iMax); - spectrum_points[i * 2 + 1] = v; - } - - if (spectrumCanvas) { - spectrumCanvas->spectrum_points.assign(spectrum_points.begin(), spectrum_points.end()); - spectrumCanvas->getSpectrumContext()->setCeilValue(fft_ceil_maa); - spectrumCanvas->getSpectrumContext()->setFloorValue(fft_floor_maa); - } - } - } -} - void WaterfallCanvas::OnIdle(wxIdleEvent &event) { Refresh(false); } @@ -963,16 +717,16 @@ void WaterfallCanvas::OnMouseRightReleased(wxMouseEvent& event) { mouseZoom = 1.0; } -void WaterfallCanvas::attachWaterfallCanvas(WaterfallCanvas* canvas_in) { - otherWaterfallCanvas = canvas_in; - otherWaterfallCanvas->setPolling(false); -} +// +//bool WaterfallCanvas::isPolling() { +// return polling; +//} +// +//void WaterfallCanvas::setPolling(bool polling) { +// this->polling = polling; +//} -bool WaterfallCanvas::isPolling() { - return polling; -} - -void WaterfallCanvas::setPolling(bool polling) { - this->polling = polling; -} +SpectrumVisualDataQueue *WaterfallCanvas::getVisualDataQueue() { + return &visualDataQueue; +} \ No newline at end of file diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index 7c06271..5c80c27 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -11,7 +11,6 @@ #include "MouseTracker.h" #include "SpectrumCanvas.h" -#include "fftw3.h" class WaterfallCanvas: public InteractiveCanvas { public: @@ -23,16 +22,11 @@ public: void setup(int fft_size_in, int waterfall_lines_in); ~WaterfallCanvas(); - void setData(DemodulatorThreadIQData *input); - DragState getDragState(); DragState getNextDragState(); - + void attachSpectrumCanvas(SpectrumCanvas *canvas_in); - void attachWaterfallCanvas(WaterfallCanvas *canvas_in); - - bool isPolling(); - void setPolling(bool polling); + SpectrumVisualDataQueue *getVisualDataQueue(); private: void OnPaint(wxPaintEvent& event); @@ -53,19 +47,6 @@ private: std::vector spectrum_points; SpectrumCanvas *spectrumCanvas; - WaterfallCanvas *otherWaterfallCanvas; - bool polling; - - fftwf_complex *in, *out, *fft_in_data, *fft_last_data; - unsigned int last_data_size; - fftwf_plan plan; - - float fft_ceil_ma, fft_ceil_maa; - float fft_floor_ma, fft_floor_maa; - - std::vector fft_result; - std::vector fft_result_ma; - std::vector fft_result_maa; WaterfallContext *glContext; @@ -76,18 +57,11 @@ private: int waterfall_lines; int dragOfs; - msresamp_crcf resampler; - double resamplerRatio; - nco_crcf freqShifter; - long shiftFrequency; - int lastInputBandwidth; float mouseZoom, zoom; float hoverAlpha; - std::vector shiftBuffer; - std::vector resampleBuffer; - + SpectrumVisualDataQueue visualDataQueue; // event table wxDECLARE_EVENT_TABLE();