diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 51c98d9..7129e92 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -369,22 +369,35 @@ void AppFrame::OnIdle(wxIdleEvent& event) { demodModeSelector->setSelection(dType); } if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) { - if (demod->getFrequency() != demodWaterfallCanvas->getCenterFrequency()) { - demodWaterfallCanvas->setCenterFrequency(demod->getFrequency()); - demodSpectrumCanvas->setCenterFrequency(demod->getFrequency()); - } - int dSelection = demodModeSelector->getSelection(); - if (dSelection != -1 && dSelection != demod->getDemodulatorType()) { - demod->setDemodulatorType(dSelection); + long long centerFreq = demod->getFrequency(); + unsigned int demodBw = (unsigned int) ceil((float) demod->getBandwidth() * 2.5); + + if (demod->getDemodulatorType() == DEMOD_TYPE_USB) { + demodBw /= 2; + centerFreq += demod->getBandwidth()/4; + } + + if (demod->getDemodulatorType() == DEMOD_TYPE_LSB) { + demodBw /= 2; + centerFreq -= demod->getBandwidth()/4; } - unsigned int demodBw = (unsigned int) ceil((float) demod->getBandwidth() * 2.5); if (demodBw > wxGetApp().getSampleRate() / 2) { demodBw = wxGetApp().getSampleRate() / 2; } if (demodBw < 30000) { demodBw = 30000; } + + if (centerFreq != demodWaterfallCanvas->getCenterFrequency()) { + demodWaterfallCanvas->setCenterFrequency(centerFreq); + demodSpectrumCanvas->setCenterFrequency(centerFreq); + } + int dSelection = demodModeSelector->getSelection(); + if (dSelection != -1 && dSelection != demod->getDemodulatorType()) { + demod->setDemodulatorType(dSelection); + } + demodWaterfallCanvas->setBandwidth(demodBw); demodSpectrumCanvas->setBandwidth(demodBw); } diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index 2c0012c..eba50f3 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -232,8 +232,8 @@ int DemodulatorInstance::getOutputDevice() { } void DemodulatorInstance::checkBandwidth() { - if ((currentDemodType == DEMOD_TYPE_USB || currentDemodType == DEMOD_TYPE_LSB) && (getBandwidth() > 60000)) { - setBandwidth(60000); + if ((currentDemodType == DEMOD_TYPE_USB || currentDemodType == DEMOD_TYPE_LSB) && (getBandwidth() % 2)) { + setBandwidth(getBandwidth()+1); } } diff --git a/src/demod/DemodulatorMgr.cpp b/src/demod/DemodulatorMgr.cpp index d26a9e3..7604d92 100644 --- a/src/demod/DemodulatorMgr.cpp +++ b/src/demod/DemodulatorMgr.cpp @@ -77,7 +77,7 @@ std::vector *DemodulatorMgr::getDemodulatorsAt(long long long long halfBuffer = bandwidth / 2; - if ((freq <= (freqTest + halfBandwidthTest + halfBuffer)) && (freq >= (freqTest - halfBandwidthTest - halfBuffer))) { + if ((freq <= (freqTest + ((testDemod->getDemodulatorType() != DEMOD_TYPE_LSB)?halfBandwidthTest:0) + halfBuffer)) && (freq >= (freqTest - ((testDemod->getDemodulatorType() != DEMOD_TYPE_USB)?halfBandwidthTest:0) - halfBuffer))) { foundDemods->push_back(testDemod); } } diff --git a/src/demod/DemodulatorPreThread.cpp b/src/demod/DemodulatorPreThread.cpp index b588755..c94b6c5 100644 --- a/src/demod/DemodulatorPreThread.cpp +++ b/src/demod/DemodulatorPreThread.cpp @@ -70,6 +70,8 @@ void DemodulatorPreThread::threadMain() { std::vector in_buf_data; std::vector out_buf_data; + liquid_float_complex carrySample; // Keep the stream count even to simplify some demod operations + bool carrySampleFlag = false; terminated = false; @@ -197,7 +199,30 @@ void DemodulatorPreThread::threadMain() { msresamp_crcf_execute(iqResampler, in_buf, bufSize, &resampledData[0], &numWritten); resamp->setRefCount(1); - resamp->data.assign(resampledData.begin(), resampledData.begin() + numWritten); + + bool uneven = (numWritten % 2 != 0); + + if (!carrySampleFlag && !uneven) { + resamp->data.assign(resampledData.begin(), resampledData.begin() + numWritten); + carrySampleFlag = false; + } else if (!carrySampleFlag && uneven) { + resamp->data.assign(resampledData.begin(), resampledData.begin() + (numWritten-1)); + carrySample = resampledData.back(); + carrySampleFlag = true; + } else if (carrySampleFlag && uneven) { + resamp->data.resize(numWritten+1); + resamp->data[0] = carrySample; + memcpy(&resamp->data[1],&resampledData[0],sizeof(liquid_float_complex)*numWritten); + carrySampleFlag = false; + } else if (carrySampleFlag && !uneven) { + resamp->data.resize(numWritten); + resamp->data[0] = carrySample; + memcpy(&resamp->data[1],&resampledData[0],sizeof(liquid_float_complex)*(numWritten-1)); + carrySample = resampledData.back(); + carrySampleFlag = true; + } + + resamp->audioResampleRatio = audioResampleRatio; resamp->audioResampler = audioResampler; diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index efd03c3..88028de 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -14,8 +14,8 @@ DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* iqInputQue 0), squelchEnabled(false) { demodFM = freqdem_create(0.5); - demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1); - demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1); + demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1); + demodAM_LSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1); demodAM_DSB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1); demodAM_DSB_CSP = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0); demodAM = demodAM_DSB_CSP; @@ -64,7 +64,8 @@ void DemodulatorThread::threadMain() { delete h; - liquid_float_complex x, y; + liquid_float_complex x, y, z[2]; + float rz[2]; firhilbf firStereoR2C = firhilbf_create(5, 60.0f); firhilbf firStereoC2R = firhilbf_create(5, 60.0f); @@ -79,16 +80,9 @@ void DemodulatorThread::threadMain() { nco_crcf ssbShifterDown = nco_crcf_create(LIQUID_NCO); nco_crcf_set_frequency(ssbShifterDown, (2.0 * M_PI) * 0.25); - float ssbFt = 0.001f; // filter transition - float ssbAs = 120.0f; // stop-band attenuation [dB] - - h_len = estimate_req_filter_len(ssbFt, ssbAs); - float *ssb_h = new float[h_len]; - liquid_firdes_kaiser(h_len, 0.25, ssbAs, 0.0, ssb_h); - - firfilt_crcf firSSB = firfilt_crcf_create(ssb_h, h_len); - - delete ssb_h; + // half band interp / decimate used for side-band elimination + resamp2_crcf ssbInterp = resamp2_crcf_create(7, 0.0f, -120.0f); + resamp2_crcf ssbDecim = resamp2_crcf_create(7, 0.0f, -120.0f); // Automatic IQ gain iqAutoGain = agc_crcf_create(); @@ -103,10 +97,10 @@ void DemodulatorThread::threadMain() { case DEMOD_TYPE_FM: break; case DEMOD_TYPE_LSB: - demodAM = demodAM_USB; + demodAM = demodAM_LSB; break; case DEMOD_TYPE_USB: - demodAM = demodAM_LSB; + demodAM = demodAM_USB; break; case DEMOD_TYPE_DSB: demodAM = demodAM_DSB; @@ -181,42 +175,59 @@ void DemodulatorThread::threadMain() { float p; switch (demodulatorType.load()) { case DEMOD_TYPE_LSB: - for (int i = 0; i < bufSize; i++) { // Reject upper band - nco_crcf_mix_up(ssbShifterUp, inp->data[i], &x); + for (int i = 0; i < bufSize / 2; i++) { // Reject upper band + nco_crcf_mix_up(ssbShifterUp, inp->data[i * 2], &z[0]); nco_crcf_step(ssbShifterUp); - firfilt_crcf_push(firSSB, x); - firfilt_crcf_execute(firSSB, &x); - nco_crcf_mix_down(ssbShifterDown, x, &(inp->data[i])); + nco_crcf_mix_up(ssbShifterUp, inp->data[i * 2 + 1], &z[1]); + nco_crcf_step(ssbShifterUp); + resamp2_crcf_decim_execute(ssbDecim, z, &x); + resamp2_crcf_interp_execute(ssbInterp, x, z); + + nco_crcf_mix_down(ssbShifterDown, z[0], &x); nco_crcf_step(ssbShifterDown); + nco_crcf_mix_down(ssbShifterDown, z[1], &y); + nco_crcf_step(ssbShifterDown); + ampmodem_demodulate(demodAM, x, &demodOutputData[i * 2]); + ampmodem_demodulate(demodAM, y, &demodOutputData[i * 2 + 1]); } break; case DEMOD_TYPE_USB: - for (int i = 0; i < bufSize; i++) { // Reject lower band - nco_crcf_mix_down(ssbShifterDown, inp->data[i], &x); + for (int i = 0; i < bufSize / 2; i++) { // Reject lower band + nco_crcf_mix_down(ssbShifterDown, inp->data[i * 2], &z[0]); nco_crcf_step(ssbShifterDown); - firfilt_crcf_push(firSSB, x); - firfilt_crcf_execute(firSSB, &x); - nco_crcf_mix_up(ssbShifterUp, x, &(inp->data[i])); + nco_crcf_mix_down(ssbShifterDown, inp->data[i * 2 + 1], &z[1]); + nco_crcf_step(ssbShifterDown); + resamp2_crcf_decim_execute(ssbDecim, z, &x); + resamp2_crcf_interp_execute(ssbInterp, x, z); + + nco_crcf_mix_up(ssbShifterUp, z[0], &x); nco_crcf_step(ssbShifterUp); + nco_crcf_mix_up(ssbShifterUp, z[1], &y); + nco_crcf_step(ssbShifterUp); + ampmodem_demodulate(demodAM, x, &demodOutputData[i * 2]); + ampmodem_demodulate(demodAM, y, &demodOutputData[i * 2 + 1]); } break; case DEMOD_TYPE_AM: case DEMOD_TYPE_DSB: + for (int i = 0; i < bufSize; i++) { + ampmodem_demodulate(demodAM, inp->data[i], &demodOutputData[i]); + } break; } + amOutputCeilMA = amOutputCeilMA + (amOutputCeil - amOutputCeilMA) * 0.05; + amOutputCeilMAA = amOutputCeilMAA + (amOutputCeilMA - amOutputCeilMAA) * 0.05; + amOutputCeil = 0; for (int i = 0; i < bufSize; i++) { - ampmodem_demodulate(demodAM, inp->data[i], &demodOutputData[i]); if (demodOutputData[i] > amOutputCeil) { amOutputCeil = demodOutputData[i]; } } - amOutputCeilMA = amOutputCeilMA + (amOutputCeil - amOutputCeilMA) * 0.05; - amOutputCeilMAA = amOutputCeilMAA + (amOutputCeilMA - amOutputCeilMAA) * 0.05; - float gain = 0.95 / amOutputCeilMAA; + float gain = 0.5 / amOutputCeilMAA; for (int i = 0; i < bufSize; i++) { demodOutputData[i] *= gain; @@ -316,7 +327,8 @@ void DemodulatorThread::threadMain() { std::vector::iterator data_i; ati->peak = 0; for (data_i = ati->data.begin(); data_i != ati->data.end(); data_i++) { - if (float p = fabs(*data_i) > ati->peak) { + float p = fabs(*data_i); + if (p > ati->peak) { ati->peak = p; } } @@ -389,11 +401,11 @@ void DemodulatorThread::threadMain() { freqdem_reset(demodFM); break; case DEMOD_TYPE_LSB: - demodAM = demodAM_USB; + demodAM = demodAM_LSB; ampmodem_reset(demodAM); break; case DEMOD_TYPE_USB: - demodAM = demodAM_LSB; + demodAM = demodAM_USB; ampmodem_reset(demodAM); break; case DEMOD_TYPE_DSB: diff --git a/src/visual/PrimaryGLContext.cpp b/src/visual/PrimaryGLContext.cpp index 7f9e59a..fd985d0 100644 --- a/src/visual/PrimaryGLContext.cpp +++ b/src/visual/PrimaryGLContext.cpp @@ -97,7 +97,7 @@ GLFont &PrimaryGLContext::getFont(GLFontSize esize) { return fonts[esize]; } -void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float g, float b, long long center_freq, long long srate) { +void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGBColor color, long long center_freq, long long srate) { if (!demod) { return; } @@ -122,10 +122,10 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4f(r, g, b, 0.6); + glColor4f(color.r, color.g, color.b, 0.6); float ofs = ((float) demod->getBandwidth()) / (float) srate; - + float ofsLeft = (demod->getDemodulatorType()!=DEMOD_TYPE_USB)?ofs:0, ofsRight = (demod->getDemodulatorType()!=DEMOD_TYPE_LSB)?ofs:0; float labelHeight = 20.0 / viewHeight; float hPos = -1.0 + labelHeight; @@ -134,48 +134,53 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float glColor4f(0, 0, 0, 0.35); glBegin(GL_QUADS); - glVertex3f(uxPos - ofs, hPos + labelHeight, 0.0); - glVertex3f(uxPos - ofs, -1.0, 0.0); + glVertex3f(uxPos - ofsLeft, hPos + labelHeight, 0.0); + glVertex3f(uxPos - ofsLeft, -1.0, 0.0); - glVertex3f(uxPos + ofs, -1.0, 0.0); - glVertex3f(uxPos + ofs, hPos + labelHeight, 0.0); + glVertex3f(uxPos + ofsRight, -1.0, 0.0); + glVertex3f(uxPos + ofsRight, hPos + labelHeight, 0.0); glEnd(); glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glColor4f(r, g, b, 0.2); + glColor4f(color.r, color.g, color.b, 0.2); glBegin(GL_QUADS); - glVertex3f(uxPos - ofs, 1.0, 0.0); - glVertex3f(uxPos - ofs, -1.0, 0.0); + glVertex3f(uxPos - ofsLeft, 1.0, 0.0); + glVertex3f(uxPos - ofsLeft, -1.0, 0.0); - glVertex3f(uxPos + ofs, -1.0, 0.0); - glVertex3f(uxPos + ofs, 1.0, 0.0); + glVertex3f(uxPos + ofsRight, -1.0, 0.0); + glVertex3f(uxPos + ofsRight, 1.0, 0.0); glEnd(); - - if (ofs * 2.0 < 16.0 / viewWidth) { ofs = 16.0 / viewWidth; - glColor4f(r, g, b, 0.2); + glColor4f(color.r, color.g, color.b, 0.2); glBegin(GL_QUADS); - glVertex3f(uxPos - ofs, hPos + labelHeight, 0.0); - glVertex3f(uxPos - ofs, -1.0, 0.0); + glVertex3f(uxPos - ofsLeft, hPos + labelHeight, 0.0); + glVertex3f(uxPos - ofsLeft, -1.0, 0.0); - glVertex3f(uxPos + ofs, -1.0, 0.0); - glVertex3f(uxPos + ofs, hPos + labelHeight, 0.0); + glVertex3f(uxPos + ofsRight, -1.0, 0.0); + glVertex3f(uxPos + ofsRight, 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); + if (demod->getDemodulatorType() == DEMOD_TYPE_USB) { + getFont(PrimaryGLContext::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER); + } else if (demod->getDemodulatorType() == DEMOD_TYPE_LSB) { + getFont(PrimaryGLContext::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER); + } else { + getFont(PrimaryGLContext::GLFONT_SIZE16).drawString(demod->getLabel(), uxPos, hPos, 16, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER); + } glDisable(GL_BLEND); } -void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, float r, float g, float b, long long center_freq, long long srate) { +void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGBColor color, long long center_freq, long long srate) { if (!demod) { return; } @@ -193,30 +198,31 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, float r, float g, f glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glColor4f(r, g, b, 0.6); + glColor4f(color.r, color.g, color.b, 0.6); + + float ofs = ((float) demod->getBandwidth()) / (float) srate; + float ofsLeft = (demod->getDemodulatorType()!=DEMOD_TYPE_USB)?ofs:0, ofsRight = (demod->getDemodulatorType()!=DEMOD_TYPE_LSB)?ofs:0; glBegin(GL_LINES); glVertex3f((uxPos - 0.5) * 2.0, 1.0, 0.0); glVertex3f((uxPos - 0.5) * 2.0, -1.0, 0.0); - float ofs = ((float) demod->getBandwidth()) / (float) srate; + glVertex3f((uxPos - 0.5) * 2.0 - ofsLeft, 1.0, 0.0); + glVertex3f((uxPos - 0.5) * 2.0 - ofsLeft, -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); - glVertex3f((uxPos - 0.5) * 2.0 + ofs, -1.0, 0.0); + glVertex3f((uxPos - 0.5) * 2.0 + ofsRight, 1.0, 0.0); + glVertex3f((uxPos - 0.5) * 2.0 + ofsRight, -1.0, 0.0); glEnd(); glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glColor4f(r, g, b, 0.2); + glColor4f(color.r, color.g, color.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 - 0.5) * 2.0 - ofsLeft, 1.0, 0.0); + glVertex3f((uxPos - 0.5) * 2.0 - ofsLeft, -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 + ofsRight, -1.0, 0.0); + glVertex3f((uxPos - 0.5) * 2.0 + ofsRight, 1.0, 0.0); glEnd(); GLint vp[4]; @@ -252,10 +258,12 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, float r, float g, f case DEMOD_TYPE_LSB: demodStr = "LSB"; demodAlign = GLFont::GLFONT_ALIGN_RIGHT; + uxPos -= xOfs; break; case DEMOD_TYPE_USB: demodStr = "USB"; demodAlign = GLFont::GLFONT_ALIGN_LEFT; + uxPos += xOfs; break; } @@ -269,11 +277,13 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, float r, float g, f } -void PrimaryGLContext::DrawFreqSelector(float uxPos, float r, float g, float b, float w, long long center_freq, long long srate) { +void PrimaryGLContext::DrawFreqSelector(float uxPos, RGBColor color, float w, long long center_freq, long long srate) { DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator(); long long bw = 0; + int last_type = wxGetApp().getDemodMgr().getLastDemodulatorType(); + if (!demod) { bw = wxGetApp().getDemodMgr().getLastBandwidth(); } else { @@ -288,9 +298,10 @@ void PrimaryGLContext::DrawFreqSelector(float uxPos, float r, float g, float b, glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glColor4f(r, g, b, 0.6); + glColor4f(color.r, color.g, color.b, 0.6); glBegin(GL_LINES); + glVertex3f((uxPos - 0.5) * 2.0, 1.0, 0.0); glVertex3f((uxPos - 0.5) * 2.0, -1.0, 0.0); @@ -302,17 +313,55 @@ void PrimaryGLContext::DrawFreqSelector(float uxPos, float r, float g, float b, 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); + if (last_type != DEMOD_TYPE_USB) { + 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); + if (last_type != DEMOD_TYPE_LSB) { + glVertex3f((uxPos - 0.5) * 2.0 + ofs, 1.0, 0.0); + glVertex3f((uxPos - 0.5) * 2.0 + ofs, -1.0, 0.0); + } glEnd(); glDisable(GL_BLEND); } +void PrimaryGLContext::DrawRangeSelector(float uxPos1, float uxPos2, RGBColor color) { + if (uxPos2 < uxPos1) { + float temp = uxPos2; + uxPos2=uxPos1; + uxPos1=temp; + } + + int last_type = wxGetApp().getDemodMgr().getLastDemodulatorType(); + + glDisable(GL_TEXTURE_2D); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + glColor4f(color.r, color.g, color.b, 0.6); + + glLineWidth((last_type == DEMOD_TYPE_USB)?2.0:1.0); + + glBegin(GL_LINES); + glVertex3f((uxPos1 - 0.5) * 2.0, 1.0, 0.0); + glVertex3f((uxPos1 - 0.5) * 2.0, -1.0, 0.0); + glEnd(); + + glLineWidth((last_type == DEMOD_TYPE_LSB)?2.0:1.0); + + glBegin(GL_LINES); + glVertex3f((uxPos2 - 0.5) * 2.0, 1.0, 0.0); + glVertex3f((uxPos2 - 0.5) * 2.0, -1.0, 0.0); + glEnd(); + + glLineWidth(1.0); + + glDisable(GL_BLEND); +} + void PrimaryGLContext::BeginDraw(float r, float g, float b) { glClearColor(r,g,b, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff --git a/src/visual/PrimaryGLContext.h b/src/visual/PrimaryGLContext.h index 6959393..2a97295 100644 --- a/src/visual/PrimaryGLContext.h +++ b/src/visual/PrimaryGLContext.h @@ -9,6 +9,7 @@ #include "CubicSDRDefs.h" #include "GLFont.h" #include "DemodulatorMgr.h" +#include "ColorTheme.h" class PrimaryGLContext: public wxGLContext { public: @@ -23,9 +24,10 @@ public: void BeginDraw(float r, float g, float b); void EndDraw(); - void DrawFreqSelector(float uxPos, float r = 1, float g = 1, float b = 1, float w = 0, long long center_freq = -1, long long srate = 0); - void DrawDemod(DemodulatorInstance *demod, float r = 1, float g = 1, float b = 1, long long center_freq = -1, long long srate = 0); - void DrawDemodInfo(DemodulatorInstance *demod, float r = 1, float g = 1, float b = 1, long long center_freq = -1, long long srate = 0); + void DrawFreqSelector(float uxPos, RGBColor color, float w = 0, long long center_freq = -1, long long srate = 0); + void DrawRangeSelector(float uxPos1, float uxPos2, RGBColor color); + void DrawDemod(DemodulatorInstance *demod, RGBColor color, long long center_freq = -1, long long srate = 0); + void DrawDemodInfo(DemodulatorInstance *demod, RGBColor color, long long center_freq = -1, long long srate = 0); static GLFont &getFont(GLFontSize esize); diff --git a/src/visual/SpectrumCanvas.cpp b/src/visual/SpectrumCanvas.cpp index e88733a..07cdd3f 100644 --- a/src/visual/SpectrumCanvas.cpp +++ b/src/visual/SpectrumCanvas.cpp @@ -83,7 +83,7 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { std::vector &demods = wxGetApp().getDemodMgr().getDemodulators(); for (int i = 0, iMax = demods.size(); i < iMax; i++) { - glContext->DrawDemodInfo(demods[i], ThemeMgr::mgr.currentTheme->fftHighlight.r, ThemeMgr::mgr.currentTheme->fftHighlight.g, ThemeMgr::mgr.currentTheme->fftHighlight.b, getCenterFrequency(), getBandwidth()); + glContext->DrawDemodInfo(demods[i], ThemeMgr::mgr.currentTheme->fftHighlight, getCenterFrequency(), getBandwidth()); } glContext->EndDraw(); diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 8669667..77f15cd 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -137,56 +137,49 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { int currentBandwidth = getBandwidth(); long long currentCenterFreq = getCenterFrequency(); + float demodColor, selectorColor; + ColorTheme *currentTheme = ThemeMgr::mgr.currentTheme; + int last_type = wxGetApp().getDemodMgr().getLastDemodulatorType(); + if (mouseTracker.mouseInView()) { if (nextDragState == WF_DRAG_RANGE) { - if (mouseTracker.mouseDown()) { - float width = mouseTracker.getOriginDeltaMouseX(); - float centerPos = mouseTracker.getOriginMouseX() + width / 2.0; + float width = (1.0 / (float) ClientSize.x); + float rangeWidth = mouseTracker.getOriginDeltaMouseX(); + float centerPos; - if (isNew) { - glContext->DrawDemod(lastActiveDemodulator, ThemeMgr::mgr.currentTheme->waterfallHighlight.r, ThemeMgr::mgr.currentTheme->waterfallHighlight.g, ThemeMgr::mgr.currentTheme->waterfallHighlight.b, currentCenterFreq, currentBandwidth); - glContext->DrawFreqSelector(centerPos, ThemeMgr::mgr.currentTheme->waterfallNew.r, ThemeMgr::mgr.currentTheme->waterfallNew.g, ThemeMgr::mgr.currentTheme->waterfallNew.b, width ? width : (1.0 / (float) ClientSize.x), currentCenterFreq, - currentBandwidth); - } else { - glContext->DrawDemod(lastActiveDemodulator, ThemeMgr::mgr.currentTheme->waterfallDestroy.r, ThemeMgr::mgr.currentTheme->waterfallDestroy.g, ThemeMgr::mgr.currentTheme->waterfallDestroy.b, currentCenterFreq, currentBandwidth); - glContext->DrawFreqSelector(centerPos, ThemeMgr::mgr.currentTheme->waterfallHover.r, ThemeMgr::mgr.currentTheme->waterfallHover.g, ThemeMgr::mgr.currentTheme->waterfallHover.b, width ? width : (1.0 / (float) ClientSize.x), currentCenterFreq, - currentBandwidth); + if (mouseTracker.mouseDown()) { + if (rangeWidth) { + width = rangeWidth; } + centerPos = mouseTracker.getOriginMouseX() + width / 2.0; } else { - if (isNew) { - glContext->DrawDemod(lastActiveDemodulator, ThemeMgr::mgr.currentTheme->waterfallHighlight.r, ThemeMgr::mgr.currentTheme->waterfallHighlight.g, ThemeMgr::mgr.currentTheme->waterfallHighlight.b, currentCenterFreq, currentBandwidth); - glContext->DrawFreqSelector(mouseTracker.getMouseX(), ThemeMgr::mgr.currentTheme->waterfallNew.r, ThemeMgr::mgr.currentTheme->waterfallNew.g, ThemeMgr::mgr.currentTheme->waterfallNew.b, 1.0 / (float) ClientSize.x, currentCenterFreq, currentBandwidth); - } else { - glContext->DrawDemod(lastActiveDemodulator,ThemeMgr::mgr.currentTheme->waterfallDestroy.r, ThemeMgr::mgr.currentTheme->waterfallDestroy.g, ThemeMgr::mgr.currentTheme->waterfallDestroy.b, currentCenterFreq, currentBandwidth); - glContext->DrawFreqSelector(mouseTracker.getMouseX(), ThemeMgr::mgr.currentTheme->waterfallHover.r, ThemeMgr::mgr.currentTheme->waterfallHover.g, ThemeMgr::mgr.currentTheme->waterfallHover.b, 1.0 / (float) ClientSize.x, currentCenterFreq, currentBandwidth); - } + centerPos = mouseTracker.getMouseX(); + } + + glContext->DrawDemod(lastActiveDemodulator, isNew?currentTheme->waterfallHighlight:currentTheme->waterfallDestroy, currentCenterFreq, currentBandwidth); + + if ((last_type == DEMOD_TYPE_LSB || last_type == DEMOD_TYPE_USB) && mouseTracker.mouseDown()) { + centerPos = mouseTracker.getMouseX(); + glContext->DrawRangeSelector(centerPos, centerPos-width, isNew?currentTheme->waterfallNew:currentTheme->waterfallHover); + } else { + glContext->DrawFreqSelector(centerPos, isNew?currentTheme->waterfallNew:currentTheme->waterfallHover, width, currentCenterFreq, currentBandwidth); } } else { + if (lastActiveDemodulator) { + glContext->DrawDemod(lastActiveDemodulator, ((isNew && activeDemodulator == NULL) || (activeDemodulator != NULL))?currentTheme->waterfallHighlight:currentTheme->waterfallDestroy, currentCenterFreq, currentBandwidth); + } if (activeDemodulator == NULL) { - if (lastActiveDemodulator) { - if (isNew) { - glContext->DrawDemod(lastActiveDemodulator, ThemeMgr::mgr.currentTheme->waterfallHighlight.r, ThemeMgr::mgr.currentTheme->waterfallHighlight.g, ThemeMgr::mgr.currentTheme->waterfallHighlight.b, currentCenterFreq, currentBandwidth); - glContext->DrawFreqSelector(mouseTracker.getMouseX(), ThemeMgr::mgr.currentTheme->waterfallNew.r, ThemeMgr::mgr.currentTheme->waterfallNew.g, ThemeMgr::mgr.currentTheme->waterfallNew.b, 0, currentCenterFreq, currentBandwidth); - } else { - glContext->DrawDemod(lastActiveDemodulator, ThemeMgr::mgr.currentTheme->waterfallDestroy.r, ThemeMgr::mgr.currentTheme->waterfallDestroy.g, ThemeMgr::mgr.currentTheme->waterfallDestroy.b, currentCenterFreq, currentBandwidth); - glContext->DrawFreqSelector(mouseTracker.getMouseX(), ThemeMgr::mgr.currentTheme->waterfallHover.r, ThemeMgr::mgr.currentTheme->waterfallHover.g, ThemeMgr::mgr.currentTheme->waterfallHover.b, 0, currentCenterFreq, currentBandwidth); - } - } else { - glContext->DrawFreqSelector(mouseTracker.getMouseX(), ThemeMgr::mgr.currentTheme->waterfallNew.r, ThemeMgr::mgr.currentTheme->waterfallNew.g, ThemeMgr::mgr.currentTheme->waterfallNew.b, 0, currentCenterFreq, currentBandwidth); - } + glContext->DrawFreqSelector(mouseTracker.getMouseX(), ((isNew && lastActiveDemodulator) || (!lastActiveDemodulator) )?currentTheme->waterfallNew:currentTheme->waterfallHover, 0, currentCenterFreq, currentBandwidth); } else { - if (lastActiveDemodulator) { - glContext->DrawDemod(lastActiveDemodulator, ThemeMgr::mgr.currentTheme->waterfallHighlight.r, ThemeMgr::mgr.currentTheme->waterfallHighlight.g, ThemeMgr::mgr.currentTheme->waterfallHighlight.b, currentCenterFreq, currentBandwidth); - } - glContext->DrawDemod(activeDemodulator, ThemeMgr::mgr.currentTheme->waterfallHover.r, ThemeMgr::mgr.currentTheme->waterfallHover.g, ThemeMgr::mgr.currentTheme->waterfallHover.b, currentCenterFreq, currentBandwidth); + glContext->DrawDemod(activeDemodulator, currentTheme->waterfallHover, currentCenterFreq, currentBandwidth); } } } else { if (activeDemodulator) { - glContext->DrawDemod(activeDemodulator, ThemeMgr::mgr.currentTheme->waterfallHighlight.r, ThemeMgr::mgr.currentTheme->waterfallHighlight.g, ThemeMgr::mgr.currentTheme->waterfallHighlight.b, currentCenterFreq, currentBandwidth); + glContext->DrawDemod(activeDemodulator, currentTheme->waterfallHighlight, currentCenterFreq, currentBandwidth); } if (lastActiveDemodulator) { - glContext->DrawDemod(lastActiveDemodulator, ThemeMgr::mgr.currentTheme->waterfallHighlight.r, ThemeMgr::mgr.currentTheme->waterfallHighlight.g, ThemeMgr::mgr.currentTheme->waterfallHighlight.b, currentCenterFreq, currentBandwidth); + glContext->DrawDemod(lastActiveDemodulator, currentTheme->waterfallHighlight, currentCenterFreq, currentBandwidth); } } @@ -194,7 +187,7 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { if (activeDemodulator == demods[i] || lastActiveDemodulator == demods[i]) { continue; } - glContext->DrawDemod(demods[i], ThemeMgr::mgr.currentTheme->waterfallHighlight.r, ThemeMgr::mgr.currentTheme->waterfallHighlight.g, ThemeMgr::mgr.currentTheme->waterfallHighlight.b, currentCenterFreq, currentBandwidth); + glContext->DrawDemod(demods[i], currentTheme->waterfallHighlight, currentCenterFreq, currentBandwidth); } glContext->EndDraw(); @@ -811,7 +804,25 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) { } } else if (dragState == WF_DRAG_RANGE) { float width = mouseTracker.getOriginDeltaMouseX(); - float pos = mouseTracker.getOriginMouseX() + width / 2.0; + + float pos; + int last_type = mgr->getLastDemodulatorType(); + + if (last_type == DEMOD_TYPE_LSB || last_type == DEMOD_TYPE_USB) { + float pos1 = mouseTracker.getOriginMouseX(); + float pos2 = mouseTracker.getMouseX(); + + if (pos2 < pos1) { + float tmp = pos1; + pos1 = pos2; + pos2 = tmp; + } + + pos = (last_type == DEMOD_TYPE_LSB)?pos2:pos1; + width *= 2; + } else { + pos = mouseTracker.getOriginMouseX() + width / 2.0; + } long long input_center_freq = getCenterFrequency(); long long freq = input_center_freq - (long long) (0.5 * (float) getBandwidth()) + (long long) ((float) pos * (float) getBandwidth());