diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 3fed1be..89394ae 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -36,7 +36,7 @@ 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) { + 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) { glContext = new WaterfallContext(this, &wxGetApp().GetContext(this)); @@ -64,6 +64,14 @@ void WaterfallCanvas::setup(int fft_size_in, int waterfall_lines_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); } @@ -394,6 +402,8 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) { spectrum_points.resize(fft_size * 2); } + unsigned int num_written; + if (isView) { if (!input->frequency || !input->sampleRate) { return; @@ -447,104 +457,129 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) { resampleBuffer.resize(out_size); } - unsigned int num_written; msresamp_crcf_execute(resampler, &shiftBuffer[0], input->data.size(), &resampleBuffer[0], &num_written); resampleBuffer.resize(fft_size); if (num_written < fft_size) { for (int i = 0; i < num_written; i++) { - in[i][0] = resampleBuffer[i].real; - in[i][1] = resampleBuffer[i].imag; + 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++) { - in[i][0] = 0; - in[i][1] = 0; + fft_in_data[i][0] = 0; + fft_in_data[i][1] = 0; } } else { for (int i = 0; i < fft_size; i++) { - in[i][0] = resampleBuffer[i].real; - in[i][1] = resampleBuffer[i].imag; + 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++) { - in[i][0] = (*data)[i].real; - in[i][1] = (*data)[i].imag; + 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++) { - in[i][0] = 0; - in[i][1] = 0; + fft_in_data[i][0] = 0; + fft_in_data[i][1] = 0; } } else { for (int i = 0; i < fft_size; i++) { - in[i][0] = (*data)[i].real; - in[i][1] = (*data)[i].imag; + fft_in_data[i][0] = (*data)[i].real; + fft_in_data[i][1] = (*data)[i].imag; } } } - fftwf_execute(plan); + bool execute = false; - float fft_ceil = 0, fft_floor = 1; + if (num_written >= fft_size) { + execute = true; + memcpy(in, fft_in_data, sizeof(fftwf_complex) * fft_size * sizeof(fftwf_complex)); + memcpy(fft_last_data, in, fft_size * sizeof(fftwf_complex)); - 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++) { - n = (i == 0) ? 1 : i; - float a = out[n][0]; - float b = out[n][1]; - float c = sqrt(a * a + b * b); - - float x = out[fft_size / 2 + n][0]; - float y = out[fft_size / 2 + n][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 { + if (last_data_size + num_written < fft_size) { // priming + unsigned int num_copy = fft_size; + 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 { - 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]; + 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)); } } - fft_ceil += 0.25; - fft_floor -= 1; + if (execute) { + fftwf_execute(plan); - 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; + float fft_ceil = 0, fft_floor = 1; - 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; + if (fft_result.size() < fft_size) { + fft_result.resize(fft_size); + fft_result_ma.resize(fft_size); + fft_result_maa.resize(fft_size); + } - 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; - } + int n; + for (int i = 0, iMax = fft_size / 2; i < iMax; i++) { + n = (i == 0) ? 1 : i; + float a = out[n][0]; + float b = out[n][1]; + float c = sqrt(a * a + b * b); - if (spectrumCanvas) { - spectrumCanvas->spectrum_points.assign(spectrum_points.begin(), spectrum_points.end()); + float x = out[fft_size / 2 + n][0]; + float y = out[fft_size / 2 + n][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()); + } } } } diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index 07ed755..f2cd994 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -56,7 +56,8 @@ private: WaterfallCanvas *otherWaterfallCanvas; bool polling; - fftwf_complex *in, *out; + 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; @@ -84,6 +85,8 @@ private: std::vector shiftBuffer; std::vector resampleBuffer; + + // event table wxDECLARE_EVENT_TABLE(); };