diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 826e40a..9bc7183 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -120,12 +120,18 @@ AppFrame::AppFrame() : vbox->AddSpacer(1); wxGetApp().getSpectrumProcesor()->attachOutput(spectrumCanvas->getVisualDataQueue()); + wxGetApp().getWaterfallProcesor()->setup(2048); waterfallCanvas = new WaterfallCanvas(this, attribList); waterfallCanvas->setup(2048, 512); waterfallCanvas->attachSpectrumCanvas(spectrumCanvas); spectrumCanvas->attachWaterfallCanvas(waterfallCanvas); vbox->Add(waterfallCanvas, 20, wxEXPAND | wxALL, 0); - wxGetApp().getSpectrumProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue()); +// wxGetApp().getSpectrumProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue()); + fftDistrib.setInput(wxGetApp().getWaterfallVisualQueue()); + fftDistrib.attachOutput(&fftQueue); + wxGetApp().getWaterfallProcesor()->setInput(&fftQueue); + wxGetApp().getWaterfallProcesor()->attachOutput(waterfallCanvas->getVisualDataQueue()); + /* vbox->AddSpacer(1); testCanvas = new UITestCanvas(this, attribList); @@ -690,9 +696,9 @@ void AppFrame::OnTimer(wxTimerEvent& event) { SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcesor(); - proc->setView(waterfallCanvas->getViewState()); - proc->setBandwidth(waterfallCanvas->getBandwidth()); - proc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); + proc->setView(spectrumCanvas->getViewState()); + proc->setBandwidth(spectrumCanvas->getBandwidth()); + proc->setCenterFrequency(spectrumCanvas->getCenterFrequency()); proc->run(); @@ -704,6 +710,27 @@ void AppFrame::OnTimer(wxTimerEvent& event) { dproc->run(); + SpectrumVisualProcessor *wproc = wxGetApp().getWaterfallProcesor(); + + int fftSize = wproc->getDesiredInputSize(); + + if (fftSize) { + fftDistrib.setFFTSize(fftSize); + } else { + fftDistrib.setFFTSize(DEFAULT_FFT_SIZE); + } + + fftDistrib.run(); + + wproc->setView(waterfallCanvas->getViewState()); + wproc->setBandwidth(waterfallCanvas->getBandwidth()); + wproc->setCenterFrequency(waterfallCanvas->getCenterFrequency()); + + while (!wproc->isInputEmpty()) { + wproc->run(); + } + + scopeCanvas->Refresh(); waterfallCanvas->Refresh(); diff --git a/src/AppFrame.h b/src/AppFrame.h index de90215..7397097 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -96,5 +96,8 @@ private: std::string currentSessionFile; wxTimer frame_timer; + FFTDataDistributor fftDistrib; + DemodulatorThreadInputQueue fftQueue; + wxDECLARE_EVENT_TABLE(); }; diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 3033b6e..8619b71 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -63,6 +63,8 @@ bool CubicSDR::OnInit() { pipeSpectrumIQVisualData = new DemodulatorThreadInputQueue(); pipeIQVisualData->set_max_num_items(1); + pipeWaterfallIQVisualData = new DemodulatorThreadInputQueue(); + spectrumDistributor.attachOutput(pipeDemodIQVisualData); spectrumDistributor.attachOutput(pipeSpectrumIQVisualData); @@ -85,8 +87,9 @@ bool CubicSDR::OnInit() { sdrPostThread = new SDRPostThread(); sdrPostThread->setNumVisSamples(16384 * 2); sdrPostThread->setInputQueue("IQDataInput", pipeSDRIQData); - sdrPostThread->setOutputQueue("IQVisualDataOut", pipeIQVisualData); - + sdrPostThread->setOutputQueue("IQVisualDataOutput", pipeIQVisualData); + sdrPostThread->setOutputQueue("IQDataOutput", pipeWaterfallIQVisualData); + std::vector::iterator devs_i; SDRThread::enumerate_rtl(&devs); @@ -276,6 +279,10 @@ SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcesor() { return &demodSpectrumProcessor; } +SpectrumVisualProcessor *CubicSDR::getWaterfallProcesor() { + return &waterfallProcessor; +} + VisualDataDistributor *CubicSDR::getSpectrumDistributor() { return &spectrumDistributor; } @@ -289,6 +296,10 @@ DemodulatorThreadInputQueue* CubicSDR::getIQVisualQueue() { return pipeIQVisualData; } +DemodulatorThreadInputQueue* CubicSDR::getWaterfallVisualQueue() { + return pipeWaterfallIQVisualData; +} + DemodulatorMgr &CubicSDR::getDemodMgr() { return demodMgr; } diff --git a/src/CubicSDR.h b/src/CubicSDR.h index c20d522..77dba79 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -58,10 +58,12 @@ public: ScopeVisualProcessor *getScopeProcessor(); SpectrumVisualProcessor *getSpectrumProcesor(); SpectrumVisualProcessor *getDemodSpectrumProcesor(); + SpectrumVisualProcessor *getWaterfallProcesor(); VisualDataDistributor *getSpectrumDistributor(); DemodulatorThreadOutputQueue* getAudioVisualQueue(); DemodulatorThreadInputQueue* getIQVisualQueue(); + DemodulatorThreadInputQueue* getWaterfallVisualQueue(); DemodulatorMgr &getDemodMgr(); void bindDemodulator(DemodulatorInstance *demod); @@ -101,9 +103,11 @@ private: DemodulatorThreadOutputQueue* pipeAudioVisualData; DemodulatorThreadInputQueue* pipeDemodIQVisualData; DemodulatorThreadInputQueue* pipeSpectrumIQVisualData; + DemodulatorThreadInputQueue* pipeWaterfallIQVisualData; ScopeVisualProcessor scopeProcessor; SpectrumVisualProcessor spectrumProcessor; + SpectrumVisualProcessor waterfallProcessor; SpectrumVisualProcessor demodSpectrumProcessor; VisualDataDistributor spectrumDistributor; diff --git a/src/process/SpectrumVisualProcessor.cpp b/src/process/SpectrumVisualProcessor.cpp index 8defddc..75f2ee4 100644 --- a/src/process/SpectrumVisualProcessor.cpp +++ b/src/process/SpectrumVisualProcessor.cpp @@ -14,6 +14,7 @@ SpectrumVisualProcessor::SpectrumVisualProcessor() : lastInputBandwidth(0), last fft_ceil_ma = fft_ceil_maa = 100.0; fft_floor_ma = fft_floor_maa = 0.0; + desiredInputSize = 0; } SpectrumVisualProcessor::~SpectrumVisualProcessor() { @@ -45,8 +46,13 @@ long SpectrumVisualProcessor::getBandwidth() { return bandwidth.load(); } +int SpectrumVisualProcessor::getDesiredInputSize() { + return desiredInputSize; +} + void SpectrumVisualProcessor::setup(int fftSize_in) { fftSize = fftSize_in; + desiredInputSize = fftSize; if (fftwInput) { free(fftwInput); @@ -103,6 +109,8 @@ void SpectrumVisualProcessor::process() { int desired_input_size = fftSize / resamplerRatio; + this->desiredInputSize = desired_input_size; + 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(); @@ -280,5 +288,7 @@ void SpectrumVisualProcessor::process() { distribute(output); } - + + iqData->decRefCount(); } + diff --git a/src/process/SpectrumVisualProcessor.h b/src/process/SpectrumVisualProcessor.h index 6ffe848..cfbd7dd 100644 --- a/src/process/SpectrumVisualProcessor.h +++ b/src/process/SpectrumVisualProcessor.h @@ -26,6 +26,8 @@ public: void setBandwidth(long bandwidth_in); long getBandwidth(); + int getDesiredInputSize(); + void setup(int fftSize); protected: @@ -59,4 +61,39 @@ private: std::vector shiftBuffer; std::vector resampleBuffer; + int desiredInputSize; +}; + + +class FFTDataDistributor : public VisualProcessor { +public: + void setFFTSize(int fftSize) { + this->fftSize = fftSize; + } + +protected: + void process() { + while (!input->empty()) { + if (!isAnyOutputEmpty()) { + return; + } + DemodulatorThreadIQData *inp; + input->pop(inp); + if (inp) { + if (inp->data.size() >= fftSize) { + for (int i = 0, iMax = inp->data.size()-fftSize; i < iMax; i += fftSize) { + DemodulatorThreadIQData *outp = outputBuffers.getBuffer(); + outp->frequency = inp->frequency; + outp->sampleRate = inp->sampleRate; + outp->data.assign(inp->data.begin()+i,inp->data.begin()+i+fftSize); + distribute(outp); + } + } + inp->decRefCount(); + } + } + } + + ReBuffer outputBuffers; + int fftSize; }; diff --git a/src/process/VisualProcessor.h b/src/process/VisualProcessor.h index 1f02bbe..b7662bf 100644 --- a/src/process/VisualProcessor.h +++ b/src/process/VisualProcessor.h @@ -11,6 +11,28 @@ public: virtual ~VisualProcessor() { } + + bool isInputEmpty() { + return input->empty(); + } + + bool isOutputEmpty() { + for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) { + if ((*outputs_i)->full()) { + return false; + } + } + return true; + } + + bool isAnyOutputEmpty() { + for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) { + if (!(*outputs_i)->full()) { + return true; + } + } + return false; + } void setInput(ThreadQueue *vis_in) { busy_update.lock(); @@ -60,24 +82,6 @@ protected: } } } - - bool isOutputEmpty() { - for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) { - if (!(*outputs_i)->empty()) { - return false; - } - } - return true; - } - - bool isAnyOutputEmpty() { - for (outputs_i = outputs.begin(); outputs_i != outputs.end(); outputs_i++) { - if ((*outputs_i)->empty()) { - return true; - } - } - return false; - } ThreadQueue *input; std::vector *> outputs; @@ -90,10 +94,10 @@ template class VisualDataDistributor : public VisualProcessor { protected: void process() { - if (!VisualProcessor::isOutputEmpty()) { - return; - } while (!VisualProcessor::input->empty()) { + if (!VisualProcessor::isAnyOutputEmpty()) { + return; + } OutputDataType *inp; VisualProcessor::input->pop(inp); if (inp) { diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp index 3ceac05..5e68d90 100644 --- a/src/sdr/SDRPostThread.cpp +++ b/src/sdr/SDRPostThread.cpp @@ -82,18 +82,18 @@ void SDRPostThread::run() { iqDataInQueue = (SDRThreadIQDataQueue*)getInputQueue("IQDataInput"); iqDataOutQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQDataOutput"); - iqVisualQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQVisualDataOut"); + iqVisualQueue = (DemodulatorThreadInputQueue*)getOutputQueue("IQVisualDataOutput"); ReBuffer buffers; std::vector fpData; std::vector dataOut; - + while (!terminated) { SDRThreadIQData *data_in; - + iqDataInQueue->pop(data_in); -// std::lock_guard < std::mutex > lock(data_in->m_mutex); - + // std::lock_guard < std::mutex > lock(data_in->m_mutex); + if (data_in && data_in->data.size()) { int dataSize = data_in->data.size()/2; if (dataSize > fpData.capacity()) { @@ -104,7 +104,7 @@ void SDRPostThread::run() { fpData.resize(dataSize); dataOut.resize(dataSize); } - + if (swapIQ) { for (int i = 0; i < dataSize; i++) { fpData[i] = _lut_swap[*((uint16_t*)&data_in->data[2*i])]; @@ -114,106 +114,101 @@ void SDRPostThread::run() { fpData[i] = _lut[*((uint16_t*)&data_in->data[2*i])]; } } - + iirfilt_crcf_execute_block(dcFilter, &fpData[0], dataSize, &dataOut[0]); - - if (iqDataOutQueue != NULL) { - DemodulatorThreadIQData *pipeDataOut = new DemodulatorThreadIQData; - - pipeDataOut->frequency = data_in->frequency; - pipeDataOut->sampleRate = data_in->sampleRate; - pipeDataOut->data.assign(dataOut.begin(), dataOut.end()); - iqDataOutQueue->push(pipeDataOut); - } - + if (iqVisualQueue != NULL && iqVisualQueue->empty()) { - + visualDataOut->busy_rw.lock(); - + if (visualDataOut->data.size() < num_vis_samples) { if (visualDataOut->data.capacity() < num_vis_samples) { visualDataOut->data.reserve(num_vis_samples); } visualDataOut->data.resize(num_vis_samples); } - + visualDataOut->frequency = data_in->frequency; visualDataOut->sampleRate = data_in->sampleRate; visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples); - + iqVisualQueue->push(visualDataOut); - + visualDataOut->busy_rw.unlock(); } busy_demod.lock(); - + int activeDemods = 0; bool pushedData = false; - - if (demodulators.size()) { - - std::vector::iterator i; - for (i = demodulators.begin(); i != demodulators.end(); i++) { - DemodulatorInstance *demod = *i; + + if (demodulators.size() || iqDataOutQueue != NULL) { + std::vector::iterator demod_i; + for (demod_i = demodulators.begin(); demod_i != demodulators.end(); demod_i++) { + DemodulatorInstance *demod = *demod_i; if (demod->getFrequency() != data_in->frequency - && abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) { + && abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) { continue; } activeDemods++; } - - if (demodulators.size()) { - - DemodulatorThreadIQData *demodDataOut = buffers.getBuffer(); - -// std::lock_guard < std::mutex > lock(demodDataOut->m_mutex); - demodDataOut->frequency = data_in->frequency; - demodDataOut->sampleRate = data_in->sampleRate; - demodDataOut->setRefCount(activeDemods); - demodDataOut->data.assign(dataOut.begin(), dataOut.end()); - - std::vector::iterator i; - for (i = demodulators.begin(); i != demodulators.end(); i++) { - DemodulatorInstance *demod = *i; - DemodulatorThreadInputQueue *demodQueue = demod->getIQInputDataPipe(); - - if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) { - if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) { - demod->setActive(false); - DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData; - dummyDataOut->frequency = data_in->frequency; - dummyDataOut->sampleRate = data_in->sampleRate; - demodQueue->push(dummyDataOut); - } - - if (demod->isFollow() && wxGetApp().getFrequency() != demod->getFrequency()) { - wxGetApp().setFrequency(demod->getFrequency()); - } - } else if (!demod->isActive()) { - demod->setActive(true); - if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) { - wxGetApp().getDemodMgr().setActiveDemodulator(demod); - } + + if (iqDataOutQueue != NULL) { + activeDemods++; + } + + DemodulatorThreadIQData *demodDataOut = buffers.getBuffer(); + + // std::lock_guard < std::mutex > lock(demodDataOut->m_mutex); + demodDataOut->frequency = data_in->frequency; + demodDataOut->sampleRate = data_in->sampleRate; + demodDataOut->setRefCount(activeDemods); + demodDataOut->data.assign(dataOut.begin(), dataOut.end()); + + for (demod_i = demodulators.begin(); demod_i != demodulators.end(); demod_i++) { + DemodulatorInstance *demod = *demod_i; + DemodulatorThreadInputQueue *demodQueue = demod->getIQInputDataPipe(); + + if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) { + if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) { + demod->setActive(false); + DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData; + dummyDataOut->frequency = data_in->frequency; + dummyDataOut->sampleRate = data_in->sampleRate; + demodQueue->push(dummyDataOut); } - - if (!demod->isActive()) { - continue; + + if (demod->isFollow() && wxGetApp().getFrequency() != demod->getFrequency()) { + wxGetApp().setFrequency(demod->getFrequency()); } - if (demod->isFollow()) { - demod->setFollow(false); + } else if (!demod->isActive()) { + demod->setActive(true); + if (wxGetApp().getDemodMgr().getLastActiveDemodulator() == NULL) { + wxGetApp().getDemodMgr().setActiveDemodulator(demod); } - - demodQueue->push(demodDataOut); - pushedData = true; } - - if (!pushedData) { - demodDataOut->setRefCount(0); + + if (!demod->isActive()) { + continue; } + if (demod->isFollow()) { + demod->setFollow(false); + } + + demodQueue->push(demodDataOut); + pushedData = true; + } + + if (iqDataOutQueue != NULL) { + iqDataOutQueue->push(demodDataOut); + pushedData = true; + } + + if (!pushedData && iqDataOutQueue == NULL) { + demodDataOut->setRefCount(0); } } - + busy_demod.unlock(); } data_in->decRefCount(); diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index a5269e2..af56d8f 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -140,7 +140,7 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { initGLExtensions(); glViewport(0, 0, ClientSize.x, ClientSize.y); - if (!visualDataQueue.empty()) { + while (!visualDataQueue.empty()) { SpectrumVisualData *vData; visualDataQueue.pop(vData);