From b7793ef9056a1d400995e763db053c6e75ba635e Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 31 Dec 2014 19:45:01 -0500 Subject: [PATCH] Squelch slider/signal indicator --- CMakeLists.txt | 4 +++ src/AppFrame.cpp | 54 ++++++++++++++++++++++++++++--- src/AppFrame.h | 13 +++++++- src/CubicSDRDefs.h | 2 +- src/audio/AudioThread.cpp | 10 ++++-- src/audio/AudioThread.h | 2 +- src/demod/DemodulatorInstance.cpp | 13 ++++++++ src/demod/DemodulatorInstance.h | 13 ++++++-- src/demod/DemodulatorThread.cpp | 34 +++++++++++++++---- src/demod/DemodulatorThread.h | 9 ++++-- src/util/MouseTracker.cpp | 8 ++--- src/visual/WaterfallCanvas.cpp | 17 ++++++---- 12 files changed, 148 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3db72f8..a222e4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,6 +136,8 @@ SET (cubicsdr_sources src/util/MouseTracker.cpp src/util/GLFont.cpp src/visual/PrimaryGLContext.cpp + src/visual/MeterCanvas.cpp + src/visual/MeterContext.cpp src/visual/ScopeCanvas.cpp src/visual/ScopeContext.cpp src/visual/SpectrumCanvas.cpp @@ -165,6 +167,8 @@ SET (cubicsdr_headers src/util/MouseTracker.h src/util/GLFont.h src/visual/PrimaryGLContext.h + src/visual/MeterCanvas.h + src/visual/MeterContext.h src/visual/ScopeCanvas.h src/visual/ScopeContext.h src/visual/SpectrumCanvas.h diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index f419420..1334782 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -79,12 +79,18 @@ AppFrame::AppFrame() : demodWaterfallCanvas->attachSpectrumCanvas(demodSpectrumCanvas); demodVisuals->Add(demodWaterfallCanvas, 3, wxEXPAND | wxALL, 0); - demodTray->Add(demodVisuals, 7, wxEXPAND | wxALL, 0); + demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0); + + demodTray->AddSpacer(2); + + demodSignalMeter = new MeterCanvas(this, NULL); + demodSignalMeter->setMax(0.5); + demodTray->Add(demodSignalMeter, 1, wxEXPAND | wxALL, 0); demodTray->AddSpacer(2); scopeCanvas = new ScopeCanvas(this, NULL); - demodTray->Add(scopeCanvas, 7, wxEXPAND | wxALL, 0); + demodTray->Add(scopeCanvas, 30, wxEXPAND | wxALL, 0); vbox->Add(demodTray, 2, wxEXPAND | wxALL, 0); vbox->AddSpacer(2); @@ -105,12 +111,42 @@ AppFrame::AppFrame() : // SetIcon(wxICON(sample)); // Make a menubar - wxMenu *menu = new wxMenu; +// wxMenu *menu = new wxMenu; // menu->Append(wxID_NEW); // menu->AppendSeparator(); - menu->Append(wxID_CLOSE); +// menu->Append(wxID_CLOSE); +// wxMenuBar *menuBar = new wxMenuBar; +// menuBar->Append(menu, wxT("&File")); + + wxMenu *menu = new wxMenu; + + std::vector devices; + std::vector::iterator devices_i; + std::map::iterator mdevices_i; + AudioThread::enumerateDevices(devices); + + int i = 0; + + for (devices_i = devices.begin(); devices_i != devices.end(); devices_i++) { + if (devices_i->inputChannels) { + input_devices[i] = *devices_i; + } + if (devices_i->outputChannels) { + output_devices[i] = *devices_i; + } + i++; + } + + + for (mdevices_i = output_devices.begin(); mdevices_i != output_devices.end(); mdevices_i++) { + wxMenuItem *itm = menu->AppendRadioItem(wxID_RT_AUDIO_DEVICE+i,mdevices_i->second.name,wxT("Description?")); + if (mdevices_i->second.isDefaultOutput) { + itm->Check(true); + } + } + wxMenuBar *menuBar = new wxMenuBar; - menuBar->Append(menu, wxT("&File")); + menuBar->Append(menu, wxT("&Device")); SetMenuBar(menuBar); @@ -155,6 +191,9 @@ void AppFrame::OnIdle(wxIdleEvent& event) { DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); if (demod) { + if (demod != activeDemodulator) { + demodSignalMeter->setInputValue(demod->getSquelchLevel()); + } if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) { if (demod->getParams().frequency != demodWaterfallCanvas->GetCenterFrequency()) { demodWaterfallCanvas->SetCenterFrequency(demod->getParams().frequency); @@ -169,6 +208,11 @@ void AppFrame::OnIdle(wxIdleEvent& event) { demodSpectrumCanvas->SetBandwidth(demodBw); } } + demodSignalMeter->setLevel(demod->getSignalLevel()); + if (demodSignalMeter->inputChanged()) { + demod->setSquelchLevel(demodSignalMeter->getInputValue()); + } + activeDemodulator = demod; } if (!wxGetApp().getIQVisualQueue()->empty()) { diff --git a/src/AppFrame.h b/src/AppFrame.h index b8589fa..912b871 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -6,6 +6,11 @@ #include "ScopeCanvas.h" #include "SpectrumCanvas.h" #include "WaterfallCanvas.h" +#include "MeterCanvas.h" + +#include + +#define wxID_RT_AUDIO_DEVICE 10000 // Define a new frame type class AppFrame: public wxFrame { @@ -25,7 +30,13 @@ private: WaterfallCanvas *waterfallCanvas; SpectrumCanvas *demodSpectrumCanvas; WaterfallCanvas *demodWaterfallCanvas; - + MeterCanvas *demodSignalMeter; // event table + + DemodulatorInstance *activeDemodulator; + + std::map input_devices; + std::map output_devices; + wxDECLARE_EVENT_TABLE(); }; diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index 3d08ed3..ca0583e 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -4,7 +4,7 @@ #define BUF_SIZE (16384*2) #define SRATE 2000000 #else -#define BUF_SIZE (16384*4) +#define BUF_SIZE (16384*5) #define SRATE 2500000 #endif #define DEFAULT_FFT_SIZE 2048 diff --git a/src/audio/AudioThread.cpp b/src/audio/AudioThread.cpp index ec0c242..4bb46a7 100644 --- a/src/audio/AudioThread.cpp +++ b/src/audio/AudioThread.cpp @@ -211,11 +211,15 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu } #endif -void AudioThread::enumerateDevices() { - int numDevices = dac.getDeviceCount(); +void AudioThread::enumerateDevices(std::vector &devs) { + RtAudio endac; + + int numDevices = endac.getDeviceCount(); for (int i = 0; i < numDevices; i++) { - RtAudio::DeviceInfo info = dac.getDeviceInfo(i); + RtAudio::DeviceInfo info = endac.getDeviceInfo(i); + + devs.push_back(info); std::cout << std::endl; diff --git a/src/audio/AudioThread.h b/src/audio/AudioThread.h index 941fdaf..de0c806 100644 --- a/src/audio/AudioThread.h +++ b/src/audio/AudioThread.h @@ -66,7 +66,7 @@ public: AudioThread(AudioThreadInputQueue *inputQueue, DemodulatorThreadCommandQueue* threadQueueNotify); ~AudioThread(); - void enumerateDevices(); + static void enumerateDevices(std::vector &devs); void threadMain(); void terminate(); diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index 9650f01..6618a1a 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -181,3 +181,16 @@ void DemodulatorInstance::setSquelchEnabled(bool state) { squelch = state; } +float DemodulatorInstance::getSignalLevel() { + return demodulatorThread->getSignalLevel(); +} + +void DemodulatorInstance::setSquelchLevel(float signal_level_in) { + demodulatorThread->setSquelchLevel(signal_level_in); +} + + +float DemodulatorInstance::getSquelchLevel() { + return demodulatorThread->getSquelchLevel(); +} + diff --git a/src/demod/DemodulatorInstance.h b/src/demod/DemodulatorInstance.h index 8d0ee39..7432e0b 100644 --- a/src/demod/DemodulatorInstance.h +++ b/src/demod/DemodulatorInstance.h @@ -52,11 +52,20 @@ public: bool isStereo(); void setStereo(bool state); - void squelchAuto();bool isSquelchEnabled(); + void squelchAuto(); + bool isSquelchEnabled(); void setSquelchEnabled(bool state); + float getSignalLevel(); + void setSquelchLevel(float signal_level_in); + float getSquelchLevel(); + private: - std::atomic label;bool terminated;bool demodTerminated;bool audioTerminated;bool preDemodTerminated; + std::atomic label; // + bool terminated; // + bool demodTerminated; // + bool audioTerminated; // + bool preDemodTerminated; std::atomic active; std::atomic squelch; std::atomic stereo; diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index b3e9640..50aa8dd 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -9,11 +9,9 @@ DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* pQueue, DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) : postInputQueue(pQueue), visOutQueue(NULL), audioInputQueue(NULL), agc(NULL), stereo(false), terminated(false), threadQueueNotify( - threadQueueNotify), threadQueueControl(threadQueueControl), squelch_level(0), squelch_tolerance(0), squelch_enabled(false) { + threadQueueNotify), threadQueueControl(threadQueueControl), squelch_level(0), squelch_tolerance(0), signal_level(0), squelch_enabled(false) { - float kf = 0.5; // modulation factor - fdem = freqdem_create(kf); -// freqdem_print(fdem); + fdem = freqdem_create(0.5); } DemodulatorThread::~DemodulatorThread() { } @@ -64,7 +62,7 @@ void DemodulatorThread::threadMain() { double shift_freq = 0; agc = agc_crcf_create(); - agc_crcf_set_bandwidth(agc, 1e-3f); + agc_crcf_set_bandwidth(agc, 0.9); std::cout << "Demodulator thread started.." << std::endl; @@ -176,10 +174,19 @@ void DemodulatorThread::threadMain() { msresamp_rrrf_execute(stereo_resampler, &demod_output_stereo[0], num_written, &resampled_audio_output_stereo[0], &num_audio_written); } + float current_level = ((60.0/fabs(agc_crcf_get_rssi(agc)))/15.0 - signal_level); //agc_crcf_get_signal_level(agc); + + if (current_level > signal_level) { + signal_level = signal_level + (current_level-signal_level) * 0.5; + } else { + signal_level = signal_level + (current_level-signal_level) * 0.05; + } + + AudioThreadInput *ati = NULL; if (audioInputQueue != NULL) { - if (!squelch_enabled || ((agc_crcf_get_signal_level(agc)) >= 0.1)) { + if (!squelch_enabled || (signal_level >= squelch_level)) { for (buffers_i = buffers.begin(); buffers_i != buffers.end(); buffers_i++) { if ((*buffers_i)->getRefCount() <= 0) { @@ -330,3 +337,18 @@ void DemodulatorThread::setStereo(bool state) { bool DemodulatorThread::isStereo() { return stereo; } + +float DemodulatorThread::getSignalLevel() { + return signal_level; +} + +void DemodulatorThread::setSquelchLevel(float signal_level_in) { + if (!squelch_enabled) { + squelch_enabled = true; + } + squelch_level = signal_level_in; +} + +float DemodulatorThread::getSquelchLevel() { + return squelch_level; +} diff --git a/src/demod/DemodulatorThread.h b/src/demod/DemodulatorThread.h index 0501b59..7843a69 100644 --- a/src/demod/DemodulatorThread.h +++ b/src/demod/DemodulatorThread.h @@ -32,12 +32,16 @@ public: } void initialize(); - void terminate(); void setStereo(bool state); bool isStereo(); + float getSignalLevel(); + void setSquelchLevel(float signal_level_in); + float getSquelchLevel(); + + #ifdef __APPLE__ static void *pthread_helper(void *context) { return ((DemodulatorThread *) context)->threadMain(); @@ -57,7 +61,8 @@ protected: DemodulatorThreadCommandQueue* threadQueueNotify; DemodulatorThreadControlCommandQueue *threadQueueControl; - float squelch_level; + std::atomic squelch_level; float squelch_tolerance; + std::atomic signal_level; bool squelch_enabled; }; diff --git a/src/util/MouseTracker.cpp b/src/util/MouseTracker.cpp index 59819ed..905ca0d 100644 --- a/src/util/MouseTracker.cpp +++ b/src/util/MouseTracker.cpp @@ -9,7 +9,7 @@ void MouseTracker::OnMouseMoved(wxMouseEvent& event) { const wxSize ClientSize = target->GetClientSize(); mouseX = (float) event.m_x / (float) ClientSize.x; - mouseY = (float) event.m_y / (float) ClientSize.y; + mouseY = 1.0 - (float) event.m_y / (float) ClientSize.y; deltaMouseX = mouseX - lastMouseX; deltaMouseY = mouseY - lastMouseY; @@ -17,11 +17,11 @@ void MouseTracker::OnMouseMoved(wxMouseEvent& event) { if (isMouseDown) { #ifndef __APPLE__ if (horizDragLock && vertDragLock) { - target->WarpPointer(originMouseX * ClientSize.x, originMouseY * ClientSize.y); + target->WarpPointer(originMouseX * ClientSize.x, (1.0-originMouseY) * ClientSize.y); mouseX = originMouseX; mouseY = originMouseY; } else if (vertDragLock && mouseY != lastMouseY) { - target->WarpPointer(event.m_x, originMouseY * ClientSize.y); + target->WarpPointer(event.m_x, (1.0-originMouseY) * ClientSize.y); mouseY = originMouseY; } else if (horizDragLock && mouseX != lastMouseX) { target->WarpPointer(originMouseX * ClientSize.x, event.m_y); @@ -42,7 +42,7 @@ void MouseTracker::OnMouseDown(wxMouseEvent& event) { const wxSize ClientSize = target->GetClientSize(); mouseX = lastMouseX = (float) event.m_x / (float) ClientSize.x; - mouseY = lastMouseY = (float) event.m_y / (float) ClientSize.y; + mouseY = lastMouseY = 1.0 - (float) event.m_y / (float) ClientSize.y; originMouseX = mouseX; originMouseY = mouseY; diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 589b966..0c9a4a1 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -42,6 +42,9 @@ WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) : nco_shift = nco_crcf_create(LIQUID_NCO); shift_freq = 0; + fft_ceil_ma = fft_ceil_maa = 100.0; + fft_floor_ma = fft_floor_maa = 0.0; + mTracker.setTarget(this); SetCursor(wxCURSOR_CROSS); } @@ -81,9 +84,6 @@ void WaterfallCanvas::Setup(int fft_size_in, int waterfall_lines_in) { } 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(); } @@ -409,8 +409,13 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) { } for (int i = 0, iMax = fft_size; i < iMax; i++) { - fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.65; - fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.65; + if (isView) { + fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * 0.85; + fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * 0.55; + } 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]; @@ -423,7 +428,7 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) { fft_ceil += 1; fft_floor -= 1; - fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.01; + 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.01; fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.01;