From 9de1abd539ce0f54bb63707eadd5612377f5b0f1 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Mon, 17 Aug 2015 00:59:38 -0400 Subject: [PATCH 1/3] Add mute button and 'M' to toggle mute on waterfall hover --- src/AppFrame.cpp | 35 ++++++++++++++++++++++++++++++- src/AppFrame.h | 1 + src/demod/DemodulatorInstance.cpp | 10 +++++++++ src/demod/DemodulatorInstance.h | 4 ++++ src/demod/DemodulatorThread.cpp | 15 ++++++++++++- src/demod/DemodulatorThread.h | 4 ++++ src/visual/ModeSelectorCanvas.cpp | 26 +++++++++++++++++++++-- src/visual/ModeSelectorCanvas.h | 7 +++++++ src/visual/PrimaryGLContext.cpp | 25 +++++++++++++++++----- src/visual/WaterfallCanvas.cpp | 6 ++++++ 10 files changed, 124 insertions(+), 9 deletions(-) diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 4ceeb81..adafee8 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -103,12 +103,25 @@ AppFrame::AppFrame() : demodTray->AddSpacer(1); + wxBoxSizer *demodGainTray = new wxBoxSizer(wxVERTICAL); + demodGainMeter = new MeterCanvas(this, attribList); demodGainMeter->setMax(2.0); demodGainMeter->setHelpTip("Current Demodulator Gain Level. Click / Drag to set Gain level."); demodGainMeter->setShowUserInput(false); - demodTray->Add(demodGainMeter, 1, wxEXPAND | wxALL, 0); + demodGainTray->Add(demodGainMeter, 8, wxEXPAND | wxALL, 0); + demodGainTray->AddSpacer(1); + + demodMuteButton = new ModeSelectorCanvas(this, attribList); + demodMuteButton->addChoice(1, "M"); + demodMuteButton->setHelpTip("Demodulator Mute Toggle"); + demodMuteButton->setToggleMode(true); + + demodGainTray->Add(demodMuteButton, 1, wxEXPAND | wxALL, 0); + + demodTray->Add(demodGainTray, 1, wxEXPAND | wxALL, 0); + vbox->Add(demodTray, 12, wxEXPAND | wxALL, 0); vbox->AddSpacer(1); @@ -663,6 +676,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) { outputDeviceMenuItems[outputDevice]->Check(true); int dType = demod->getDemodulatorType(); demodModeSelector->setSelection(dType); + demodMuteButton->setSelection(demod->isMuted()?1:-1); } if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) { long long centerFreq = demod->getFrequency(); @@ -694,6 +708,22 @@ void AppFrame::OnIdle(wxIdleEvent& event) { demod->setDemodulatorType(dSelection); } + int muteMode = demodMuteButton->getSelection(); + if (demodMuteButton->modeChanged()) { + if (demod->isMuted() && muteMode == -1) { + demod->setMuted(false); + } else if (!demod->isMuted() && muteMode == 1) { + demod->setMuted(true); + } + demodMuteButton->clearModeChanged(); + } else { + if (demod->isMuted() && muteMode == -1) { + demodMuteButton->setSelection(1); + } else if (!demod->isMuted() && muteMode == 1) { + demodMuteButton->setSelection(-1); + } + } + demodWaterfallCanvas->setBandwidth(demodBw); demodSpectrumCanvas->setBandwidth(demodBw); } @@ -812,6 +842,7 @@ void AppFrame::saveSession(std::string fileName) { *demod->newChild("stereo") = (*instance_i)->isStereo() ? 1 : 0; *demod->newChild("output_device") = outputDevices[(*instance_i)->getOutputDevice()].name; *demod->newChild("gain") = (*instance_i)->getGain(); + *demod->newChild("muted") = (*instance_i)->isMuted() ? 1 : 0; } s.SaveToFileXML(fileName); @@ -859,6 +890,7 @@ bool AppFrame::loadSession(std::string fileName) { float squelch_level = demod->hasAnother("squelch_level") ? (float) *demod->getNext("squelch_level") : 0; int squelch_enabled = demod->hasAnother("squelch_enabled") ? (int) *demod->getNext("squelch_enabled") : 0; int stereo = demod->hasAnother("stereo") ? (int) *demod->getNext("stereo") : 0; + int muted = demod->hasAnother("muted") ? (int) *demod->getNext("muted") : 0; std::string output_device = demod->hasAnother("output_device") ? string(*(demod->getNext("output_device"))) : ""; float gain = demod->hasAnother("gain") ? (float) *demod->getNext("gain") : 1.0; @@ -870,6 +902,7 @@ bool AppFrame::loadSession(std::string fileName) { newDemod->setFrequency(freq); newDemod->setGain(gain); newDemod->updateLabel(freq); + newDemod->setMuted(muted?true:false); if (squelch_enabled) { newDemod->setSquelchEnabled(true); newDemod->setSquelchLevel(squelch_level); diff --git a/src/AppFrame.h b/src/AppFrame.h index 42ea5e9..58fb5cc 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -81,6 +81,7 @@ private: // UITestCanvas *testCanvas; MeterCanvas *spectrumAvgMeter; MeterCanvas *waterfallSpeedMeter; + ModeSelectorCanvas *demodMuteButton; DemodulatorInstance *activeDemodulator; diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index d308327..c3440bc 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -10,6 +10,7 @@ DemodulatorInstance::DemodulatorInstance() : active.store(false); squelch.store(false); stereo.store(false); + muted.store(false); tracking.store(false); follow.store(false); currentAudioSampleRate.store(0); @@ -412,6 +413,15 @@ void DemodulatorInstance::setTracking(bool tracking) { this->tracking = tracking; } +bool DemodulatorInstance::isMuted() { + return demodulatorThread->isMuted(); +} + +void DemodulatorInstance::setMuted(bool muted) { + this->muted = muted; + demodulatorThread->setMuted(muted); +} + DemodulatorThreadInputQueue *DemodulatorInstance::getIQInputDataPipe() { return pipeIQInputData; } diff --git a/src/demod/DemodulatorInstance.h b/src/demod/DemodulatorInstance.h index d211746..cc9da67 100644 --- a/src/demod/DemodulatorInstance.h +++ b/src/demod/DemodulatorInstance.h @@ -73,6 +73,9 @@ public: bool isTracking(); void setTracking(bool tracking); + + bool isMuted(); + void setMuted(bool muted); DemodulatorThreadInputQueue *getIQInputDataPipe(); @@ -98,6 +101,7 @@ private: std::atomic_bool active; std::atomic_bool squelch; std::atomic_bool stereo; + std::atomic_bool muted; std::atomic_llong currentFrequency; std::atomic_int currentBandwidth; diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index becc261..485fd54 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -14,6 +14,7 @@ DemodulatorThread::DemodulatorThread() : IOThread(), iqAutoGain(NULL), amOutputCeil(1), amOutputCeilMA(1), amOutputCeilMAA(1), audioSampleRate(0), squelchLevel(0), signalLevel(0), squelchEnabled(false), iqInputQueue(NULL), audioOutputQueue(NULL), audioVisOutputQueue(NULL), threadQueueControl(NULL), threadQueueNotify(NULL) { stereo.store(false); + muted.store(false); agcEnabled.store(false); demodulatorType.store(DEMOD_TYPE_FM); @@ -404,7 +405,11 @@ void DemodulatorThread::run() { } if (ati != NULL) { - audioOutputQueue->push(ati); + if (!muted.load()) { + audioOutputQueue->push(ati); + } else { + ati->setRefCount(0); + } } if (!threadQueueControl->empty()) { @@ -510,6 +515,14 @@ bool DemodulatorThread::isStereo() { return stereo.load(); } +bool DemodulatorThread::isMuted() { + return muted.load(); +} + +void DemodulatorThread::setMuted(bool muted) { + this->muted.store(muted); +} + void DemodulatorThread::setAGC(bool state) { agcEnabled.store(state); } diff --git a/src/demod/DemodulatorThread.h b/src/demod/DemodulatorThread.h index eb179c5..7f7e417 100644 --- a/src/demod/DemodulatorThread.h +++ b/src/demod/DemodulatorThread.h @@ -27,6 +27,9 @@ public: void setAGC(bool state); bool getAGC(); + void setMuted(bool state); + bool isMuted(); + float getSignalLevel(); void setSquelchLevel(float signal_level_in); float getSquelchLevel(); @@ -64,6 +67,7 @@ protected: float amOutputCeilMAA; std::atomic_bool stereo; + std::atomic_bool muted; std::atomic_bool agcEnabled; std::atomic_int demodulatorType; int audioSampleRate; diff --git a/src/visual/ModeSelectorCanvas.cpp b/src/visual/ModeSelectorCanvas.cpp index 5058291..c26de45 100644 --- a/src/visual/ModeSelectorCanvas.cpp +++ b/src/visual/ModeSelectorCanvas.cpp @@ -25,7 +25,7 @@ EVT_ENTER_WINDOW(ModeSelectorCanvas::OnMouseEnterWindow) wxEND_EVENT_TABLE() ModeSelectorCanvas::ModeSelectorCanvas(wxWindow *parent, int *attribList) : -InteractiveCanvas(parent, attribList), numChoices(0), currentSelection(-1) { +InteractiveCanvas(parent, attribList), numChoices(0), currentSelection(-1), toggleMode(false), inputChanged(false) { glContext = new ModeSelectorContext(this, &wxGetApp().GetContext(this)); } @@ -97,10 +97,21 @@ void ModeSelectorCanvas::OnMouseReleased(wxMouseEvent& event) { const wxSize ClientSize = GetClientSize(); + int selectedButton = currentSelection; if (mouseTracker.getOriginDeltaMouseX() < 2.0 / ClientSize.y) { - currentSelection = getHoveredSelection(); + selectedButton = getHoveredSelection(); } + if (toggleMode && (currentSelection == selectedButton)) { + selectedButton = -1; + } + + if (currentSelection != selectedButton) { + inputChanged = true; + } + + currentSelection = selectedButton; + SetCursor (wxCURSOR_ARROW); } @@ -148,4 +159,15 @@ int ModeSelectorCanvas::getSelection() { return selections[currentSelection].value; } +void ModeSelectorCanvas::setToggleMode(bool toggleMode) { + this->toggleMode = toggleMode; +} + +bool ModeSelectorCanvas::modeChanged() { + return inputChanged; +} + +void ModeSelectorCanvas::clearModeChanged() { + inputChanged = false; +} diff --git a/src/visual/ModeSelectorCanvas.h b/src/visual/ModeSelectorCanvas.h index 7dcf12b..68de86e 100644 --- a/src/visual/ModeSelectorCanvas.h +++ b/src/visual/ModeSelectorCanvas.h @@ -35,6 +35,11 @@ public: void setSelection(int value); int getSelection(); + void setToggleMode(bool toggleMode); + + bool modeChanged(); + void clearModeChanged(); + private: void setNumChoices(int numChoices_in); @@ -53,6 +58,8 @@ private: std::string helpTip; int numChoices; int currentSelection; + bool toggleMode; + bool inputChanged; std::vector selections; // wxDECLARE_EVENT_TABLE(); diff --git a/src/visual/PrimaryGLContext.cpp b/src/visual/PrimaryGLContext.cpp index 0ff82dc..ba02874 100644 --- a/src/visual/PrimaryGLContext.cpp +++ b/src/visual/PrimaryGLContext.cpp @@ -94,7 +94,12 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGB3f color, lo glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4f(0, 0, 0, 0.35); + if (demod->isMuted()) { + glColor4f(0.8, 0, 0, 0.35); + } else { + glColor4f(0, 0, 0, 0.35); + } + glBegin(GL_QUADS); glVertex3f(uxPos - ofsLeft, hPos + labelHeight, 0.0); glVertex3f(uxPos - ofsLeft, -1.0, 0.0); @@ -128,12 +133,18 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGB3f color, lo glColor4f(1.0, 1.0, 1.0, 0.8); + std::string demodLabel = demod->getLabel(); + + if (demod->isMuted()) { + demodLabel.append("[M]"); + } + if (demod->getDemodulatorType() == DEMOD_TYPE_USB) { - GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER); + GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER); } else if (demod->getDemodulatorType() == DEMOD_TYPE_LSB) { - GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER); + GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER); } else { - GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER); + GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER); } glDisable(GL_BLEND); @@ -230,7 +241,11 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGB3f color, long l glColor3f(0, 0, 0); GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5) + xOfs, -1.0 + hPos - yOfs, 16, demodAlign, GLFont::GLFONT_ALIGN_CENTER); - glColor3f(0.8, 0.8, 0.8); + if (demod->isMuted()) { + glColor3f(0.8, 0.2, 0.2); + } else { + glColor3f(0.8, 0.2, 0.2); + } GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5), -1.0 + hPos, 16, demodAlign, GLFont::GLFONT_ALIGN_CENTER); glDisable(GL_BLEND); diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index f2d2578..c91fb98 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -322,6 +322,12 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { wxGetApp().removeDemodulator(activeDemod); wxGetApp().getDemodMgr().deleteThread(activeDemod); break; + case 'M': + if (!activeDemod) { + break; + } + activeDemod->setMuted(!activeDemod->isMuted()); + break; case 'S': if (!activeDemod) { break; From 58fb313d6ff81282849c0392769ffd1235eb8ca9 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Mon, 17 Aug 2015 01:07:57 -0400 Subject: [PATCH 2/3] Update waterfall helptip --- src/visual/WaterfallCanvas.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index c91fb98..204473f 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -363,18 +363,15 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { if (freq < minFreq) { wxGetApp().setFrequency(freq+(wxGetApp().getSampleRate()/2)); - setStatusText("Set center frequency: %s", freq); } if (freq > maxFreq) { wxGetApp().setFrequency(freq-(wxGetApp().getSampleRate()/2)); - setStatusText("Set center frequency: %s", freq); } } else { if (spectrumCanvas) { spectrumCanvas->setCenterFrequency(freq); } wxGetApp().setFrequency(freq); - setStatusText("Set center frequency: %s", freq); } } @@ -412,7 +409,6 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { } demod->setBandwidth(currentBW); - setStatusText("Set demodulator bandwidth: %s", demod->getBandwidth()); } if (dragState == WF_DRAG_FREQUENCY) { @@ -430,8 +426,6 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { currentFreq = demod->getFrequency(); demod->updateLabel(currentFreq); } - - setStatusText("Set demodulator frequency: %s", demod->getFrequency()); } } else if (mouseTracker.mouseRightDown()) { mouseZoom = mouseZoom + ((1.0 - (mouseTracker.getDeltaMouseY() * 4.0)) - mouseZoom) * 0.1; @@ -511,14 +505,14 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) { mouseTracker.setVertDragLock(true); mouseTracker.setHorizDragLock(false); - setStatusText("Click and drag to change demodulator bandwidth. SPACE for direct frequency input. D to delete, S for stereo."); + setStatusText("Click and drag to change demodulator bandwidth. SPACE for direct frequency input. M for mute, D to delete, S for stereo."); } else { SetCursor(wxCURSOR_SIZING); nextDragState = WF_DRAG_FREQUENCY; mouseTracker.setVertDragLock(true); mouseTracker.setHorizDragLock(false); - setStatusText("Click and drag to change demodulator frequency; SPACE for direct input. D to delete, S for stereo."); + setStatusText("Click and drag to change demodulator frequency; SPACE for direct input. M for mute, D to delete, S for stereo."); } } else { SetCursor(wxCURSOR_CROSS); From 4df66ea0e32bb5edba558dc4007846956e7ff3d4 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Mon, 17 Aug 2015 01:11:42 -0400 Subject: [PATCH 3/3] Move [M] to avoid confusion with Mhz --- src/visual/PrimaryGLContext.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/visual/PrimaryGLContext.cpp b/src/visual/PrimaryGLContext.cpp index ba02874..15d96f8 100644 --- a/src/visual/PrimaryGLContext.cpp +++ b/src/visual/PrimaryGLContext.cpp @@ -136,7 +136,7 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGB3f color, lo std::string demodLabel = demod->getLabel(); if (demod->isMuted()) { - demodLabel.append("[M]"); + demodLabel = std::string("[M] ") + demodLabel; } if (demod->getDemodulatorType() == DEMOD_TYPE_USB) { @@ -241,11 +241,7 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGB3f color, long l glColor3f(0, 0, 0); GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5) + xOfs, -1.0 + hPos - yOfs, 16, demodAlign, GLFont::GLFONT_ALIGN_CENTER); - if (demod->isMuted()) { - glColor3f(0.8, 0.2, 0.2); - } else { - glColor3f(0.8, 0.2, 0.2); - } + glColor3f(1, 1, 1); GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5), -1.0 + hPos, 16, demodAlign, GLFont::GLFONT_ALIGN_CENTER); glDisable(GL_BLEND);