Merge pull request #135 from cjcliffe/demod_mute

Demodulator Mute feature
This commit is contained in:
Charles J. Cliffe 2015-08-17 01:14:09 -04:00
commit 44621e42ea
10 changed files with 122 additions and 17 deletions

View File

@ -103,11 +103,24 @@ AppFrame::AppFrame() :
demodTray->AddSpacer(1); demodTray->AddSpacer(1);
wxBoxSizer *demodGainTray = new wxBoxSizer(wxVERTICAL);
demodGainMeter = new MeterCanvas(this, attribList); demodGainMeter = new MeterCanvas(this, attribList);
demodGainMeter->setMax(2.0); demodGainMeter->setMax(2.0);
demodGainMeter->setHelpTip("Current Demodulator Gain Level. Click / Drag to set Gain level."); demodGainMeter->setHelpTip("Current Demodulator Gain Level. Click / Drag to set Gain level.");
demodGainMeter->setShowUserInput(false); 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->Add(demodTray, 12, wxEXPAND | wxALL, 0);
vbox->AddSpacer(1); vbox->AddSpacer(1);
@ -663,6 +676,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
outputDeviceMenuItems[outputDevice]->Check(true); outputDeviceMenuItems[outputDevice]->Check(true);
int dType = demod->getDemodulatorType(); int dType = demod->getDemodulatorType();
demodModeSelector->setSelection(dType); demodModeSelector->setSelection(dType);
demodMuteButton->setSelection(demod->isMuted()?1:-1);
} }
if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) { if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) {
long long centerFreq = demod->getFrequency(); long long centerFreq = demod->getFrequency();
@ -694,6 +708,22 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
demod->setDemodulatorType(dSelection); 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); demodWaterfallCanvas->setBandwidth(demodBw);
demodSpectrumCanvas->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("stereo") = (*instance_i)->isStereo() ? 1 : 0;
*demod->newChild("output_device") = outputDevices[(*instance_i)->getOutputDevice()].name; *demod->newChild("output_device") = outputDevices[(*instance_i)->getOutputDevice()].name;
*demod->newChild("gain") = (*instance_i)->getGain(); *demod->newChild("gain") = (*instance_i)->getGain();
*demod->newChild("muted") = (*instance_i)->isMuted() ? 1 : 0;
} }
s.SaveToFileXML(fileName); 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; 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 squelch_enabled = demod->hasAnother("squelch_enabled") ? (int) *demod->getNext("squelch_enabled") : 0;
int stereo = demod->hasAnother("stereo") ? (int) *demod->getNext("stereo") : 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"))) : ""; std::string output_device = demod->hasAnother("output_device") ? string(*(demod->getNext("output_device"))) : "";
float gain = demod->hasAnother("gain") ? (float) *demod->getNext("gain") : 1.0; 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->setFrequency(freq);
newDemod->setGain(gain); newDemod->setGain(gain);
newDemod->updateLabel(freq); newDemod->updateLabel(freq);
newDemod->setMuted(muted?true:false);
if (squelch_enabled) { if (squelch_enabled) {
newDemod->setSquelchEnabled(true); newDemod->setSquelchEnabled(true);
newDemod->setSquelchLevel(squelch_level); newDemod->setSquelchLevel(squelch_level);

View File

@ -81,6 +81,7 @@ private:
// UITestCanvas *testCanvas; // UITestCanvas *testCanvas;
MeterCanvas *spectrumAvgMeter; MeterCanvas *spectrumAvgMeter;
MeterCanvas *waterfallSpeedMeter; MeterCanvas *waterfallSpeedMeter;
ModeSelectorCanvas *demodMuteButton;
DemodulatorInstance *activeDemodulator; DemodulatorInstance *activeDemodulator;

View File

@ -10,6 +10,7 @@ DemodulatorInstance::DemodulatorInstance() :
active.store(false); active.store(false);
squelch.store(false); squelch.store(false);
stereo.store(false); stereo.store(false);
muted.store(false);
tracking.store(false); tracking.store(false);
follow.store(false); follow.store(false);
currentAudioSampleRate.store(0); currentAudioSampleRate.store(0);
@ -412,6 +413,15 @@ void DemodulatorInstance::setTracking(bool tracking) {
this->tracking = tracking; this->tracking = tracking;
} }
bool DemodulatorInstance::isMuted() {
return demodulatorThread->isMuted();
}
void DemodulatorInstance::setMuted(bool muted) {
this->muted = muted;
demodulatorThread->setMuted(muted);
}
DemodulatorThreadInputQueue *DemodulatorInstance::getIQInputDataPipe() { DemodulatorThreadInputQueue *DemodulatorInstance::getIQInputDataPipe() {
return pipeIQInputData; return pipeIQInputData;
} }

View File

@ -74,6 +74,9 @@ public:
bool isTracking(); bool isTracking();
void setTracking(bool tracking); void setTracking(bool tracking);
bool isMuted();
void setMuted(bool muted);
DemodulatorThreadInputQueue *getIQInputDataPipe(); DemodulatorThreadInputQueue *getIQInputDataPipe();
protected: protected:
@ -98,6 +101,7 @@ private:
std::atomic_bool active; std::atomic_bool active;
std::atomic_bool squelch; std::atomic_bool squelch;
std::atomic_bool stereo; std::atomic_bool stereo;
std::atomic_bool muted;
std::atomic_llong currentFrequency; std::atomic_llong currentFrequency;
std::atomic_int currentBandwidth; std::atomic_int currentBandwidth;

View File

@ -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) { 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); stereo.store(false);
muted.store(false);
agcEnabled.store(false); agcEnabled.store(false);
demodulatorType.store(DEMOD_TYPE_FM); demodulatorType.store(DEMOD_TYPE_FM);
@ -404,7 +405,11 @@ void DemodulatorThread::run() {
} }
if (ati != NULL) { if (ati != NULL) {
if (!muted.load()) {
audioOutputQueue->push(ati); audioOutputQueue->push(ati);
} else {
ati->setRefCount(0);
}
} }
if (!threadQueueControl->empty()) { if (!threadQueueControl->empty()) {
@ -510,6 +515,14 @@ bool DemodulatorThread::isStereo() {
return stereo.load(); return stereo.load();
} }
bool DemodulatorThread::isMuted() {
return muted.load();
}
void DemodulatorThread::setMuted(bool muted) {
this->muted.store(muted);
}
void DemodulatorThread::setAGC(bool state) { void DemodulatorThread::setAGC(bool state) {
agcEnabled.store(state); agcEnabled.store(state);
} }

View File

@ -27,6 +27,9 @@ public:
void setAGC(bool state); void setAGC(bool state);
bool getAGC(); bool getAGC();
void setMuted(bool state);
bool isMuted();
float getSignalLevel(); float getSignalLevel();
void setSquelchLevel(float signal_level_in); void setSquelchLevel(float signal_level_in);
float getSquelchLevel(); float getSquelchLevel();
@ -64,6 +67,7 @@ protected:
float amOutputCeilMAA; float amOutputCeilMAA;
std::atomic_bool stereo; std::atomic_bool stereo;
std::atomic_bool muted;
std::atomic_bool agcEnabled; std::atomic_bool agcEnabled;
std::atomic_int demodulatorType; std::atomic_int demodulatorType;
int audioSampleRate; int audioSampleRate;

View File

@ -25,7 +25,7 @@ EVT_ENTER_WINDOW(ModeSelectorCanvas::OnMouseEnterWindow)
wxEND_EVENT_TABLE() wxEND_EVENT_TABLE()
ModeSelectorCanvas::ModeSelectorCanvas(wxWindow *parent, int *attribList) : 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)); glContext = new ModeSelectorContext(this, &wxGetApp().GetContext(this));
} }
@ -97,10 +97,21 @@ void ModeSelectorCanvas::OnMouseReleased(wxMouseEvent& event) {
const wxSize ClientSize = GetClientSize(); const wxSize ClientSize = GetClientSize();
int selectedButton = currentSelection;
if (mouseTracker.getOriginDeltaMouseX() < 2.0 / ClientSize.y) { 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); SetCursor (wxCURSOR_ARROW);
} }
@ -148,4 +159,15 @@ int ModeSelectorCanvas::getSelection() {
return selections[currentSelection].value; return selections[currentSelection].value;
} }
void ModeSelectorCanvas::setToggleMode(bool toggleMode) {
this->toggleMode = toggleMode;
}
bool ModeSelectorCanvas::modeChanged() {
return inputChanged;
}
void ModeSelectorCanvas::clearModeChanged() {
inputChanged = false;
}

View File

@ -35,6 +35,11 @@ public:
void setSelection(int value); void setSelection(int value);
int getSelection(); int getSelection();
void setToggleMode(bool toggleMode);
bool modeChanged();
void clearModeChanged();
private: private:
void setNumChoices(int numChoices_in); void setNumChoices(int numChoices_in);
@ -53,6 +58,8 @@ private:
std::string helpTip; std::string helpTip;
int numChoices; int numChoices;
int currentSelection; int currentSelection;
bool toggleMode;
bool inputChanged;
std::vector<ModeSelectorMode> selections; std::vector<ModeSelectorMode> selections;
// //
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();

View File

@ -94,7 +94,12 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGB3f color, lo
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (demod->isMuted()) {
glColor4f(0.8, 0, 0, 0.35);
} else {
glColor4f(0, 0, 0, 0.35); glColor4f(0, 0, 0, 0.35);
}
glBegin(GL_QUADS); glBegin(GL_QUADS);
glVertex3f(uxPos - ofsLeft, hPos + labelHeight, 0.0); glVertex3f(uxPos - ofsLeft, hPos + labelHeight, 0.0);
glVertex3f(uxPos - ofsLeft, -1.0, 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); glColor4f(1.0, 1.0, 1.0, 0.8);
std::string demodLabel = demod->getLabel();
if (demod->isMuted()) {
demodLabel = std::string("[M] ") + demodLabel;
}
if (demod->getDemodulatorType() == DEMOD_TYPE_USB) { 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) { } 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 { } 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); glDisable(GL_BLEND);
@ -230,7 +241,7 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGB3f color, long l
glColor3f(0, 0, 0); glColor3f(0, 0, 0);
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5) + xOfs, -1.0 + hPos - yOfs, 16, demodAlign, GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5) + xOfs, -1.0 + hPos - yOfs, 16, demodAlign,
GLFont::GLFONT_ALIGN_CENTER); GLFont::GLFONT_ALIGN_CENTER);
glColor3f(0.8, 0.8, 0.8); 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); GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5), -1.0 + hPos, 16, demodAlign, GLFont::GLFONT_ALIGN_CENTER);
glDisable(GL_BLEND); glDisable(GL_BLEND);

View File

@ -322,6 +322,12 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
wxGetApp().removeDemodulator(activeDemod); wxGetApp().removeDemodulator(activeDemod);
wxGetApp().getDemodMgr().deleteThread(activeDemod); wxGetApp().getDemodMgr().deleteThread(activeDemod);
break; break;
case 'M':
if (!activeDemod) {
break;
}
activeDemod->setMuted(!activeDemod->isMuted());
break;
case 'S': case 'S':
if (!activeDemod) { if (!activeDemod) {
break; break;
@ -357,18 +363,15 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
if (freq < minFreq) { if (freq < minFreq) {
wxGetApp().setFrequency(freq+(wxGetApp().getSampleRate()/2)); wxGetApp().setFrequency(freq+(wxGetApp().getSampleRate()/2));
setStatusText("Set center frequency: %s", freq);
} }
if (freq > maxFreq) { if (freq > maxFreq) {
wxGetApp().setFrequency(freq-(wxGetApp().getSampleRate()/2)); wxGetApp().setFrequency(freq-(wxGetApp().getSampleRate()/2));
setStatusText("Set center frequency: %s", freq);
} }
} else { } else {
if (spectrumCanvas) { if (spectrumCanvas) {
spectrumCanvas->setCenterFrequency(freq); spectrumCanvas->setCenterFrequency(freq);
} }
wxGetApp().setFrequency(freq); wxGetApp().setFrequency(freq);
setStatusText("Set center frequency: %s", freq);
} }
} }
@ -406,7 +409,6 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
} }
demod->setBandwidth(currentBW); demod->setBandwidth(currentBW);
setStatusText("Set demodulator bandwidth: %s", demod->getBandwidth());
} }
if (dragState == WF_DRAG_FREQUENCY) { if (dragState == WF_DRAG_FREQUENCY) {
@ -424,8 +426,6 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
currentFreq = demod->getFrequency(); currentFreq = demod->getFrequency();
demod->updateLabel(currentFreq); demod->updateLabel(currentFreq);
} }
setStatusText("Set demodulator frequency: %s", demod->getFrequency());
} }
} else if (mouseTracker.mouseRightDown()) { } else if (mouseTracker.mouseRightDown()) {
mouseZoom = mouseZoom + ((1.0 - (mouseTracker.getDeltaMouseY() * 4.0)) - mouseZoom) * 0.1; mouseZoom = mouseZoom + ((1.0 - (mouseTracker.getDeltaMouseY() * 4.0)) - mouseZoom) * 0.1;
@ -505,14 +505,14 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
mouseTracker.setVertDragLock(true); mouseTracker.setVertDragLock(true);
mouseTracker.setHorizDragLock(false); 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 { } else {
SetCursor(wxCURSOR_SIZING); SetCursor(wxCURSOR_SIZING);
nextDragState = WF_DRAG_FREQUENCY; nextDragState = WF_DRAG_FREQUENCY;
mouseTracker.setVertDragLock(true); mouseTracker.setVertDragLock(true);
mouseTracker.setHorizDragLock(false); 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 { } else {
SetCursor(wxCURSOR_CROSS); SetCursor(wxCURSOR_CROSS);