Demodulator now has it's own spectrum view

This commit is contained in:
Charles J. Cliffe 2014-12-29 00:24:10 -05:00
parent d642cc63fd
commit 4403824e3b
20 changed files with 183 additions and 82 deletions

View File

@ -28,13 +28,14 @@ EVT_IDLE(AppFrame::OnIdle)
wxEND_EVENT_TABLE()
AppFrame::AppFrame() :
wxFrame(NULL, wxID_ANY, wxT("CubicSDR")) {
wxFrame(NULL, wxID_ANY, wxT("CubicSDR")) {
wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *demodOpts = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *demodVisuals = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *demodTray = new wxBoxSizer(wxHORIZONTAL);
/*
demodTray->AddSpacer(5);
demodOpts->AddSpacer(5);
@ -63,12 +64,19 @@ wxFrame(NULL, wxID_ANY, wxT("CubicSDR")) {
demodOpts->AddSpacer(5);
demodTray->AddSpacer(5);
demodTray->Add(demodOpts, 1, wxEXPAND | wxALL, 0);
demodTray->Add(demodOpts, 1, wxEXPAND | wxALL, 0); */
demodSpectrumCanvas = new SpectrumCanvas(this, NULL);
demodSpectrumCanvas->Setup(1024);
demodSpectrumCanvas->SetView(DEFAULT_FREQ, 300000);
demodVisuals->Add(demodSpectrumCanvas, 1, wxEXPAND | wxALL, 0);
demodVisuals->AddSpacer(1);
demodWaterfallCanvas = new WaterfallCanvas(this, NULL);
demodWaterfallCanvas->Setup(1024,128);
demodWaterfallCanvas->SetView(DEFAULT_FREQ,300000);
demodWaterfallCanvas->Setup(1024, 256);
demodWaterfallCanvas->SetView(DEFAULT_FREQ, 300000);
demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas);
demodVisuals->Add(demodWaterfallCanvas, 3, wxEXPAND | wxALL, 0);
demodTray->Add(demodVisuals, 7, wxEXPAND | wxALL, 0);
@ -85,7 +93,8 @@ wxFrame(NULL, wxID_ANY, wxT("CubicSDR")) {
vbox->Add(spectrumCanvas, 1, wxEXPAND | wxALL, 0);
vbox->AddSpacer(2);
waterfallCanvas = new WaterfallCanvas(this, NULL);
waterfallCanvas->Setup(2048,512);
waterfallCanvas->Setup(2048, 512);
waterfallCanvas->attachSpectrumCanvas(spectrumCanvas);
vbox->Add(waterfallCanvas, 4, wxEXPAND | wxALL, 0);
this->SetSizer(vbox);
@ -149,13 +158,15 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) {
if (demod->getParams().frequency != demodWaterfallCanvas->GetCenterFrequency()) {
demodWaterfallCanvas->SetCenterFrequency(demod->getParams().frequency);
demodSpectrumCanvas->SetCenterFrequency(demod->getParams().frequency);
}
unsigned int demodBw = (unsigned int) ceil((float) demod->getParams().bandwidth * 2.5);
if (demodBw > SRATE/2) {
demodBw = SRATE/2;
if (demodBw > SRATE / 2) {
demodBw = SRATE / 2;
}
if (demodBw != demodWaterfallCanvas->GetBandwidth()) {
demodWaterfallCanvas->SetBandwidth(demodBw);
demodSpectrumCanvas->SetBandwidth(demodBw);
}
}
}
@ -165,7 +176,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
wxGetApp().getIQVisualQueue()->pop(iqData);
if (iqData && iqData->data.size()) {
spectrumCanvas->setData(iqData);
// spectrumCanvas->setData(iqData);
waterfallCanvas->setData(iqData);
demodWaterfallCanvas->setData(iqData);
delete iqData;
@ -188,7 +199,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
scopeCanvas->waveform_points[i * 2] = ((double) i / (double) iMax);
}
scopeCanvas->setDivider(demodAudioData->channels == 2);
scopeCanvas->setStereo(demodAudioData->channels == 2);
delete demodAudioData;
} else {

View File

@ -23,6 +23,7 @@ private:
ScopeCanvas *scopeCanvas;
SpectrumCanvas *spectrumCanvas;
WaterfallCanvas *waterfallCanvas;
SpectrumCanvas *demodSpectrumCanvas;
WaterfallCanvas *demodWaterfallCanvas;
// event table

View File

@ -71,10 +71,10 @@ class DemodulatorThreadPostIQData: public ReferenceCounter {
public:
std::vector<liquid_float_complex> data;
int bandwidth;
float audio_resample_ratio;
double audio_resample_ratio;
msresamp_rrrf audio_resampler;
msresamp_rrrf stereo_resampler;
float resample_ratio;
double resample_ratio;
msresamp_crcf resampler;
DemodulatorThreadPostIQData() :

View File

@ -30,32 +30,17 @@ DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* pQueueIn
void DemodulatorPreThread::initialize() {
initialized = false;
resample_ratio = (float) (params.bandwidth) / (float) params.inputRate;
audio_resample_ratio = (float) (params.audioSampleRate) / (float) params.bandwidth;
resample_ratio = (double) (params.bandwidth) / (double) params.inputRate;
audio_resample_ratio = (double) (params.audioSampleRate) / (double) params.bandwidth;
float As = 60.0f; // stop-band attenuation [dB]
// create multi-stage arbitrary resampler object
if (resampler) {
msresamp_crcf_destroy(resampler);
}
resampler = msresamp_crcf_create(resample_ratio, As);
// msresamp_crcf_print(resampler);
if (audio_resampler) {
msresamp_rrrf_destroy(audio_resampler);
}
audio_resampler = msresamp_rrrf_create(audio_resample_ratio, As);
// msresamp_crcf_print(audio_resampler);
if (stereo_resampler) {
msresamp_rrrf_destroy(stereo_resampler);
}
stereo_resampler = msresamp_rrrf_create(audio_resample_ratio, As);
initialized = true;
// std::cout << "inputResampleRate " << params.bandwidth << std::endl;
last_params = params;
}
@ -68,12 +53,12 @@ DemodulatorPreThread::~DemodulatorPreThread() {
#ifdef __APPLE__
void *DemodulatorPreThread::threadMain() {
#else
void DemodulatorPreThread::threadMain() {
void DemodulatorPreThread::threadMain() {
#endif
#ifdef __APPLE__
pthread_t tID = pthread_self(); // ID of this thread
int priority = sched_get_priority_max( SCHED_FIFO) - 1;
sched_param prio = { priority }; // scheduling priority of thread
sched_param prio = {priority}; // scheduling priority of thread
pthread_setschedparam(tID, SCHED_FIFO, &prio);
#endif
@ -137,13 +122,13 @@ void *DemodulatorPreThread::threadMain() {
if (inp->frequency != params.frequency) {
if ((params.frequency - inp->frequency) != shift_freq) {
shift_freq = params.frequency - inp->frequency;
if (abs(shift_freq) <= (int) ((float) (SRATE / 2) * 1.5)) {
nco_crcf_set_frequency(nco_shift, (2.0 * M_PI) * (((float) abs(shift_freq)) / ((float) SRATE)));
if (abs(shift_freq) <= (int) ((double) (SRATE / 2) * 1.5)) {
nco_crcf_set_frequency(nco_shift, (2.0 * M_PI) * (((double) abs(shift_freq)) / ((double) SRATE)));
}
}
}
if (abs(shift_freq) > (int) ((float) (SRATE / 2) * 1.5)) {
if (abs(shift_freq) > (int) ((double) (SRATE / 2) * 1.5)) {
continue;
}

View File

@ -53,11 +53,11 @@ protected:
AudioThreadInputQueue *audioInputQueue;
msresamp_crcf resampler;
float resample_ratio;
double resample_ratio;
msresamp_rrrf audio_resampler;
msresamp_rrrf stereo_resampler;
float audio_resample_ratio;
double audio_resample_ratio;
DemodulatorThreadParameters params;
DemodulatorThreadParameters last_params;

View File

@ -36,7 +36,7 @@ void DemodulatorThread::threadMain() {
firfilt_rrrf fir_filter2 = NULL;
msresamp_crcf resampler = NULL;
float fc = 0.5 * ((double) 36000 / (double) AUDIO_FREQUENCY); // filter cutoff frequency
double fc = 0.5 * ((double) 36000 / (double) AUDIO_FREQUENCY); // filter cutoff frequency
if (fc <= 0) {
fc = 0;
}
@ -61,7 +61,7 @@ void DemodulatorThread::threadMain() {
firhilbf firC2R = firhilbf_create(m, slsl);
nco_crcf nco_shift = nco_crcf_create(LIQUID_NCO);
float shift_freq = 0;
double shift_freq = 0;
agc = agc_crcf_create();
agc_crcf_set_bandwidth(agc, 1e-3f);
@ -105,7 +105,7 @@ void DemodulatorThread::threadMain() {
stereo_resampler = inp->stereo_resampler;
}
int out_size = ceil((float) (bufSize) * inp->resample_ratio);
int out_size = ceil((double) (bufSize) * inp->resample_ratio);
if (agc_data.size() != out_size) {
if (agc_data.capacity() < out_size) {
@ -121,7 +121,7 @@ void DemodulatorThread::threadMain() {
agc_crcf_execute_block(agc, &resampled_data[0], num_written, &agc_data[0]);
float audio_resample_ratio = inp->audio_resample_ratio;
double audio_resample_ratio = inp->audio_resample_ratio;
if (demod_output.size() != num_written) {
if (demod_output.capacity() < num_written) {
@ -130,7 +130,7 @@ void DemodulatorThread::threadMain() {
demod_output.resize(num_written);
}
int audio_out_size = ceil((float) (num_written) * audio_resample_ratio);
int audio_out_size = ceil((double) (num_written) * audio_resample_ratio);
freqdem_demodulate_block(fdem, &agc_data[0], num_written, &demod_output[0]);
@ -152,7 +152,7 @@ void DemodulatorThread::threadMain() {
demod_output_stereo.resize(num_written);
}
double freq = (2.0 * M_PI) * (((float) abs(38000)) / ((float) inp->bandwidth));
double freq = (2.0 * M_PI) * (((double) abs(38000)) / ((double) inp->bandwidth));
if (shift_freq != freq) {
nco_crcf_set_frequency(nco_shift, freq);

View File

@ -58,5 +58,6 @@ protected:
DemodulatorThreadCommandQueue* threadQueueNotify;
DemodulatorThreadControlCommandQueue *threadQueueControl;
float squelch_level;
float squelch_tolerance;bool squelch_enabled;
float squelch_tolerance;
bool squelch_enabled;
};

View File

@ -34,8 +34,8 @@ void DemodulatorWorkerThread::threadMain() {
if (filterChanged) {
DemodulatorWorkerThreadResult result(DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS);
result.resample_ratio = (float) (filterCommand.bandwidth) / (float) filterCommand.inputRate;
result.audio_resample_ratio = (float) (filterCommand.audioSampleRate) / (float) filterCommand.bandwidth;
result.resample_ratio = (double) (filterCommand.bandwidth) / (double) filterCommand.inputRate;
result.audio_resample_ratio = (double) (filterCommand.audioSampleRate) / (double) filterCommand.bandwidth;
float As = 60.0f; // stop-band attenuation [dB]
@ -46,8 +46,8 @@ void DemodulatorWorkerThread::threadMain() {
result.audioSampleRate = filterCommand.audioSampleRate;
result.bandwidth = filterCommand.bandwidth;
result.inputRate = filterCommand.inputRate;
resultQueue->push(result);
std::this_thread::sleep_for(std::chrono::milliseconds(30));
}
}

View File

@ -36,10 +36,10 @@ public:
DemodulatorThreadResultEnum cmd;
msresamp_crcf resampler;
float resample_ratio;
double resample_ratio;
msresamp_rrrf audio_resampler;
msresamp_rrrf stereo_resampler;
float audio_resample_ratio;
double audio_resample_ratio;
unsigned int inputRate;
unsigned int bandwidth;

View File

@ -132,7 +132,7 @@ void SDRPostThread::threadMain() {
DemodulatorInstance *demod = *i;
if (demod->getParams().frequency != data_in->frequency
&& abs(data_in->frequency - demod->getParams().frequency) > (int) ((float) ((float) SRATE / 2.0))) {
&& abs(data_in->frequency - demod->getParams().frequency) > (int) ((double) ((double) SRATE / 2.0))) {
continue;
}
activeDemods++;
@ -166,7 +166,7 @@ void SDRPostThread::threadMain() {
DemodulatorThreadInputQueue *demodQueue = demod->threadQueueDemod;
if (demod->getParams().frequency != data_in->frequency
&& abs(data_in->frequency - demod->getParams().frequency) > (int) ((float) ((float) SRATE / 2.0))) {
&& abs(data_in->frequency - demod->getParams().frequency) > (int) ((double) ((double) SRATE / 2.0))) {
if (demod->isActive()) {
demod->setActive(false);
DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData;

View File

@ -21,7 +21,7 @@ wxEND_EVENT_TABLE()
ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) :
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
wxFULL_REPAINT_ON_RESIZE), parent(parent), frameTimer(0), divider(false) {
wxFULL_REPAINT_ON_RESIZE), parent(parent), frameTimer(0), stereo(false) {
glContext = new ScopeContext(this, &wxGetApp().GetContext(this));
timer.start();
@ -35,8 +35,8 @@ void ScopeCanvas::setWaveformPoints(std::vector<float> &waveform_points_in) {
waveform_points = waveform_points_in;
}
void ScopeCanvas::setDivider(bool state) {
divider = state;
void ScopeCanvas::setStereo(bool state) {
stereo = state;
}
void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
@ -47,10 +47,7 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
glViewport(0, 0, ClientSize.x, ClientSize.y);
glContext->DrawBegin();
glContext->Plot(waveform_points);
if (divider) {
glContext->DrawDivider();
}
glContext->Plot(waveform_points, stereo);
glContext->DrawEnd();
SwapBuffers();

View File

@ -19,7 +19,7 @@ public:
~ScopeCanvas();
void setWaveformPoints(std::vector<float> &waveform_points_in);
void setDivider(bool state);
void setStereo(bool state);
private:
void OnPaint(wxPaintEvent& event);
@ -30,7 +30,7 @@ private:
ScopeContext *glContext;
Timer timer;
float frameTimer;
bool divider;
bool stereo;
// event table
wxDECLARE_EVENT_TABLE();
};

View File

@ -20,18 +20,57 @@ void ScopeContext::DrawBegin() {
glDisable (GL_TEXTURE_2D);
}
void ScopeContext::Plot(std::vector<float> &points) {
void ScopeContext::Plot(std::vector<float> &points, bool stereo) {
glColor3f(1.0, 1.0, 1.0);
if (stereo) {
glColor3f(0.7, 0.7, 0.7);
glBegin(GL_LINES);
glVertex2f(-1.0,0.0);
glVertex2f(1.0,0.0);
glEnd();
glColor3f(0.3, 0.3, 0.3);
glBegin(GL_LINES);
glVertex2f(-1.0,0.5);
glVertex2f(1.0,0.5);
glVertex2f(-1.0,-0.5);
glVertex2f(1.0,-0.5);
glEnd();
} else {
glColor3f(0.3, 0.3, 0.3);
glBegin(GL_LINES);
glVertex2f(-1.0,0.0);
glVertex2f(1.0,0.0);
glEnd();
}
glColor3f(0.9, 0.9, 0.9);
if (points.size()) {
glPushMatrix();
glTranslatef(-1.0f, 0.0f, 0.0f);
glScalef(2.0f, 2.0f, 1.0f);
glEnableClientState (GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, &points[0]);
glDrawArrays(GL_LINE_STRIP, 0, points.size() / 2);
if (stereo) {
glPushMatrix();
glTranslatef(-1.0f, 0.5f, 0.0f);
glScalef(4.0f, 0.92f, 1.0f);
glDrawArrays(GL_LINE_STRIP, 0, points.size() / 4);
glPopMatrix();
glPushMatrix();
glTranslatef(-3.0f, -0.5f, 0.0f);
glPushMatrix();
glScalef(4.0f, 0.92f, 1.0f);
glDrawArrays(GL_LINE_STRIP, points.size() / 4, points.size() / 4);
glPopMatrix();
glPopMatrix();
} else {
glPushMatrix();
glTranslatef(-1.0f, 0.0f, 0.0f);
glScalef(2.0f, 2.0f, 1.0f);
glDrawArrays(GL_LINE_STRIP, 0, points.size() / 2);
glPopMatrix();
}
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
}

View File

@ -12,7 +12,7 @@ public:
ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext);
void DrawBegin();
void Plot(std::vector<float> &points);
void Plot(std::vector<float> &points, bool stereo=false);
void DrawDivider();
void DrawEnd();

View File

@ -27,7 +27,7 @@ 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) {
wxFULL_REPAINT_ON_RESIZE), parent(parent), fft_size(0), in(NULL), out(NULL), plan(NULL), center_freq(0), bandwidth(0), isView(0) {
glContext = new SpectrumContext(this, &wxGetApp().GetContext(this));
@ -74,12 +74,12 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
glViewport(0, 0, ClientSize.x, ClientSize.y);
glContext->BeginDraw();
glContext->Draw(spectrum_points);
glContext->Draw(spectrum_points, GetCenterFrequency(), GetBandwidth());
std::vector<DemodulatorInstance *> &demods = wxGetApp().getDemodMgr().getDemodulators();
for (int i = 0, iMax = demods.size(); i < iMax; i++) {
glContext->DrawDemodInfo(demods[i]);
glContext->DrawDemodInfo(demods[i], 1, 1, 1, GetCenterFrequency(), GetBandwidth());
}
glContext->EndDraw();
@ -171,6 +171,41 @@ void SpectrumCanvas::setData(DemodulatorThreadIQData *input) {
}
}
void SpectrumCanvas::SetView(int center_freq_in, int bandwidth_in) {
isView = true;
center_freq = center_freq_in;
bandwidth = bandwidth_in;
}
void SpectrumCanvas::DisableView() {
isView = false;
}
void SpectrumCanvas::SetCenterFrequency(unsigned int center_freq_in) {
center_freq = center_freq_in;
}
unsigned int SpectrumCanvas::GetCenterFrequency() {
if (isView) {
return center_freq;
} else {
return (unsigned int) wxGetApp().getFrequency();
}
}
void SpectrumCanvas::SetBandwidth(unsigned int bandwidth_in) {
bandwidth = bandwidth_in;
}
unsigned int SpectrumCanvas::GetBandwidth() {
if (isView) {
return bandwidth;
} else {
return SRATE;
}
}
void SpectrumCanvas::OnIdle(wxIdleEvent &event) {
// timer.update();
// frameTimer += timer.lastUpdateSeconds();
@ -183,7 +218,7 @@ void SpectrumCanvas::OnIdle(wxIdleEvent &event) {
void SpectrumCanvas::mouseMoved(wxMouseEvent& event) {
mTracker.OnMouseMoved(event);
if (mTracker.mouseDown()) {
int freqChange = mTracker.getDeltaMouseX() * SRATE;
int freqChange = mTracker.getDeltaMouseX() * GetBandwidth();
if (freqChange != 0) {
int freq = wxGetApp().getFrequency();

View File

@ -14,11 +14,23 @@
class SpectrumCanvas: public wxGLCanvas {
public:
std::vector<float> spectrum_points;
SpectrumCanvas(wxWindow *parent, int *attribList = NULL);
void Setup(int fft_size_in);
~SpectrumCanvas();
void setData(DemodulatorThreadIQData *input);
void SetView(int center_freq_in, int bandwidth_in);
void DisableView();
void SetCenterFrequency(unsigned int center_freq_in);
unsigned int GetCenterFrequency();
void SetBandwidth(unsigned int bandwidth_in);
unsigned int GetBandwidth();
private:
void OnPaint(wxPaintEvent& event);
@ -33,7 +45,6 @@ private:
void mouseLeftWindow(wxMouseEvent& event);
wxWindow *parent;
std::vector<float> spectrum_points;
fftw_complex *in, *out;
fftw_plan plan;
@ -48,6 +59,11 @@ private:
SpectrumContext *glContext;
int fft_size;
unsigned int center_freq;
unsigned int bandwidth;
bool isView;
MouseTracker mTracker;
// event table
wxDECLARE_EVENT_TABLE();

View File

@ -6,7 +6,7 @@
#include <iostream>
SpectrumContext::SpectrumContext(SpectrumCanvas *canvas, wxGLContext *sharedContext) :
PrimaryGLContext(canvas, sharedContext) {
PrimaryGLContext(canvas, sharedContext), fft_size(0) {
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
@ -15,7 +15,7 @@ SpectrumContext::SpectrumContext(SpectrumCanvas *canvas, wxGLContext *sharedCont
}
void SpectrumContext::Draw(std::vector<float> &points) {
void SpectrumContext::Draw(std::vector<float> &points, int freq, int bandwidth) {
glDisable(GL_TEXTURE_2D);
glColor3f(1.0, 1.0, 1.0);
@ -35,9 +35,10 @@ void SpectrumContext::Draw(std::vector<float> &points) {
glGetIntegerv( GL_VIEWPORT, vp);
float viewHeight = (float) vp[3];
float viewWidth = (float) vp[2];
float leftFreq = (float) wxGetApp().getFrequency() - ((float) SRATE / 2.0);
float rightFreq = leftFreq + (float) SRATE;
float leftFreq = (float) freq - ((float) bandwidth / 2.0);
float rightFreq = leftFreq + (float) bandwidth;
float firstMhz = floor(leftFreq / 1000000.0) * 1000000.0;
float mhzStart = ((firstMhz - leftFreq) / (rightFreq - leftFreq)) * 2.0;

View File

@ -11,7 +11,7 @@ class SpectrumContext: public PrimaryGLContext {
public:
SpectrumContext(SpectrumCanvas *canvas, wxGLContext *sharedContext);
void Draw(std::vector<float> &points);
void Draw(std::vector<float> &points, int freq, int bandwidth);
private:
int fft_size;

View File

@ -17,6 +17,8 @@
#include <wx/numformatter.h>
#define MIN_FM_BANDWIDTH 10000
wxBEGIN_EVENT_TABLE(WaterfallCanvas, wxGLCanvas) EVT_PAINT(WaterfallCanvas::OnPaint)
EVT_KEY_DOWN(WaterfallCanvas::OnKeyDown)
EVT_KEY_UP(WaterfallCanvas::OnKeyUp)
@ -30,7 +32,7 @@ wxEND_EVENT_TABLE()
WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
wxFULL_REPAINT_ON_RESIZE), parent(parent), frameTimer(0), activeDemodulatorBandwidth(0), activeDemodulatorFrequency(0), dragState(
wxFULL_REPAINT_ON_RESIZE), parent(parent), spectrumCanvas(NULL), frameTimer(0), 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) {
@ -126,6 +128,11 @@ WaterfallCanvas::DragState WaterfallCanvas::getNextDragState() {
return nextDragState;
}
void WaterfallCanvas::attachSpectrumCanvas(SpectrumCanvas *canvas_in) {
spectrumCanvas = canvas_in;
}
void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
wxPaintDC dc(this);
const wxSize ClientSize = GetClientSize();
@ -427,6 +434,10 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) {
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());
}
}
}
@ -467,11 +478,11 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) {
DemodulatorThreadCommand command;
command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_BANDWIDTH;
activeDemodulatorBandwidth = activeDemodulatorBandwidth + bwDiff;
if (activeDemodulatorBandwidth < 2000) {
activeDemodulatorBandwidth = 2000;
if (activeDemodulatorBandwidth > SRATE) {
activeDemodulatorBandwidth = SRATE;
}
if (activeDemodulatorBandwidth > GetBandwidth()) {
activeDemodulatorBandwidth = GetBandwidth();
if (activeDemodulatorBandwidth < MIN_FM_BANDWIDTH) {
activeDemodulatorBandwidth = MIN_FM_BANDWIDTH;
}
command.int_value = activeDemodulatorBandwidth;
@ -661,8 +672,8 @@ void WaterfallCanvas::mouseReleased(wxMouseEvent& event) {
unsigned int freq = input_center_freq - (int) (0.5 * (float) GetBandwidth()) + (int) ((float) pos * (float) GetBandwidth());
unsigned int bw = (unsigned int) (fabs(width) * (float) GetBandwidth());
if (bw < 2000) {
bw = 2000;
if (bw < MIN_FM_BANDWIDTH) {
bw = MIN_FM_BANDWIDTH;
}
if (!bw) {

View File

@ -8,6 +8,7 @@
#include "WaterfallContext.h"
#include "MouseTracker.h"
#include "SpectrumCanvas.h"
#include "fftw3.h"
#include "Timer.h"
@ -37,6 +38,8 @@ public:
DragState getDragState();
DragState getNextDragState();
void attachSpectrumCanvas(SpectrumCanvas *canvas_in);
private:
void OnPaint(wxPaintEvent& event);
void OnKeyDown(wxKeyEvent& event);
@ -52,6 +55,7 @@ private:
void mouseLeftWindow(wxMouseEvent& event);
wxWindow *parent;
SpectrumCanvas *spectrumCanvas;
std::vector<float> spectrum_points;
fftw_complex *in, *out;