mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2024-11-26 13:48:38 -05:00
Zoomed-in demodulator waterfall somewhat working
- update demod WF from demodulator is jittery - adjustments with immediate update is awkward
This commit is contained in:
parent
a3f8bc08e7
commit
1e970f4373
@ -28,7 +28,7 @@ EVT_IDLE(AppFrame::OnIdle)
|
|||||||
wxEND_EVENT_TABLE()
|
wxEND_EVENT_TABLE()
|
||||||
|
|
||||||
AppFrame::AppFrame() :
|
AppFrame::AppFrame() :
|
||||||
wxFrame(NULL, wxID_ANY, wxT("CubicSDR")) {
|
wxFrame(NULL, wxID_ANY, wxT("CubicSDR")) {
|
||||||
|
|
||||||
wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
|
wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
|
||||||
wxBoxSizer *demodTray = new wxBoxSizer(wxHORIZONTAL);
|
wxBoxSizer *demodTray = new wxBoxSizer(wxHORIZONTAL);
|
||||||
@ -64,15 +64,22 @@ AppFrame::AppFrame() :
|
|||||||
|
|
||||||
demodTray->Add(demodOpts, 1, wxEXPAND | wxALL, 0);
|
demodTray->Add(demodOpts, 1, wxEXPAND | wxALL, 0);
|
||||||
|
|
||||||
|
demodWaterfallCanvas = new WaterfallCanvas(this, NULL);
|
||||||
|
demodWaterfallCanvas->Setup(1024,128);
|
||||||
|
demodWaterfallCanvas->SetView(DEFAULT_FREQ,300000);
|
||||||
|
demodTray->Add(demodWaterfallCanvas, 7, wxEXPAND | wxALL, 0);
|
||||||
|
|
||||||
scopeCanvas = new ScopeCanvas(this, NULL);
|
scopeCanvas = new ScopeCanvas(this, NULL);
|
||||||
demodTray->Add(scopeCanvas, 7, wxEXPAND | wxALL, 0);
|
demodTray->Add(scopeCanvas, 7, wxEXPAND | wxALL, 0);
|
||||||
|
|
||||||
vbox->Add(demodTray, 1, wxEXPAND | wxALL, 0);
|
vbox->Add(demodTray, 1, wxEXPAND | wxALL, 0);
|
||||||
vbox->AddSpacer(2);
|
vbox->AddSpacer(2);
|
||||||
spectrumCanvas = new SpectrumCanvas(this, NULL);
|
spectrumCanvas = new SpectrumCanvas(this, NULL);
|
||||||
|
spectrumCanvas->Setup(2048);
|
||||||
vbox->Add(spectrumCanvas, 1, wxEXPAND | wxALL, 0);
|
vbox->Add(spectrumCanvas, 1, wxEXPAND | wxALL, 0);
|
||||||
vbox->AddSpacer(2);
|
vbox->AddSpacer(2);
|
||||||
waterfallCanvas = new WaterfallCanvas(this, NULL);
|
waterfallCanvas = new WaterfallCanvas(this, NULL);
|
||||||
|
waterfallCanvas->Setup(2048,512);
|
||||||
vbox->Add(waterfallCanvas, 4, wxEXPAND | wxALL, 0);
|
vbox->Add(waterfallCanvas, 4, wxEXPAND | wxALL, 0);
|
||||||
|
|
||||||
this->SetSizer(vbox);
|
this->SetSizer(vbox);
|
||||||
@ -129,14 +136,27 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
|||||||
// std::this_thread::sleep_for(std::chrono::milliseconds(4));
|
// std::this_thread::sleep_for(std::chrono::milliseconds(4));
|
||||||
// std::this_thread::yield();
|
// std::this_thread::yield();
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
|
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||||
|
|
||||||
|
if (demod) {
|
||||||
|
if (demod->getParams().frequency != demodWaterfallCanvas->GetCenterFrequency()) {
|
||||||
|
demodWaterfallCanvas->SetCenterFrequency(demod->getParams().frequency);
|
||||||
|
}
|
||||||
|
unsigned int demodBw = (unsigned int) ceil((float) demod->getParams().bandwidth * 1.5);
|
||||||
|
if (demodBw != demodWaterfallCanvas->GetBandwidth()) {
|
||||||
|
demodWaterfallCanvas->SetBandwidth(demodBw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!wxGetApp().getIQVisualQueue()->empty()) {
|
if (!wxGetApp().getIQVisualQueue()->empty()) {
|
||||||
DemodulatorThreadIQData *iqData;
|
DemodulatorThreadIQData *iqData;
|
||||||
wxGetApp().getIQVisualQueue()->pop(iqData);
|
wxGetApp().getIQVisualQueue()->pop(iqData);
|
||||||
|
|
||||||
if (iqData && iqData->data.size()) {
|
if (iqData && iqData->data.size()) {
|
||||||
spectrumCanvas->setData(&iqData->data);
|
spectrumCanvas->setData(iqData);
|
||||||
waterfallCanvas->setData(&iqData->data);
|
waterfallCanvas->setData(iqData);
|
||||||
|
demodWaterfallCanvas->setData(iqData);
|
||||||
delete iqData;
|
delete iqData;
|
||||||
} else {
|
} else {
|
||||||
std::cout << "Incoming IQ data empty?" << std::endl;
|
std::cout << "Incoming IQ data empty?" << std::endl;
|
||||||
@ -148,8 +168,8 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
|||||||
AudioThreadInput *demodAudioData;
|
AudioThreadInput *demodAudioData;
|
||||||
wxGetApp().getAudioVisualQueue()->pop(demodAudioData);
|
wxGetApp().getAudioVisualQueue()->pop(demodAudioData);
|
||||||
if (demodAudioData && demodAudioData->data.size()) {
|
if (demodAudioData && demodAudioData->data.size()) {
|
||||||
if (scopeCanvas->waveform_points.size() != demodAudioData->data.size()*2) {
|
if (scopeCanvas->waveform_points.size() != demodAudioData->data.size() * 2) {
|
||||||
scopeCanvas->waveform_points.resize(demodAudioData->data.size()*2);
|
scopeCanvas->waveform_points.resize(demodAudioData->data.size() * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0, iMax = demodAudioData->data.size(); i < iMax; i++) {
|
for (int i = 0, iMax = demodAudioData->data.size(); i < iMax; i++) {
|
||||||
|
@ -23,7 +23,8 @@ private:
|
|||||||
ScopeCanvas *scopeCanvas;
|
ScopeCanvas *scopeCanvas;
|
||||||
SpectrumCanvas *spectrumCanvas;
|
SpectrumCanvas *spectrumCanvas;
|
||||||
WaterfallCanvas *waterfallCanvas;
|
WaterfallCanvas *waterfallCanvas;
|
||||||
|
WaterfallCanvas *demodWaterfallCanvas;
|
||||||
|
|
||||||
// event table
|
// event table
|
||||||
wxDECLARE_EVENT_TABLE();
|
wxDECLARE_EVENT_TABLE();
|
||||||
};
|
};
|
||||||
|
@ -28,6 +28,7 @@ bool CubicSDR::OnInit() {
|
|||||||
sdrThread = new SDRThread(threadCmdQueueSDR);
|
sdrThread = new SDRThread(threadCmdQueueSDR);
|
||||||
|
|
||||||
sdrPostThread = new SDRPostThread();
|
sdrPostThread = new SDRPostThread();
|
||||||
|
sdrPostThread->setNumVisSamples(2048);
|
||||||
|
|
||||||
iqPostDataQueue = new SDRThreadIQDataQueue;
|
iqPostDataQueue = new SDRThreadIQDataQueue;
|
||||||
iqVisualQueue = new DemodulatorThreadInputQueue;
|
iqVisualQueue = new DemodulatorThreadInputQueue;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#define BUF_SIZE (16384*4)
|
#define BUF_SIZE (16384*4)
|
||||||
#define SRATE 2500000
|
#define SRATE 2500000
|
||||||
#endif
|
#endif
|
||||||
#define FFT_SIZE 2048
|
#define DEFAULT_FFT_SIZE 2048
|
||||||
|
|
||||||
#define DEFAULT_FREQ 98900000
|
#define DEFAULT_FREQ 98900000
|
||||||
#define AUDIO_FREQUENCY 44100
|
#define AUDIO_FREQUENCY 44100
|
||||||
|
@ -367,7 +367,7 @@ void AudioThread::setActive(bool state) {
|
|||||||
while (!inputQueue->empty()) { // flush queue
|
while (!inputQueue->empty()) { // flush queue
|
||||||
inputQueue->pop(dummy);
|
inputQueue->pop(dummy);
|
||||||
if (dummy) {
|
if (dummy) {
|
||||||
delete dummy;
|
dummy->decRefCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deviceController[parameters.deviceId]->bindThread(this);
|
deviceController[parameters.deviceId]->bindThread(this);
|
||||||
@ -376,7 +376,7 @@ void AudioThread::setActive(bool state) {
|
|||||||
while (!inputQueue->empty()) { // flush queue
|
while (!inputQueue->empty()) { // flush queue
|
||||||
inputQueue->pop(dummy);
|
inputQueue->pop(dummy);
|
||||||
if (dummy) {
|
if (dummy) {
|
||||||
delete dummy;
|
dummy->decRefCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
|
|
||||||
DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* pQueueIn, DemodulatorThreadPostInputQueue* pQueueOut,
|
DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* pQueueIn, DemodulatorThreadPostInputQueue* pQueueOut,
|
||||||
DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) :
|
DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) :
|
||||||
inputQueue(pQueueIn), postInputQueue(pQueueOut), terminated(false), initialized(false), audio_resampler(NULL), stereo_resampler(NULL), resample_ratio(1), audio_resample_ratio(
|
inputQueue(pQueueIn), postInputQueue(pQueueOut), terminated(false), initialized(false), audio_resampler(NULL), stereo_resampler(NULL), resample_ratio(
|
||||||
1), resampler(NULL), commandQueue(NULL), audioInputQueue(NULL), threadQueueNotify(threadQueueNotify), threadQueueControl(
|
1), audio_resample_ratio(1), resampler(NULL), commandQueue(NULL), audioInputQueue(NULL), threadQueueNotify(threadQueueNotify), threadQueueControl(
|
||||||
threadQueueControl) {
|
threadQueueControl) {
|
||||||
|
|
||||||
float kf = 0.5; // modulation factor
|
float kf = 0.5; // modulation factor
|
||||||
@ -53,7 +53,6 @@ void DemodulatorPreThread::initialize() {
|
|||||||
}
|
}
|
||||||
stereo_resampler = msresamp_rrrf_create(audio_resample_ratio, As);
|
stereo_resampler = msresamp_rrrf_create(audio_resample_ratio, As);
|
||||||
|
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
// std::cout << "inputResampleRate " << params.bandwidth << std::endl;
|
// std::cout << "inputResampleRate " << params.bandwidth << std::endl;
|
||||||
|
|
||||||
@ -69,12 +68,12 @@ DemodulatorPreThread::~DemodulatorPreThread() {
|
|||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
void *DemodulatorPreThread::threadMain() {
|
void *DemodulatorPreThread::threadMain() {
|
||||||
#else
|
#else
|
||||||
void DemodulatorPreThread::threadMain() {
|
void DemodulatorPreThread::threadMain() {
|
||||||
#endif
|
#endif
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
pthread_t tID = pthread_self(); // ID of this thread
|
pthread_t tID = pthread_self(); // ID of this thread
|
||||||
int priority = sched_get_priority_max( SCHED_FIFO )-1;
|
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);
|
pthread_setschedparam(tID, SCHED_FIFO, &prio);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -162,7 +161,7 @@ void DemodulatorPreThread::threadMain() {
|
|||||||
out_buf_data.resize(bufSize);
|
out_buf_data.resize(bufSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
in_buf_data.assign(inp->data.begin(),inp->data.end());
|
in_buf_data.assign(inp->data.begin(), inp->data.end());
|
||||||
|
|
||||||
liquid_float_complex *in_buf = &in_buf_data[0];
|
liquid_float_complex *in_buf = &in_buf_data[0];
|
||||||
liquid_float_complex *out_buf = &out_buf_data[0];
|
liquid_float_complex *out_buf = &out_buf_data[0];
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
SDRPostThread::SDRPostThread() :
|
SDRPostThread::SDRPostThread() :
|
||||||
sample_rate(SRATE), iqDataOutQueue(NULL), iqDataInQueue(NULL), iqVisualQueue(NULL), terminated(false), dcFilter(NULL) {
|
sample_rate(SRATE), iqDataOutQueue(NULL), iqDataInQueue(NULL), iqVisualQueue(NULL), terminated(false), dcFilter(NULL), num_vis_samples(2048) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SDRPostThread::~SDRPostThread() {
|
SDRPostThread::~SDRPostThread() {
|
||||||
@ -34,6 +34,14 @@ void SDRPostThread::setIQVisualQueue(DemodulatorThreadInputQueue *iqVisQueue) {
|
|||||||
iqVisualQueue = iqVisQueue;
|
iqVisualQueue = iqVisQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SDRPostThread::setNumVisSamples(int num_vis_samples_in) {
|
||||||
|
num_vis_samples = num_vis_samples_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDRPostThread::getNumVisSamples() {
|
||||||
|
return num_vis_samples;
|
||||||
|
}
|
||||||
|
|
||||||
void SDRPostThread::threadMain() {
|
void SDRPostThread::threadMain() {
|
||||||
int n_read;
|
int n_read;
|
||||||
double seconds = 0.0;
|
double seconds = 0.0;
|
||||||
@ -89,7 +97,9 @@ void SDRPostThread::threadMain() {
|
|||||||
|
|
||||||
if (iqVisualQueue != NULL && iqVisualQueue.load()->empty()) {
|
if (iqVisualQueue != NULL && iqVisualQueue.load()->empty()) {
|
||||||
DemodulatorThreadIQData *visualDataOut = new DemodulatorThreadIQData;
|
DemodulatorThreadIQData *visualDataOut = new DemodulatorThreadIQData;
|
||||||
visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + FFT_SIZE);
|
visualDataOut->frequency = data_in->frequency;
|
||||||
|
visualDataOut->bandwidth = data_in->bandwidth;
|
||||||
|
visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples);
|
||||||
iqVisualQueue.load()->push(visualDataOut);
|
iqVisualQueue.load()->push(visualDataOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,9 @@ public:
|
|||||||
void setIQDataOutQueue(DemodulatorThreadInputQueue* iqDataQueue);
|
void setIQDataOutQueue(DemodulatorThreadInputQueue* iqDataQueue);
|
||||||
void setIQVisualQueue(DemodulatorThreadInputQueue* iqVisQueue);
|
void setIQVisualQueue(DemodulatorThreadInputQueue* iqVisQueue);
|
||||||
|
|
||||||
|
void setNumVisSamples(int num_vis_samples_in);
|
||||||
|
int getNumVisSamples();
|
||||||
|
|
||||||
void threadMain();
|
void threadMain();
|
||||||
void terminate();
|
void terminate();
|
||||||
|
|
||||||
@ -30,4 +33,5 @@ protected:
|
|||||||
std::vector<DemodulatorInstance *> demodulators_remove;
|
std::vector<DemodulatorInstance *> demodulators_remove;
|
||||||
std::atomic<bool> terminated;
|
std::atomic<bool> terminated;
|
||||||
iirfilt_crcf dcFilter;
|
iirfilt_crcf dcFilter;
|
||||||
|
int num_vis_samples;
|
||||||
};
|
};
|
||||||
|
@ -92,7 +92,7 @@ GLFont &PrimaryGLContext::getFont(GLFontSize esize) {
|
|||||||
return fonts[esize];
|
return fonts[esize];
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float g, float b) {
|
void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float g, float b, int center_freq, int srate) {
|
||||||
if (!demod) {
|
if (!demod) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -103,7 +103,11 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float
|
|||||||
float viewHeight = (float) vp[3];
|
float viewHeight = (float) vp[3];
|
||||||
float viewWidth = (float) vp[2];
|
float viewWidth = (float) vp[2];
|
||||||
|
|
||||||
float uxPos = (float) (demod->getParams().frequency - (wxGetApp().getFrequency() - SRATE / 2)) / (float) SRATE;
|
if (center_freq == -1) {
|
||||||
|
center_freq = wxGetApp().getFrequency();
|
||||||
|
}
|
||||||
|
|
||||||
|
float uxPos = (float) (demod->getParams().frequency - (center_freq - srate / 2)) / (float) srate;
|
||||||
uxPos = (uxPos - 0.5) * 2.0;
|
uxPos = (uxPos - 0.5) * 2.0;
|
||||||
|
|
||||||
glDisable(GL_TEXTURE_2D);
|
glDisable(GL_TEXTURE_2D);
|
||||||
@ -112,7 +116,7 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float
|
|||||||
glBlendFunc(GL_SRC_ALPHA, GL_DST_COLOR);
|
glBlendFunc(GL_SRC_ALPHA, GL_DST_COLOR);
|
||||||
glColor4f(r, g, b, 0.6);
|
glColor4f(r, g, b, 0.6);
|
||||||
|
|
||||||
float ofs = ((float) demod->getParams().bandwidth) / (float) SRATE;
|
float ofs = ((float) demod->getParams().bandwidth) / (float) srate;
|
||||||
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_DST_COLOR);
|
glBlendFunc(GL_SRC_ALPHA, GL_DST_COLOR);
|
||||||
glColor4f(r, g, b, 0.2);
|
glColor4f(r, g, b, 0.2);
|
||||||
@ -149,12 +153,16 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, float r, float g, float b) {
|
void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, float r, float g, float b, int center_freq, int srate) {
|
||||||
if (!demod) {
|
if (!demod) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float uxPos = (float) (demod->getParams().frequency - (wxGetApp().getFrequency() - SRATE / 2)) / (float) SRATE;
|
if (center_freq == -1) {
|
||||||
|
center_freq = wxGetApp().getFrequency();
|
||||||
|
}
|
||||||
|
|
||||||
|
float uxPos = (float) (demod->getParams().frequency - (center_freq - srate / 2)) / (float) srate;
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glDisable(GL_TEXTURE_2D);
|
glDisable(GL_TEXTURE_2D);
|
||||||
@ -167,7 +175,7 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, float r, float g, f
|
|||||||
glVertex3f((uxPos - 0.5) * 2.0, 1.0, 0.0);
|
glVertex3f((uxPos - 0.5) * 2.0, 1.0, 0.0);
|
||||||
glVertex3f((uxPos - 0.5) * 2.0, -1.0, 0.0);
|
glVertex3f((uxPos - 0.5) * 2.0, -1.0, 0.0);
|
||||||
|
|
||||||
float ofs = ((float) demod->getParams().bandwidth) / (float) SRATE;
|
float ofs = ((float) demod->getParams().bandwidth) / (float) srate;
|
||||||
|
|
||||||
glVertex3f((uxPos - 0.5) * 2.0 - ofs, 1.0, 0.0);
|
glVertex3f((uxPos - 0.5) * 2.0 - ofs, 1.0, 0.0);
|
||||||
glVertex3f((uxPos - 0.5) * 2.0 - ofs, -1.0, 0.0);
|
glVertex3f((uxPos - 0.5) * 2.0 - ofs, -1.0, 0.0);
|
||||||
@ -191,7 +199,7 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, float r, float g, f
|
|||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrimaryGLContext::DrawFreqSelector(float uxPos, float r, float g, float b, float w) {
|
void PrimaryGLContext::DrawFreqSelector(float uxPos, float r, float g, float b, float w, int center_freq, int srate) {
|
||||||
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||||
|
|
||||||
int bw = 0;
|
int bw = 0;
|
||||||
@ -218,7 +226,7 @@ void PrimaryGLContext::DrawFreqSelector(float uxPos, float r, float g, float b,
|
|||||||
if (w) {
|
if (w) {
|
||||||
ofs = w;
|
ofs = w;
|
||||||
} else {
|
} else {
|
||||||
ofs = ((float) bw) / (float) SRATE;
|
ofs = ((float) bw) / (float) srate;
|
||||||
}
|
}
|
||||||
|
|
||||||
glVertex3f((uxPos - 0.5) * 2.0 - ofs, 1.0, 0.0);
|
glVertex3f((uxPos - 0.5) * 2.0 - ofs, 1.0, 0.0);
|
||||||
|
@ -23,9 +23,9 @@ public:
|
|||||||
void BeginDraw();
|
void BeginDraw();
|
||||||
void EndDraw();
|
void EndDraw();
|
||||||
|
|
||||||
void DrawFreqSelector(float uxPos, float r = 1, float g = 1, float b = 1, float w = 0);
|
void DrawFreqSelector(float uxPos, float r = 1, float g = 1, float b = 1, float w = 0, int center_freq = -1, int srate = SRATE);
|
||||||
void DrawDemod(DemodulatorInstance *demod, float r = 1, float g = 1, float b = 1);
|
void DrawDemod(DemodulatorInstance *demod, float r = 1, float g = 1, float b = 1, int center_freq = -1, int srate = SRATE);
|
||||||
void DrawDemodInfo(DemodulatorInstance *demod, float r = 1, float g = 1, float b = 1);
|
void DrawDemodInfo(DemodulatorInstance *demod, float r = 1, float g = 1, float b = 1, int center_freq = -1, int srate = SRATE);
|
||||||
|
|
||||||
static GLFont &getFont(GLFontSize esize);
|
static GLFont &getFont(GLFontSize esize);
|
||||||
|
|
||||||
|
@ -27,20 +27,9 @@ wxEND_EVENT_TABLE()
|
|||||||
|
|
||||||
SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) :
|
SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) :
|
||||||
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
|
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
|
||||||
wxFULL_REPAINT_ON_RESIZE), parent(parent), frameTimer(0) {
|
wxFULL_REPAINT_ON_RESIZE), parent(parent), frameTimer(0), fft_size(0), in(NULL), out(NULL), plan(NULL) {
|
||||||
|
|
||||||
int in_block_size = FFT_SIZE;
|
|
||||||
int out_block_size = FFT_SIZE;
|
|
||||||
|
|
||||||
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * in_block_size);
|
|
||||||
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * out_block_size);
|
|
||||||
plan = fftw_plan_dft_1d(out_block_size, in, out, FFTW_FORWARD, FFTW_MEASURE);
|
|
||||||
|
|
||||||
fft_ceil_ma = fft_ceil_maa = 100.0;
|
|
||||||
fft_floor_ma = fft_floor_maa = 0.0;
|
|
||||||
|
|
||||||
glContext = new SpectrumContext(this, &wxGetApp().GetContext(this));
|
glContext = new SpectrumContext(this, &wxGetApp().GetContext(this));
|
||||||
timer.start();
|
|
||||||
|
|
||||||
mTracker.setTarget(this);
|
mTracker.setTarget(this);
|
||||||
mTracker.setVertDragLock(true);
|
mTracker.setVertDragLock(true);
|
||||||
@ -48,6 +37,33 @@ SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) :
|
|||||||
SetCursor(wxCURSOR_SIZEWE);
|
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 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * fft_size);
|
||||||
|
if (out) {
|
||||||
|
free(out);
|
||||||
|
}
|
||||||
|
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * fft_size);
|
||||||
|
if (plan) {
|
||||||
|
fftw_destroy_plan(plan);
|
||||||
|
}
|
||||||
|
plan = fftw_plan_dft_1d(fft_size, in, out, FFTW_FORWARD, FFTW_MEASURE);
|
||||||
|
|
||||||
|
|
||||||
|
fft_ceil_ma = fft_ceil_maa = 100.0;
|
||||||
|
fft_floor_ma = fft_floor_maa = 0.0;
|
||||||
|
|
||||||
|
timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
SpectrumCanvas::~SpectrumCanvas() {
|
SpectrumCanvas::~SpectrumCanvas() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -73,14 +89,23 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
|||||||
SwapBuffers();
|
SwapBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectrumCanvas::setData(std::vector<liquid_float_complex> *data) {
|
void SpectrumCanvas::setData(DemodulatorThreadIQData *input) {
|
||||||
|
if (!input) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::vector<liquid_float_complex> *data = &input->data;
|
||||||
if (data && data->size()) {
|
if (data && data->size()) {
|
||||||
if (spectrum_points.size() < FFT_SIZE * 2) {
|
if (fft_size != data->size()) {
|
||||||
spectrum_points.resize(FFT_SIZE * 2);
|
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++) {
|
for (int i = 0; i < fft_size; i++) {
|
||||||
in[i][0] = (*data)[i].real;
|
in[i][0] = (*data)[i].real;
|
||||||
in[i][1] = (*data)[i].imag;
|
in[i][1] = (*data)[i].imag;
|
||||||
}
|
}
|
||||||
@ -89,31 +114,34 @@ void SpectrumCanvas::setData(std::vector<liquid_float_complex> *data) {
|
|||||||
|
|
||||||
double fft_ceil = 0, fft_floor = 1;
|
double fft_ceil = 0, fft_floor = 1;
|
||||||
|
|
||||||
if (fft_result.size() < FFT_SIZE) {
|
if (fft_result.size() != fft_size) {
|
||||||
fft_result.resize(FFT_SIZE);
|
if (fft_result.capacity() < fft_size) {
|
||||||
fft_result_ma.resize(FFT_SIZE);
|
fft_result.reserve(fft_size);
|
||||||
fft_result_maa.resize(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;
|
int n;
|
||||||
for (int i = 0, iMax = FFT_SIZE / 2; i < iMax; i++) {
|
for (int i = 0, iMax = fft_size / 2; i < iMax; i++) {
|
||||||
n = (i == 0) ? 1 : i;
|
n = (i == 0) ? 1 : i;
|
||||||
double a = out[n][0];
|
double a = out[n][0];
|
||||||
double b = out[n][1];
|
double b = out[n][1];
|
||||||
double c = sqrt(a * a + b * b);
|
double c = sqrt(a * a + b * b);
|
||||||
|
|
||||||
// n = (i == FFT_SIZE / 2) ? (FFT_SIZE / 2 + 1) : i;
|
// n = (i == FFT_SIZE / 2) ? (FFT_SIZE / 2 + 1) : i;
|
||||||
double x = out[FFT_SIZE / 2 + n][0];
|
double x = out[fft_size / 2 + n][0];
|
||||||
double y = out[FFT_SIZE / 2 + n][1];
|
double y = out[fft_size / 2 + n][1];
|
||||||
double z = sqrt(x * x + y * y);
|
double z = sqrt(x * x + y * y);
|
||||||
|
|
||||||
fft_result[i] = (z);
|
fft_result[i] = (z);
|
||||||
fft_result[FFT_SIZE / 2 + i] = (c);
|
fft_result[fft_size / 2 + i] = (c);
|
||||||
}
|
}
|
||||||
|
|
||||||
float time_slice = (float) SRATE / (float) (BUF_SIZE / 2);
|
for (int i = 0, iMax = fft_size; i < iMax; i++) {
|
||||||
|
|
||||||
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_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;
|
fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65;
|
||||||
|
|
||||||
@ -136,7 +164,7 @@ void SpectrumCanvas::setData(std::vector<liquid_float_complex> *data) {
|
|||||||
|
|
||||||
// fftw_execute(plan[1]);
|
// fftw_execute(plan[1]);
|
||||||
|
|
||||||
for (int i = 0, iMax = FFT_SIZE; i < iMax; i++) {
|
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));
|
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] = ((float) i / (float) iMax);
|
||||||
spectrum_points[i * 2 + 1] = v;
|
spectrum_points[i * 2 + 1] = v;
|
||||||
|
@ -15,9 +15,10 @@
|
|||||||
class SpectrumCanvas: public wxGLCanvas {
|
class SpectrumCanvas: public wxGLCanvas {
|
||||||
public:
|
public:
|
||||||
SpectrumCanvas(wxWindow *parent, int *attribList = NULL);
|
SpectrumCanvas(wxWindow *parent, int *attribList = NULL);
|
||||||
|
void Setup(int fft_size_in);
|
||||||
~SpectrumCanvas();
|
~SpectrumCanvas();
|
||||||
|
|
||||||
void setData(std::vector<liquid_float_complex> *data);
|
void setData(DemodulatorThreadIQData *input);
|
||||||
private:
|
private:
|
||||||
void OnPaint(wxPaintEvent& event);
|
void OnPaint(wxPaintEvent& event);
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ private:
|
|||||||
SpectrumContext *glContext;
|
SpectrumContext *glContext;
|
||||||
Timer timer;
|
Timer timer;
|
||||||
float frameTimer;
|
float frameTimer;
|
||||||
|
int fft_size;
|
||||||
|
|
||||||
MouseTracker mTracker;
|
MouseTracker mTracker;
|
||||||
// event table
|
// event table
|
||||||
|
@ -14,4 +14,5 @@ public:
|
|||||||
void Draw(std::vector<float> &points);
|
void Draw(std::vector<float> &points);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int fft_size;
|
||||||
};
|
};
|
||||||
|
@ -29,39 +29,93 @@ EVT_ENTER_WINDOW(WaterfallCanvas::mouseEnterWindow)
|
|||||||
wxEND_EVENT_TABLE()
|
wxEND_EVENT_TABLE()
|
||||||
|
|
||||||
WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
|
WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) :
|
||||||
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
|
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), frameTimer(0), activeDemodulatorBandwidth(0), activeDemodulatorFrequency(0), dragState(
|
||||||
WF_DRAG_NONE), nextDragState(WF_DRAG_NONE), shiftDown(false), altDown(false), ctrlDown(false) {
|
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) {
|
||||||
|
|
||||||
int in_block_size = FFT_SIZE;
|
|
||||||
int out_block_size = FFT_SIZE;
|
|
||||||
|
|
||||||
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * in_block_size);
|
|
||||||
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * out_block_size);
|
|
||||||
plan = fftw_plan_dft_1d(out_block_size, in, out, FFTW_FORWARD, FFTW_MEASURE);
|
|
||||||
|
|
||||||
fft_ceil_ma = fft_ceil_maa = 100.0;
|
|
||||||
fft_floor_ma = fft_floor_maa = 0.0;
|
|
||||||
|
|
||||||
glContext = new WaterfallContext(this, &wxGetApp().GetContext(this));
|
glContext = new WaterfallContext(this, &wxGetApp().GetContext(this));
|
||||||
timer.start();
|
|
||||||
|
nco_shift = nco_crcf_create(LIQUID_NCO);
|
||||||
|
shift_freq = 0;
|
||||||
|
|
||||||
mTracker.setTarget(this);
|
mTracker.setTarget(this);
|
||||||
SetCursor(wxCURSOR_CROSS);
|
SetCursor(wxCURSOR_CROSS);
|
||||||
}
|
}
|
||||||
|
|
||||||
WaterfallCanvas::~WaterfallCanvas() {
|
WaterfallCanvas::~WaterfallCanvas() {
|
||||||
|
nco_crcf_destroy(nco_shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaterfallCanvas::SetView(int center_freq_in, int bandwidth_in) {
|
||||||
|
isView = true;
|
||||||
|
center_freq = center_freq_in;
|
||||||
|
bandwidth = bandwidth_in;
|
||||||
|
last_bandwidth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaterfallCanvas::DisableView() {
|
||||||
|
isView = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaterfallCanvas::Setup(int fft_size_in, int waterfall_lines_in) {
|
||||||
|
if (fft_size == fft_size_in && waterfall_lines_in == waterfall_lines) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fft_size = fft_size_in;
|
||||||
|
waterfall_lines = waterfall_lines_in;
|
||||||
|
|
||||||
|
if (in) {
|
||||||
|
free(in);
|
||||||
|
}
|
||||||
|
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * fft_size);
|
||||||
|
if (out) {
|
||||||
|
free(out);
|
||||||
|
}
|
||||||
|
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * fft_size);
|
||||||
|
if (plan) {
|
||||||
|
fftw_destroy_plan(plan);
|
||||||
|
}
|
||||||
|
plan = fftw_plan_dft_1d(fft_size, in, out, FFTW_FORWARD, FFTW_MEASURE);
|
||||||
|
|
||||||
|
fft_ceil_ma = fft_ceil_maa = 100.0;
|
||||||
|
fft_floor_ma = fft_floor_maa = 0.0;
|
||||||
|
|
||||||
|
glContext->Setup(fft_size, waterfall_lines);
|
||||||
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
int WaterfallCanvas::GetFrequencyAt(float x) {
|
int WaterfallCanvas::GetFrequencyAt(float x) {
|
||||||
|
int iqCenterFreq = GetCenterFrequency();
|
||||||
int center_freq = wxGetApp().getFrequency();
|
int iqBandwidth = GetBandwidth();
|
||||||
int freq = center_freq - (int) (0.5 * (float) SRATE) + (int) ((float) x * (float) SRATE);
|
int freq = iqCenterFreq - (int) (0.5 * (float) iqBandwidth) + (int) ((float) x * (float) iqBandwidth);
|
||||||
|
|
||||||
return freq;
|
return freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WaterfallCanvas::SetCenterFrequency(unsigned int center_freq_in) {
|
||||||
|
center_freq = center_freq_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int WaterfallCanvas::GetCenterFrequency() {
|
||||||
|
if (isView) {
|
||||||
|
return center_freq;
|
||||||
|
} else {
|
||||||
|
return (unsigned int)wxGetApp().getFrequency();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaterfallCanvas::SetBandwidth(unsigned int bandwidth_in) {
|
||||||
|
bandwidth = bandwidth_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int WaterfallCanvas::GetBandwidth() {
|
||||||
|
if (isView) {
|
||||||
|
return bandwidth;
|
||||||
|
} else {
|
||||||
|
return SRATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||||
wxPaintDC dc(this);
|
wxPaintDC dc(this);
|
||||||
const wxSize ClientSize = GetClientSize();
|
const wxSize ClientSize = GetClientSize();
|
||||||
@ -80,6 +134,9 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
|||||||
bool isNew = shiftDown
|
bool isNew = shiftDown
|
||||||
|| (wxGetApp().getDemodMgr().getLastActiveDemodulator() && !wxGetApp().getDemodMgr().getLastActiveDemodulator()->isActive());
|
|| (wxGetApp().getDemodMgr().getLastActiveDemodulator() && !wxGetApp().getDemodMgr().getLastActiveDemodulator()->isActive());
|
||||||
|
|
||||||
|
int currentBandwidth = GetBandwidth();
|
||||||
|
int currentCenterFreq = GetCenterFrequency();
|
||||||
|
|
||||||
if (mTracker.mouseInView()) {
|
if (mTracker.mouseInView()) {
|
||||||
if (nextDragState == WF_DRAG_RANGE) {
|
if (nextDragState == WF_DRAG_RANGE) {
|
||||||
if (mTracker.mouseDown()) {
|
if (mTracker.mouseDown()) {
|
||||||
@ -87,47 +144,49 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
|||||||
float centerPos = mTracker.getOriginMouseX() + width / 2.0;
|
float centerPos = mTracker.getOriginMouseX() + width / 2.0;
|
||||||
|
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
glContext->DrawDemod(lastActiveDemodulator);
|
glContext->DrawDemod(lastActiveDemodulator, 1, 1, 1, currentCenterFreq, currentBandwidth);
|
||||||
glContext->DrawFreqSelector(centerPos, 0, 1, 0, width ? width : (1.0 / (float) ClientSize.x));
|
glContext->DrawFreqSelector(centerPos, 0, 1, 0, width ? width : (1.0 / (float) ClientSize.x), currentCenterFreq,
|
||||||
|
currentBandwidth);
|
||||||
} else {
|
} else {
|
||||||
glContext->DrawDemod(lastActiveDemodulator, 1, 0, 0);
|
glContext->DrawDemod(lastActiveDemodulator, 1, 0, 0, currentCenterFreq, currentBandwidth);
|
||||||
glContext->DrawFreqSelector(centerPos, 1, 1, 0, width ? width : (1.0 / (float) ClientSize.x));
|
glContext->DrawFreqSelector(centerPos, 1, 1, 0, width ? width : (1.0 / (float) ClientSize.x), currentCenterFreq,
|
||||||
|
currentBandwidth);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
glContext->DrawDemod(lastActiveDemodulator);
|
glContext->DrawDemod(lastActiveDemodulator, 1, 1, 1, currentCenterFreq, currentBandwidth);
|
||||||
glContext->DrawFreqSelector(mTracker.getMouseX(), 0, 1, 0, 1.0 / (float) ClientSize.x);
|
glContext->DrawFreqSelector(mTracker.getMouseX(), 0, 1, 0, 1.0 / (float) ClientSize.x, currentCenterFreq, currentBandwidth);
|
||||||
} else {
|
} else {
|
||||||
glContext->DrawDemod(lastActiveDemodulator, 1, 0, 0);
|
glContext->DrawDemod(lastActiveDemodulator, 1, 0, 0, currentCenterFreq, currentBandwidth);
|
||||||
glContext->DrawFreqSelector(mTracker.getMouseX(), 1, 1, 0, 1.0 / (float) ClientSize.x);
|
glContext->DrawFreqSelector(mTracker.getMouseX(), 1, 1, 0, 1.0 / (float) ClientSize.x, currentCenterFreq, currentBandwidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (activeDemodulator == NULL) {
|
if (activeDemodulator == NULL) {
|
||||||
if (lastActiveDemodulator) {
|
if (lastActiveDemodulator) {
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
glContext->DrawDemod(lastActiveDemodulator);
|
glContext->DrawDemod(lastActiveDemodulator, 1, 1, 1, currentCenterFreq, currentBandwidth);
|
||||||
glContext->DrawFreqSelector(mTracker.getMouseX(), 0, 1, 0);
|
glContext->DrawFreqSelector(mTracker.getMouseX(), 0, 1, 0, 0, currentCenterFreq, currentBandwidth);
|
||||||
} else {
|
} else {
|
||||||
glContext->DrawDemod(lastActiveDemodulator, 1, 0, 0);
|
glContext->DrawDemod(lastActiveDemodulator, 1, 0, 0, currentCenterFreq, currentBandwidth);
|
||||||
glContext->DrawFreqSelector(mTracker.getMouseX(), 1, 1, 0);
|
glContext->DrawFreqSelector(mTracker.getMouseX(), 1, 1, 0, 0, currentCenterFreq, currentBandwidth);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
glContext->DrawFreqSelector(mTracker.getMouseX(), 1, 1, 0);
|
glContext->DrawFreqSelector(mTracker.getMouseX(), 1, 1, 0, 0, currentCenterFreq, currentBandwidth);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (lastActiveDemodulator) {
|
if (lastActiveDemodulator) {
|
||||||
glContext->DrawDemod(lastActiveDemodulator);
|
glContext->DrawDemod(lastActiveDemodulator, 1, 1, 1, currentCenterFreq, currentBandwidth);
|
||||||
}
|
}
|
||||||
glContext->DrawDemod(activeDemodulator, 1, 1, 0);
|
glContext->DrawDemod(activeDemodulator, 1, 1, 0, currentCenterFreq, currentBandwidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (activeDemodulator) {
|
if (activeDemodulator) {
|
||||||
glContext->DrawDemod(activeDemodulator);
|
glContext->DrawDemod(activeDemodulator, 1, 1, 1, currentCenterFreq, currentBandwidth);
|
||||||
}
|
}
|
||||||
if (lastActiveDemodulator) {
|
if (lastActiveDemodulator) {
|
||||||
glContext->DrawDemod(lastActiveDemodulator);
|
glContext->DrawDemod(lastActiveDemodulator, 1, 1, 1, currentCenterFreq, currentBandwidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +194,7 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
|||||||
if (activeDemodulator == demods[i] || lastActiveDemodulator == demods[i]) {
|
if (activeDemodulator == demods[i] || lastActiveDemodulator == demods[i]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
glContext->DrawDemod(demods[i]);
|
glContext->DrawDemod(demods[i], 1, 1, 1, currentCenterFreq, currentBandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
glContext->EndDraw();
|
glContext->EndDraw();
|
||||||
@ -161,102 +220,178 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
|
|||||||
DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
|
DemodulatorInstance *activeDemod = wxGetApp().getDemodMgr().getActiveDemodulator();
|
||||||
|
|
||||||
unsigned int freq;
|
unsigned int freq;
|
||||||
switch (event.GetKeyCode()) {
|
if (!isView) {
|
||||||
case WXK_RIGHT:
|
switch (event.GetKeyCode()) {
|
||||||
freq = wxGetApp().getFrequency();
|
case WXK_RIGHT:
|
||||||
if (shiftDown) {
|
freq = wxGetApp().getFrequency();
|
||||||
freq += SRATE * 10;
|
if (shiftDown) {
|
||||||
} else {
|
freq += SRATE * 10;
|
||||||
freq += SRATE / 2;
|
} else {
|
||||||
}
|
freq += SRATE / 2;
|
||||||
wxGetApp().setFrequency(freq);
|
}
|
||||||
((wxFrame*) parent)->GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %i"), freq));
|
wxGetApp().setFrequency(freq);
|
||||||
break;
|
((wxFrame*) parent)->GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %i"), freq));
|
||||||
case WXK_LEFT:
|
|
||||||
freq = wxGetApp().getFrequency();
|
|
||||||
if (shiftDown) {
|
|
||||||
freq -= SRATE * 10;
|
|
||||||
} else {
|
|
||||||
freq -= SRATE / 2;
|
|
||||||
}
|
|
||||||
wxGetApp().setFrequency(freq);
|
|
||||||
((wxFrame*) parent)->GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %i"), freq));
|
|
||||||
break;
|
|
||||||
case 'D':
|
|
||||||
case WXK_DELETE:
|
|
||||||
if (!activeDemod) {
|
|
||||||
break;
|
break;
|
||||||
}
|
case WXK_LEFT:
|
||||||
wxGetApp().removeDemodulator(activeDemod);
|
freq = wxGetApp().getFrequency();
|
||||||
wxGetApp().getDemodMgr().deleteThread(activeDemod);
|
if (shiftDown) {
|
||||||
break;
|
freq -= SRATE * 10;
|
||||||
case 'S':
|
} else {
|
||||||
if (!activeDemod) {
|
freq -= SRATE / 2;
|
||||||
|
}
|
||||||
|
wxGetApp().setFrequency(freq);
|
||||||
|
((wxFrame*) parent)->GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %i"), freq));
|
||||||
break;
|
break;
|
||||||
|
case 'D':
|
||||||
|
case WXK_DELETE:
|
||||||
|
if (!activeDemod) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wxGetApp().removeDemodulator(activeDemod);
|
||||||
|
wxGetApp().getDemodMgr().deleteThread(activeDemod);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
if (!activeDemod) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (activeDemod->isSquelchEnabled()) {
|
||||||
|
activeDemod->setSquelchEnabled(false);
|
||||||
|
} else {
|
||||||
|
activeDemod->squelchAuto();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WXK_SPACE:
|
||||||
|
if (!activeDemod) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (activeDemod->isStereo()) {
|
||||||
|
activeDemod->setStereo(false);
|
||||||
|
} else {
|
||||||
|
activeDemod->setStereo(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
event.Skip();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (activeDemod->isSquelchEnabled()) {
|
|
||||||
activeDemod->setSquelchEnabled(false);
|
|
||||||
} else {
|
|
||||||
activeDemod->squelchAuto();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WXK_SPACE:
|
|
||||||
if (!activeDemod) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (activeDemod->isStereo()) {
|
|
||||||
activeDemod->setStereo(false);
|
|
||||||
} else {
|
|
||||||
activeDemod->setStereo(true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
event.Skip();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterfallCanvas::setData(std::vector<liquid_float_complex> *data) {
|
void WaterfallCanvas::setData(DemodulatorThreadIQData *input) {
|
||||||
|
if (!input) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<liquid_float_complex> *data = &input->data;
|
||||||
|
|
||||||
if (data && data->size()) {
|
if (data && data->size()) {
|
||||||
if (spectrum_points.size() < FFT_SIZE * 2) {
|
if (fft_size != data->size() && !isView) {
|
||||||
spectrum_points.resize(FFT_SIZE * 2);
|
Setup(data->size(), waterfall_lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < FFT_SIZE; i++) {
|
if (last_bandwidth != bandwidth && !isView) {
|
||||||
in[i][0] = (*data)[i].real;
|
Setup(bandwidth, waterfall_lines);
|
||||||
in[i][1] = (*data)[i].imag;
|
}
|
||||||
|
|
||||||
|
if (spectrum_points.size() < fft_size * 2) {
|
||||||
|
spectrum_points.resize(fft_size * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isView) {
|
||||||
|
if (!input->frequency || !input->bandwidth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (center_freq != input->frequency) {
|
||||||
|
if (((int)center_freq - (int)input->frequency) != shift_freq || last_input_bandwidth != input->bandwidth) {
|
||||||
|
if ((int)input->frequency - abs((int)center_freq) < (int) ((float) ((float) SRATE / 2.0))) {
|
||||||
|
shift_freq = (int)center_freq - (int)input->frequency;
|
||||||
|
nco_crcf_reset(nco_shift);
|
||||||
|
nco_crcf_set_frequency(nco_shift, (2.0 * M_PI) * (((float) abs(shift_freq)) / ((float) input->bandwidth)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shift_buffer.size() != input->data.size()) {
|
||||||
|
if (shift_buffer.capacity() < input->data.size()) {
|
||||||
|
shift_buffer.reserve(input->data.size());
|
||||||
|
}
|
||||||
|
shift_buffer.resize(input->data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shift_freq < 0) {
|
||||||
|
nco_crcf_mix_block_up(nco_shift, &input->data[0], &shift_buffer[0], input->data.size());
|
||||||
|
} else {
|
||||||
|
nco_crcf_mix_block_down(nco_shift, &input->data[0], &shift_buffer[0], input->data.size());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
shift_buffer.assign(input->data.begin(), input->data.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resampler || bandwidth != last_bandwidth || last_input_bandwidth != input->bandwidth) {
|
||||||
|
resample_ratio = (float) (bandwidth) / (float) input->bandwidth;
|
||||||
|
|
||||||
|
float As = 60.0f;
|
||||||
|
|
||||||
|
if (resampler) {
|
||||||
|
msresamp_crcf_destroy(resampler);
|
||||||
|
}
|
||||||
|
resampler = msresamp_crcf_create(resample_ratio, As);
|
||||||
|
|
||||||
|
last_bandwidth = bandwidth;
|
||||||
|
last_input_bandwidth = input->bandwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int out_size = ceil((float) (input->data.size()) * resample_ratio);
|
||||||
|
|
||||||
|
if (resampler_buffer.size() != out_size) {
|
||||||
|
if (resampler_buffer.capacity() < out_size) {
|
||||||
|
resampler_buffer.reserve(out_size);
|
||||||
|
}
|
||||||
|
resampler_buffer.resize(out_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int num_written;
|
||||||
|
msresamp_crcf_execute(resampler, &shift_buffer[0], input->data.size(), &resampler_buffer[0], &num_written);
|
||||||
|
|
||||||
|
resampler_buffer.resize(fft_size);
|
||||||
|
|
||||||
|
for (int i = 0; i < fft_size; i++) {
|
||||||
|
in[i][0] = resampler_buffer[i].real;
|
||||||
|
in[i][1] = resampler_buffer[i].imag;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < fft_size; i++) {
|
||||||
|
in[i][0] = (*data)[i].real;
|
||||||
|
in[i][1] = (*data)[i].imag;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fftw_execute(plan);
|
fftw_execute(plan);
|
||||||
|
|
||||||
double fft_ceil = 0, fft_floor = 1;
|
double fft_ceil = 0, fft_floor = 1;
|
||||||
|
|
||||||
if (fft_result.size() < FFT_SIZE) {
|
if (fft_result.size() < fft_size) {
|
||||||
fft_result.resize(FFT_SIZE);
|
fft_result.resize(fft_size);
|
||||||
fft_result_ma.resize(FFT_SIZE);
|
fft_result_ma.resize(fft_size);
|
||||||
fft_result_maa.resize(FFT_SIZE);
|
fft_result_maa.resize(fft_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int n;
|
int n;
|
||||||
for (int i = 0, iMax = FFT_SIZE / 2; i < iMax; i++) {
|
for (int i = 0, iMax = fft_size / 2; i < iMax; i++) {
|
||||||
n = (i == 0) ? 1 : i;
|
n = (i == 0) ? 1 : i;
|
||||||
double a = out[n][0];
|
double a = out[n][0];
|
||||||
double b = out[n][1];
|
double b = out[n][1];
|
||||||
double c = sqrt(a * a + b * b);
|
double c = sqrt(a * a + b * b);
|
||||||
|
|
||||||
// n = (i == FFT_SIZE / 2) ? (FFT_SIZE / 2 + 1) : i;
|
double x = out[fft_size / 2 + n][0];
|
||||||
double x = out[FFT_SIZE / 2 + n][0];
|
double y = out[fft_size / 2 + n][1];
|
||||||
double y = out[FFT_SIZE / 2 + n][1];
|
|
||||||
double z = sqrt(x * x + y * y);
|
double z = sqrt(x * x + y * y);
|
||||||
|
|
||||||
fft_result[i] = (z);
|
fft_result[i] = (z);
|
||||||
fft_result[FFT_SIZE / 2 + i] = (c);
|
fft_result[fft_size / 2 + i] = (c);
|
||||||
}
|
}
|
||||||
|
|
||||||
float time_slice = (float) SRATE / (float) (BUF_SIZE / 2);
|
for (int i = 0, iMax = fft_size; i < iMax; i++) {
|
||||||
|
|
||||||
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_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;
|
fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65;
|
||||||
|
|
||||||
@ -277,12 +412,11 @@ void WaterfallCanvas::setData(std::vector<liquid_float_complex> *data) {
|
|||||||
fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 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;
|
fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.01;
|
||||||
|
|
||||||
for (int i = 0, iMax = FFT_SIZE; i < iMax; i++) {
|
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));
|
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] = ((float) i / (float) iMax);
|
||||||
spectrum_points[i * 2 + 1] = v;
|
spectrum_points[i * 2 + 1] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +444,7 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) {
|
|||||||
}
|
}
|
||||||
if (dragState == WF_DRAG_BANDWIDTH_LEFT || dragState == WF_DRAG_BANDWIDTH_RIGHT) {
|
if (dragState == WF_DRAG_BANDWIDTH_LEFT || dragState == WF_DRAG_BANDWIDTH_RIGHT) {
|
||||||
|
|
||||||
int bwDiff = (int) (mTracker.getDeltaMouseX() * (float) SRATE) * 2;
|
int bwDiff = (int) (mTracker.getDeltaMouseX() * (float) GetBandwidth()) * 2;
|
||||||
|
|
||||||
if (dragState == WF_DRAG_BANDWIDTH_LEFT) {
|
if (dragState == WF_DRAG_BANDWIDTH_LEFT) {
|
||||||
bwDiff = -bwDiff;
|
bwDiff = -bwDiff;
|
||||||
@ -326,8 +460,8 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) {
|
|||||||
if (activeDemodulatorBandwidth < 2000) {
|
if (activeDemodulatorBandwidth < 2000) {
|
||||||
activeDemodulatorBandwidth = 2000;
|
activeDemodulatorBandwidth = 2000;
|
||||||
}
|
}
|
||||||
if (activeDemodulatorBandwidth > SRATE) {
|
if (activeDemodulatorBandwidth > GetBandwidth()) {
|
||||||
activeDemodulatorBandwidth = SRATE;
|
activeDemodulatorBandwidth = GetBandwidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
command.int_value = activeDemodulatorBandwidth;
|
command.int_value = activeDemodulatorBandwidth;
|
||||||
@ -335,7 +469,7 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dragState == WF_DRAG_FREQUENCY) {
|
if (dragState == WF_DRAG_FREQUENCY) {
|
||||||
int bwDiff = (int) (mTracker.getDeltaMouseX() * (float) SRATE);
|
int bwDiff = (int) (mTracker.getDeltaMouseX() * (float) GetBandwidth());
|
||||||
|
|
||||||
if (!activeDemodulatorFrequency) {
|
if (!activeDemodulatorFrequency) {
|
||||||
activeDemodulatorFrequency = demod->getParams().frequency;
|
activeDemodulatorFrequency = demod->getParams().frequency;
|
||||||
@ -363,7 +497,7 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) {
|
|||||||
mTracker.setHorizDragLock(false);
|
mTracker.setHorizDragLock(false);
|
||||||
} else if (demodsHover->size()) {
|
} else if (demodsHover->size()) {
|
||||||
int hovered = -1;
|
int hovered = -1;
|
||||||
int near_dist = SRATE;
|
int near_dist = GetBandwidth();
|
||||||
|
|
||||||
DemodulatorInstance *activeDemodulator = NULL;
|
DemodulatorInstance *activeDemodulator = NULL;
|
||||||
|
|
||||||
@ -397,7 +531,7 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) {
|
|||||||
int freqDiff = ((int) activeDemodulator->getParams().frequency - freqPos);
|
int freqDiff = ((int) activeDemodulator->getParams().frequency - freqPos);
|
||||||
|
|
||||||
if (abs(freqDiff) > (activeDemodulator->getParams().bandwidth / 3)) {
|
if (abs(freqDiff) > (activeDemodulator->getParams().bandwidth / 3)) {
|
||||||
SetCursor(wxCURSOR_SIZEWE);
|
SetCursor (wxCURSOR_SIZEWE);
|
||||||
|
|
||||||
if (freqDiff > 0) {
|
if (freqDiff > 0) {
|
||||||
nextDragState = WF_DRAG_BANDWIDTH_LEFT;
|
nextDragState = WF_DRAG_BANDWIDTH_LEFT;
|
||||||
@ -408,14 +542,14 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) {
|
|||||||
mTracker.setVertDragLock(true);
|
mTracker.setVertDragLock(true);
|
||||||
mTracker.setHorizDragLock(false);
|
mTracker.setHorizDragLock(false);
|
||||||
} else {
|
} else {
|
||||||
SetCursor(wxCURSOR_SIZING);
|
SetCursor (wxCURSOR_SIZING);
|
||||||
nextDragState = WF_DRAG_FREQUENCY;
|
nextDragState = WF_DRAG_FREQUENCY;
|
||||||
|
|
||||||
mTracker.setVertDragLock(true);
|
mTracker.setVertDragLock(true);
|
||||||
mTracker.setHorizDragLock(false);
|
mTracker.setHorizDragLock(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SetCursor(wxCURSOR_CROSS);
|
SetCursor (wxCURSOR_CROSS);
|
||||||
nextDragState = WF_DRAG_NONE;
|
nextDragState = WF_DRAG_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,8 +594,8 @@ void WaterfallCanvas::mouseReleased(wxMouseEvent& event) {
|
|||||||
|
|
||||||
if (mTracker.getOriginDeltaMouseX() == 0 && mTracker.getOriginDeltaMouseY() == 0) {
|
if (mTracker.getOriginDeltaMouseX() == 0 && mTracker.getOriginDeltaMouseY() == 0) {
|
||||||
float pos = mTracker.getMouseX();
|
float pos = mTracker.getMouseX();
|
||||||
int center_freq = wxGetApp().getFrequency();
|
int input_center_freq = GetCenterFrequency();
|
||||||
int freq = center_freq - (int) (0.5 * (float) SRATE) + (int) ((float) pos * (float) SRATE);
|
int freq = input_center_freq - (int) (0.5 * (float) GetBandwidth()) + (int) ((float) pos * (float) GetBandwidth());
|
||||||
|
|
||||||
if (dragState == WF_DRAG_NONE) {
|
if (dragState == WF_DRAG_NONE) {
|
||||||
if (!isNew && wxGetApp().getDemodMgr().getDemodulators().size()) {
|
if (!isNew && wxGetApp().getDemodMgr().getDemodulators().size()) {
|
||||||
@ -497,14 +631,14 @@ void WaterfallCanvas::mouseReleased(wxMouseEvent& event) {
|
|||||||
wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep)));
|
wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep)));
|
||||||
|
|
||||||
wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getLastActiveDemodulator(), false);
|
wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getLastActiveDemodulator(), false);
|
||||||
SetCursor(wxCURSOR_SIZING);
|
SetCursor (wxCURSOR_SIZING);
|
||||||
nextDragState = WF_DRAG_FREQUENCY;
|
nextDragState = WF_DRAG_FREQUENCY;
|
||||||
mTracker.setVertDragLock(true);
|
mTracker.setVertDragLock(true);
|
||||||
mTracker.setHorizDragLock(false);
|
mTracker.setHorizDragLock(false);
|
||||||
} else {
|
} else {
|
||||||
float pos = mTracker.getMouseX();
|
float pos = mTracker.getMouseX();
|
||||||
int center_freq = wxGetApp().getFrequency();
|
int input_center_freq = GetCenterFrequency();
|
||||||
int freq = center_freq - (int) (0.5 * (float) SRATE) + (int) ((float) pos * (float) SRATE);
|
int freq = input_center_freq - (int) (0.5 * (float) GetBandwidth()) + (int) ((float) pos * (float) GetBandwidth());
|
||||||
|
|
||||||
wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getActiveDemodulator(), false);
|
wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getActiveDemodulator(), false);
|
||||||
nextDragState = WF_DRAG_FREQUENCY;
|
nextDragState = WF_DRAG_FREQUENCY;
|
||||||
@ -513,15 +647,15 @@ void WaterfallCanvas::mouseReleased(wxMouseEvent& event) {
|
|||||||
float width = mTracker.getOriginDeltaMouseX();
|
float width = mTracker.getOriginDeltaMouseX();
|
||||||
float pos = mTracker.getOriginMouseX() + width / 2.0;
|
float pos = mTracker.getOriginMouseX() + width / 2.0;
|
||||||
|
|
||||||
int center_freq = wxGetApp().getFrequency();
|
int input_center_freq = GetCenterFrequency();
|
||||||
int freq = center_freq - (int) (0.5 * (float) SRATE) + (int) ((float) pos * (float) SRATE);
|
unsigned int freq = input_center_freq - (int) (0.5 * (float) GetBandwidth()) + (int) ((float) pos * (float) GetBandwidth());
|
||||||
int bandwidth = (int) (fabs(width) * (float) SRATE);
|
unsigned int bw = (unsigned int) (fabs(width) * (float) GetBandwidth());
|
||||||
|
|
||||||
if (bandwidth < 2000) {
|
if (bw < 2000) {
|
||||||
bandwidth = 2000;
|
bw = 2000;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bandwidth) {
|
if (!bw) {
|
||||||
dragState = WF_DRAG_NONE;
|
dragState = WF_DRAG_NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -531,7 +665,7 @@ void WaterfallCanvas::mouseReleased(wxMouseEvent& event) {
|
|||||||
} else {
|
} else {
|
||||||
demod = wxGetApp().getDemodMgr().newThread();
|
demod = wxGetApp().getDemodMgr().newThread();
|
||||||
demod->getParams().frequency = freq;
|
demod->getParams().frequency = freq;
|
||||||
demod->getParams().bandwidth = bandwidth;
|
demod->getParams().bandwidth = bw;
|
||||||
|
|
||||||
demod->run();
|
demod->run();
|
||||||
|
|
||||||
@ -556,7 +690,7 @@ void WaterfallCanvas::mouseReleased(wxMouseEvent& event) {
|
|||||||
command.int_value = freq;
|
command.int_value = freq;
|
||||||
demod->getCommandQueue()->push(command);
|
demod->getCommandQueue()->push(command);
|
||||||
command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_BANDWIDTH;
|
command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_BANDWIDTH;
|
||||||
command.int_value = bandwidth;
|
command.int_value = bw;
|
||||||
demod->getCommandQueue()->push(command);
|
demod->getCommandQueue()->push(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,11 +699,12 @@ void WaterfallCanvas::mouseReleased(wxMouseEvent& event) {
|
|||||||
|
|
||||||
void WaterfallCanvas::mouseLeftWindow(wxMouseEvent& event) {
|
void WaterfallCanvas::mouseLeftWindow(wxMouseEvent& event) {
|
||||||
mTracker.OnMouseLeftWindow(event);
|
mTracker.OnMouseLeftWindow(event);
|
||||||
SetCursor(wxCURSOR_CROSS);
|
SetCursor (wxCURSOR_CROSS);
|
||||||
wxGetApp().getDemodMgr().setActiveDemodulator(NULL);
|
wxGetApp().getDemodMgr().setActiveDemodulator(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterfallCanvas::mouseEnterWindow(wxMouseEvent& event) {
|
void WaterfallCanvas::mouseEnterWindow(wxMouseEvent& event) {
|
||||||
mTracker.OnMouseEnterWindow(event);
|
mTracker.OnMouseEnterWindow(event);
|
||||||
SetCursor(wxCURSOR_CROSS);
|
SetCursor (wxCURSOR_CROSS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,11 +19,21 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
WaterfallCanvas(wxWindow *parent, int *attribList = NULL);
|
WaterfallCanvas(wxWindow *parent, int *attribList = NULL);
|
||||||
|
void Setup(int fft_size_in, int waterfall_lines_in);
|
||||||
~WaterfallCanvas();
|
~WaterfallCanvas();
|
||||||
|
|
||||||
void setData(std::vector<liquid_float_complex> *data);
|
void setData(DemodulatorThreadIQData *input);
|
||||||
int GetFrequencyAt(float x);
|
int GetFrequencyAt(float x);
|
||||||
|
|
||||||
|
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:
|
private:
|
||||||
void OnPaint(wxPaintEvent& event);
|
void OnPaint(wxPaintEvent& event);
|
||||||
void OnKeyDown(wxKeyEvent& event);
|
void OnKeyDown(wxKeyEvent& event);
|
||||||
@ -62,7 +72,28 @@ private:
|
|||||||
DragState dragState;
|
DragState dragState;
|
||||||
DragState nextDragState;
|
DragState nextDragState;
|
||||||
|
|
||||||
bool shiftDown;bool altDown;bool ctrlDown;
|
bool shiftDown;
|
||||||
|
bool altDown;
|
||||||
|
bool ctrlDown;
|
||||||
|
|
||||||
|
int fft_size;
|
||||||
|
int waterfall_lines;
|
||||||
|
|
||||||
|
unsigned int center_freq;
|
||||||
|
unsigned int bandwidth;
|
||||||
|
|
||||||
|
bool isView;
|
||||||
|
msresamp_crcf resampler;
|
||||||
|
float resample_ratio;
|
||||||
|
nco_crcf nco_shift;
|
||||||
|
int shift_freq;
|
||||||
|
|
||||||
|
int last_input_bandwidth;
|
||||||
|
int last_bandwidth;
|
||||||
|
|
||||||
|
std::vector<liquid_float_complex> shift_buffer;
|
||||||
|
std::vector<liquid_float_complex> resampler_buffer;
|
||||||
|
|
||||||
// event table
|
// event table
|
||||||
wxDECLARE_EVENT_TABLE();
|
wxDECLARE_EVENT_TABLE();
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,31 @@
|
|||||||
#include "CubicSDR.h"
|
#include "CubicSDR.h"
|
||||||
|
|
||||||
WaterfallContext::WaterfallContext(WaterfallCanvas *canvas, wxGLContext *sharedContext) :
|
WaterfallContext::WaterfallContext(WaterfallCanvas *canvas, wxGLContext *sharedContext) :
|
||||||
PrimaryGLContext(canvas, sharedContext) {
|
PrimaryGLContext(canvas, sharedContext), waterfall(0), waterfall_tex(NULL) {
|
||||||
|
grad.addColor(GradientColor(0, 0, 0));
|
||||||
|
grad.addColor(GradientColor(0, 0, 1.0));
|
||||||
|
grad.addColor(GradientColor(0, 1.0, 0));
|
||||||
|
grad.addColor(GradientColor(1.0, 1.0, 0));
|
||||||
|
grad.addColor(GradientColor(1.0, 0.2, 0.0));
|
||||||
|
|
||||||
|
grad.generate(256);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaterfallContext::Setup(int fft_size_in, int num_waterfall_lines_in) {
|
||||||
|
if (waterfall) {
|
||||||
|
glDeleteTextures(1, &waterfall);
|
||||||
|
waterfall = 0;
|
||||||
|
}
|
||||||
|
if (waterfall_tex) {
|
||||||
|
delete waterfall_tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
waterfall_lines = num_waterfall_lines_in;
|
||||||
|
fft_size = fft_size_in;
|
||||||
|
|
||||||
|
waterfall_tex = new unsigned char[fft_size * waterfall_lines];
|
||||||
|
memset(waterfall_tex,0,fft_size * waterfall_lines);
|
||||||
|
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
@ -23,26 +47,19 @@ WaterfallContext::WaterfallContext(WaterfallCanvas *canvas, wxGLContext *sharedC
|
|||||||
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
||||||
|
|
||||||
grad.addColor(GradientColor(0, 0, 0));
|
|
||||||
grad.addColor(GradientColor(0, 0, 1.0));
|
|
||||||
grad.addColor(GradientColor(0, 1.0, 0));
|
|
||||||
grad.addColor(GradientColor(1.0, 1.0, 0));
|
|
||||||
grad.addColor(GradientColor(1.0, 0.2, 0.0));
|
|
||||||
|
|
||||||
grad.generate(256);
|
|
||||||
|
|
||||||
glPixelTransferi(GL_MAP_COLOR, GL_TRUE);
|
glPixelTransferi(GL_MAP_COLOR, GL_TRUE);
|
||||||
glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 256, &(grad.getRed())[0]);
|
glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 256, &(grad.getRed())[0]);
|
||||||
glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 256, &(grad.getGreen())[0]);
|
glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 256, &(grad.getGreen())[0]);
|
||||||
glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 256, &(grad.getBlue())[0]);
|
glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 256, &(grad.getBlue())[0]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterfallContext::Draw(std::vector<float> &points) {
|
void WaterfallContext::Draw(std::vector<float> &points) {
|
||||||
|
|
||||||
if (points.size()) {
|
if (points.size()) {
|
||||||
memmove(waterfall_tex + FFT_SIZE, waterfall_tex, (NUM_WATERFALL_LINES - 1) * FFT_SIZE);
|
memmove(waterfall_tex + fft_size, waterfall_tex, (waterfall_lines - 1) * fft_size);
|
||||||
|
|
||||||
for (int i = 0, iMax = FFT_SIZE; i < iMax; i++) {
|
for (int i = 0, iMax = fft_size; i < iMax; i++) {
|
||||||
float v = points[i * 2 + 1];
|
float v = points[i * 2 + 1];
|
||||||
|
|
||||||
float wv = v;
|
float wv = v;
|
||||||
@ -57,7 +74,7 @@ void WaterfallContext::Draw(std::vector<float> &points) {
|
|||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, waterfall);
|
glBindTexture(GL_TEXTURE_2D, waterfall);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, FFT_SIZE, NUM_WATERFALL_LINES, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, (GLvoid *) waterfall_tex);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fft_size, waterfall_lines, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, (GLvoid *) waterfall_tex);
|
||||||
|
|
||||||
glColor3f(1.0, 1.0, 1.0);
|
glColor3f(1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
#include "PrimaryGLContext.h"
|
#include "PrimaryGLContext.h"
|
||||||
#include "Gradient.h"
|
#include "Gradient.h"
|
||||||
|
|
||||||
#define NUM_WATERFALL_LINES 512
|
|
||||||
|
|
||||||
class WaterfallCanvas;
|
class WaterfallCanvas;
|
||||||
|
|
||||||
class WaterfallContext: public PrimaryGLContext {
|
class WaterfallContext: public PrimaryGLContext {
|
||||||
@ -12,9 +10,12 @@ public:
|
|||||||
WaterfallContext(WaterfallCanvas *canvas, wxGLContext *sharedContext);
|
WaterfallContext(WaterfallCanvas *canvas, wxGLContext *sharedContext);
|
||||||
|
|
||||||
void Draw(std::vector<float> &points);
|
void Draw(std::vector<float> &points);
|
||||||
|
void Setup(int fft_size_in, int num_waterfall_lines_in);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Gradient grad;
|
Gradient grad;
|
||||||
GLuint waterfall;
|
GLuint waterfall;
|
||||||
unsigned char waterfall_tex[FFT_SIZE * NUM_WATERFALL_LINES];
|
unsigned char *waterfall_tex;
|
||||||
|
int fft_size;
|
||||||
|
int waterfall_lines;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user