diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index a8d11bb..f7707c6 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -29,6 +29,7 @@ bool CubicSDR::OnInit() { audioVisualQueue = new DemodulatorThreadOutputQueue(); demodulatorTest[0]->setVisualOutputQueue(audioVisualQueue); + demodMgr.setActiveDemodulator(demodulatorTest[0]); threadCmdQueueSDR = new SDRThreadCommandQueue; sdrThread = new SDRThread(threadCmdQueueSDR); diff --git a/src/demod/DemodulatorMgr.cpp b/src/demod/DemodulatorMgr.cpp index 472d3ca..9302eb2 100644 --- a/src/demod/DemodulatorMgr.cpp +++ b/src/demod/DemodulatorMgr.cpp @@ -1,4 +1,6 @@ #include +#include +#include DemodulatorInstance::DemodulatorInstance() : t_Demod(NULL), t_Audio(NULL), threadQueueDemod(NULL), demodulatorThread(NULL) { @@ -54,16 +56,16 @@ void DemodulatorInstance::run() { t_Audio = new std::thread(&AudioThread::threadMain, audioThread); #ifdef __APPLE__ // Already using pthreads, might as well do some custom init.. - pthread_attr_t attr; - size_t size; + pthread_attr_t attr; + size_t size; - pthread_attr_init(&attr); - pthread_attr_setstacksize(&attr, 2048000); - pthread_attr_getstacksize(&attr, &size); + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 2048000); + pthread_attr_getstacksize(&attr, &size); pthread_create(&t_Demod, &attr, &DemodulatorThread::pthread_helper, demodulatorThread); - pthread_attr_destroy(&attr); + pthread_attr_destroy(&attr); - std::cout << "Initialized demodulator stack size of " << size << std::endl; + std::cout << "Initialized demodulator stack size of " << size << std::endl; #else t_Demod = new std::thread(&DemodulatorThread::threadMain, demodulatorThread); @@ -91,7 +93,16 @@ void DemodulatorInstance::terminate() { t_Audio->join(); } -DemodulatorMgr::DemodulatorMgr() { +std::string DemodulatorInstance::getLabel() { + return label; +} + +void DemodulatorInstance::setLabel(std::string labelStr) { + label = labelStr; +} + +DemodulatorMgr::DemodulatorMgr() : + activeDemodulator(NULL), lastActiveDemodulator(NULL) { } @@ -101,7 +112,13 @@ DemodulatorMgr::~DemodulatorMgr() { DemodulatorInstance *DemodulatorMgr::newThread() { DemodulatorInstance *newDemod = new DemodulatorInstance; + demods.push_back(newDemod); + + std::stringstream label; + label << demods.size(); + newDemod->setLabel(label.str()); + return newDemod; } @@ -137,3 +154,26 @@ std::vector *DemodulatorMgr::getDemodulatorsAt(int freq, return foundDemods; } + +void DemodulatorMgr::setActiveDemodulator(DemodulatorInstance *demod, bool temporary) { + if (!temporary) { + if (activeDemodulator != NULL) { + lastActiveDemodulator = activeDemodulator; + } else { + lastActiveDemodulator = demod; + } + } + activeDemodulator = demod; +} + +DemodulatorInstance *DemodulatorMgr::getActiveDemodulator() { + return activeDemodulator; +} + +DemodulatorInstance *DemodulatorMgr::getLastActiveDemodulator() { + if (std::find(demods.begin(), demods.end(), lastActiveDemodulator) == demods.end()) { + lastActiveDemodulator = activeDemodulator; + } + + return lastActiveDemodulator; +} diff --git a/src/demod/DemodulatorMgr.h b/src/demod/DemodulatorMgr.h index 935c2c8..9b6ad28 100644 --- a/src/demod/DemodulatorMgr.h +++ b/src/demod/DemodulatorMgr.h @@ -32,6 +32,11 @@ public: void run(); void terminate(); + std::string getLabel(); + void setLabel(std::string labelStr); + +private: + std::string label; }; class DemodulatorMgr { @@ -44,6 +49,13 @@ public: std::vector *getDemodulatorsAt(int freq, int bandwidth); void terminateAll(); + + void setActiveDemodulator(DemodulatorInstance *demod, bool temporary = true); + DemodulatorInstance *getActiveDemodulator(); + DemodulatorInstance *getLastActiveDemodulator(); + private: std::vector demods; + DemodulatorInstance *activeDemodulator; + DemodulatorInstance *lastActiveDemodulator; }; diff --git a/src/visual/PrimaryGLContext.cpp b/src/visual/PrimaryGLContext.cpp index 884944f..05a11fe 100644 --- a/src/visual/PrimaryGLContext.cpp +++ b/src/visual/PrimaryGLContext.cpp @@ -63,18 +63,24 @@ GLFont &PrimaryGLContext::getFont(GLFontSize esize) { std::string fontName; switch (esize) { - case GLFONT_SIZE12: fontName = "vera_sans_mono12.fnt"; - break; - case GLFONT_SIZE16: fontName = "vera_sans_mono16.fnt"; - break; - case GLFONT_SIZE18: fontName = "vera_sans_mono18.fnt"; - break; - case GLFONT_SIZE24: fontName = "vera_sans_mono24.fnt"; - break; - case GLFONT_SIZE32: fontName = "vera_sans_mono32.fnt"; - break; - case GLFONT_SIZE48: fontName = "vera_sans_mono48.fnt"; - break; + case GLFONT_SIZE12: + fontName = "vera_sans_mono12.fnt"; + break; + case GLFONT_SIZE16: + fontName = "vera_sans_mono16.fnt"; + break; + case GLFONT_SIZE18: + fontName = "vera_sans_mono18.fnt"; + break; + case GLFONT_SIZE24: + fontName = "vera_sans_mono24.fnt"; + break; + case GLFONT_SIZE32: + fontName = "vera_sans_mono32.fnt"; + break; + case GLFONT_SIZE48: + fontName = "vera_sans_mono48.fnt"; + break; } fonts[esize].loadFont(fontName); @@ -88,9 +94,15 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float return; } - float uxPos = (float) (demod->getParams().frequency - (wxGetApp().getFrequency() - SRATE / 2)) / (float) SRATE; + GLint vp[4]; + glGetIntegerv( GL_VIEWPORT, vp); + + float viewHeight = (float) vp[3]; + float viewWidth = (float) vp[2]; + + float uxPos = (float) (demod->getParams().frequency - (wxGetApp().getFrequency() - SRATE / 2)) / (float) SRATE; + uxPos = (uxPos - 0.5) * 2.0; - glDisable(GL_DEPTH_TEST); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); @@ -102,15 +114,36 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float glBlendFunc(GL_SRC_ALPHA, GL_DST_COLOR); glColor4f(r, g, b, 0.2); glBegin(GL_QUADS); - glVertex3f((uxPos - 0.5) * 2.0 - ofs, 1.0, 0.0); - glVertex3f((uxPos - 0.5) * 2.0 - ofs, -1.0, 0.0); + glVertex3f(uxPos - ofs, 1.0, 0.0); + glVertex3f(uxPos - 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 + ofs, -1.0, 0.0); + glVertex3f(uxPos + ofs, 1.0, 0.0); glEnd(); + float labelHeight = 20.0 / viewHeight; + + float hPos = -1.0 + labelHeight; + + if (ofs * 2.0 < 16.0 / viewWidth) { + ofs = 16.0 / viewWidth; + + glColor4f(r, g, b, 0.2); + glBegin(GL_QUADS); + glVertex3f(uxPos - ofs, hPos + labelHeight, 0.0); + glVertex3f(uxPos - ofs, -1.0, 0.0); + + glVertex3f(uxPos + ofs, -1.0, 0.0); + glVertex3f(uxPos + ofs, hPos + labelHeight, 0.0); + glEnd(); + } + + glColor4f(1.0, 1.0, 1.0, 0.8); + + getFont(PrimaryGLContext::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER); + glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); + } void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, float r, float g, float b) { diff --git a/src/visual/SpectrumContext.cpp b/src/visual/SpectrumContext.cpp index dd1cafa..8d4993e 100644 --- a/src/visual/SpectrumContext.cpp +++ b/src/visual/SpectrumContext.cpp @@ -22,8 +22,8 @@ void SpectrumContext::Draw(std::vector &points) { if (points.size()) { glPushMatrix(); - glTranslatef(-1.0f, -0.9f, 0.0f); - glScalef(2.0f, 1.8f, 1.0f); + glTranslatef(-1.0f, -0.75f, 0.0f); + glScalef(2.0f, 1.5f, 1.0f); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, &points[0]); glDrawArrays(GL_LINE_STRIP, 0, points.size() / 2); diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 50568fe..73af788 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -19,6 +19,7 @@ wxBEGIN_EVENT_TABLE(WaterfallCanvas, wxGLCanvas) EVT_PAINT(WaterfallCanvas::OnPaint) EVT_KEY_DOWN(WaterfallCanvas::OnKeyDown) +EVT_KEY_UP(WaterfallCanvas::OnKeyUp) EVT_IDLE(WaterfallCanvas::OnIdle) EVT_MOTION(WaterfallCanvas::mouseMoved) EVT_LEFT_DOWN(WaterfallCanvas::mouseDown) @@ -29,8 +30,8 @@ wxEND_EVENT_TABLE() WaterfallCanvas::WaterfallCanvas(wxWindow *parent, int *attribList) : wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, - wxFULL_REPAINT_ON_RESIZE), parent(parent), frameTimer(0), activeDemodulatorBandwidth(0), activeDemodulator(NULL), dragState(WF_DRAG_NONE), nextDragState( - WF_DRAG_NONE) { + wxFULL_REPAINT_ON_RESIZE), parent(parent), frameTimer(0), activeDemodulatorBandwidth(0), dragState(WF_DRAG_NONE), nextDragState(WF_DRAG_NONE), shiftDown( + false) { int in_block_size = BUF_SIZE / 2; int out_block_size = FFT_SIZE; @@ -73,17 +74,38 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { std::vector &demods = wxGetApp().getDemodMgr().getDemodulators(); + DemodulatorInstance *activeDemodulator = wxGetApp().getDemodMgr().getActiveDemodulator(); + DemodulatorInstance *lastActiveDemodulator = wxGetApp().getDemodMgr().getLastActiveDemodulator(); + if (mTracker.mouseInView()) { if (activeDemodulator == NULL) { - glContext->DrawFreqSelector(mTracker.getMouseX(), 0, 1, 0); + if (lastActiveDemodulator) { + if (shiftDown) { + glContext->DrawDemod(lastActiveDemodulator); + glContext->DrawFreqSelector(mTracker.getMouseX(), 0, 1, 0); + } else { + glContext->DrawDemod(lastActiveDemodulator, 1, 0, 0); + glContext->DrawFreqSelector(mTracker.getMouseX(), 1, 1, 0); + } + } } else { + if (lastActiveDemodulator) { + glContext->DrawDemod(lastActiveDemodulator); + } glContext->DrawDemod(activeDemodulator, 1, 1, 0); } + } else { + if (activeDemodulator) { + glContext->DrawDemod(activeDemodulator); + } + if (lastActiveDemodulator) { + glContext->DrawDemod(lastActiveDemodulator); + } } for (int i = 0, iMax = demods.size(); i < iMax; i++) { - if (activeDemodulator == demods[i]) { + if (activeDemodulator == demods[i] || lastActiveDemodulator == demods[i]) { continue; } glContext->DrawDemod(demods[i]); @@ -94,6 +116,14 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { SwapBuffers(); } +void WaterfallCanvas::OnKeyUp(wxKeyEvent& event) { + switch (event.GetKeyCode()) { + case WXK_SHIFT: + shiftDown = false; + break; + } +} + void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { float angle = 5.0; @@ -117,6 +147,9 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { break; case WXK_SPACE: break; + case WXK_SHIFT: + shiftDown = true; + break; default: event.Skip(); return; @@ -205,7 +238,7 @@ void WaterfallCanvas::OnIdle(wxIdleEvent &event) { void WaterfallCanvas::mouseMoved(wxMouseEvent& event) { mTracker.OnMouseMoved(event); - DemodulatorInstance *demod = activeDemodulator; + DemodulatorInstance *demod = wxGetApp().getDemodMgr().getActiveDemodulator(); if (mTracker.mouseDown()) { if (demod == NULL) { @@ -254,18 +287,20 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) { } else { int freqPos = GetFrequencyAt(mTracker.getMouseX()); - activeDemodulator = NULL; - std::vector *demodsHover = wxGetApp().getDemodMgr().getDemodulatorsAt(freqPos, 15000); + wxGetApp().getDemodMgr().setActiveDemodulator(NULL); + if (demodsHover->size()) { int hovered = -1; int near_dist = SRATE; + DemodulatorInstance *activeDemodulator = NULL; + for (int i = 0, iMax = demodsHover->size(); i < iMax; i++) { DemodulatorInstance *demod = (*demodsHover)[i]; - int halfBw = (demod->getParams().bandwidth/2); int freqDiff = (int) demod->getParams().frequency - freqPos; + int halfBw = (demod->getParams().bandwidth / 2); int dist = abs(freqDiff); @@ -274,7 +309,7 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) { near_dist = dist; } - if (dist <= halfBw && dist >= (int)((float)halfBw/(float)1.5)) { + if (dist <= halfBw && dist >= (int) ((float) halfBw / (float) 1.5)) { int edge_dist = abs(halfBw - dist); if (edge_dist < near_dist) { activeDemodulator = demod; @@ -283,6 +318,12 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) { } } + if (activeDemodulator == NULL) { + return; + } + + wxGetApp().getDemodMgr().setActiveDemodulator(activeDemodulator, false); + int freqDiff = ((int) activeDemodulator->getParams().frequency - freqPos); if (abs(freqDiff) > (activeDemodulator->getParams().bandwidth / 3)) { @@ -314,8 +355,12 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) { void WaterfallCanvas::mouseDown(wxMouseEvent& event) { mTracker.OnMouseDown(event); - dragState = nextDragState; + + if (dragState) { + wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getActiveDemodulator(), false); + } + activeDemodulatorBandwidth = 0; activeDemodulatorFrequency = 0; } @@ -328,43 +373,53 @@ void WaterfallCanvas::mouseWheelMoved(wxMouseEvent& event) { void WaterfallCanvas::mouseReleased(wxMouseEvent& event) { mTracker.OnMouseReleased(event); - if (mTracker.getOriginDeltaMouseX() == 0 && mTracker.getOriginDeltaMouseY() == 0 && dragState == WF_DRAG_NONE) { - - if (activeDemodulator == NULL) { - return; - } - - float pos = mTracker.getMouseX(); - - int center_freq = wxGetApp().getFrequency(); - - DemodulatorInstance *demod = activeDemodulator; - - int freq = center_freq - (int) (0.5 * (float) SRATE) + (int) ((float) pos * (float) SRATE); - - DemodulatorThreadCommand command; - command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY; - command.int_value = freq; - - demod->getCommandQueue()->push(command); - - ((wxFrame*) parent)->GetStatusBar()->SetStatusText( - wxString::Format(wxT("Set center frequency: %s"), - wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep))); - } - - dragState = WF_DRAG_NONE; + SetCursor(wxCURSOR_CROSS); mTracker.setVertDragLock(true); mTracker.setHorizDragLock(true); - SetCursor(wxCURSOR_CROSS); + if (mTracker.getOriginDeltaMouseX() == 0 && mTracker.getOriginDeltaMouseY() == 0) { + DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); + if (1) { + + if (demod == NULL) { + return; + } + + float pos = mTracker.getMouseX(); + + int center_freq = wxGetApp().getFrequency(); + + int freq = center_freq - (int) (0.5 * (float) SRATE) + (int) ((float) pos * (float) SRATE); + + DemodulatorThreadCommand command; + command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY; + command.int_value = freq; + + demod->getCommandQueue()->push(command); + + ((wxFrame*) parent)->GetStatusBar()->SetStatusText( + wxString::Format(wxT("Set demodulator frequency: %s"), + wxNumberFormatter::ToString((long) freq, wxNumberFormatter::Style_WithThousandsSep))); + + wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getLastActiveDemodulator(), false); + SetCursor(wxCURSOR_SIZING); + nextDragState = WF_DRAG_FREQUENCY; + mTracker.setVertDragLock(true); + mTracker.setHorizDragLock(false); + } else { + wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getActiveDemodulator(), false); + nextDragState = WF_DRAG_NONE; + } + } + + dragState = WF_DRAG_NONE; } void WaterfallCanvas::mouseLeftWindow(wxMouseEvent& event) { mTracker.OnMouseLeftWindow(event); SetCursor(wxCURSOR_CROSS); - activeDemodulator = NULL; + wxGetApp().getDemodMgr().setActiveDemodulator(NULL); } void WaterfallCanvas::mouseEnterWindow(wxMouseEvent& event) { diff --git a/src/visual/WaterfallCanvas.h b/src/visual/WaterfallCanvas.h index d720f0b..0942372 100644 --- a/src/visual/WaterfallCanvas.h +++ b/src/visual/WaterfallCanvas.h @@ -25,6 +25,7 @@ public: private: void OnPaint(wxPaintEvent& event); void OnKeyDown(wxKeyEvent& event); + void OnKeyUp(wxKeyEvent& event); void OnIdle(wxIdleEvent &event); @@ -55,11 +56,12 @@ private: int activeDemodulatorBandwidth; int activeDemodulatorFrequency; - DemodulatorInstance *activeDemodulator; DragState dragState; DragState nextDragState; + bool shiftDown; + // event table wxDECLARE_EVENT_TABLE(); };