Merge pull request #55 from cjcliffe/ssb-experimental

SSB improvements
This commit is contained in:
Charles J. Cliffe 2015-02-17 21:53:42 -05:00
commit 14881acdc9
9 changed files with 236 additions and 124 deletions

View File

@ -369,22 +369,35 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
demodModeSelector->setSelection(dType); demodModeSelector->setSelection(dType);
} }
if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) { if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) {
if (demod->getFrequency() != demodWaterfallCanvas->getCenterFrequency()) { long long centerFreq = demod->getFrequency();
demodWaterfallCanvas->setCenterFrequency(demod->getFrequency()); unsigned int demodBw = (unsigned int) ceil((float) demod->getBandwidth() * 2.5);
demodSpectrumCanvas->setCenterFrequency(demod->getFrequency());
} if (demod->getDemodulatorType() == DEMOD_TYPE_USB) {
int dSelection = demodModeSelector->getSelection(); demodBw /= 2;
if (dSelection != -1 && dSelection != demod->getDemodulatorType()) { centerFreq += demod->getBandwidth()/4;
demod->setDemodulatorType(dSelection); }
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) { if (demodBw > wxGetApp().getSampleRate() / 2) {
demodBw = wxGetApp().getSampleRate() / 2; demodBw = wxGetApp().getSampleRate() / 2;
} }
if (demodBw < 30000) { if (demodBw < 30000) {
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); demodWaterfallCanvas->setBandwidth(demodBw);
demodSpectrumCanvas->setBandwidth(demodBw); demodSpectrumCanvas->setBandwidth(demodBw);
} }

View File

@ -232,8 +232,8 @@ int DemodulatorInstance::getOutputDevice() {
} }
void DemodulatorInstance::checkBandwidth() { void DemodulatorInstance::checkBandwidth() {
if ((currentDemodType == DEMOD_TYPE_USB || currentDemodType == DEMOD_TYPE_LSB) && (getBandwidth() > 60000)) { if ((currentDemodType == DEMOD_TYPE_USB || currentDemodType == DEMOD_TYPE_LSB) && (getBandwidth() % 2)) {
setBandwidth(60000); setBandwidth(getBandwidth()+1);
} }
} }

View File

@ -77,7 +77,7 @@ std::vector<DemodulatorInstance *> *DemodulatorMgr::getDemodulatorsAt(long long
long long halfBuffer = bandwidth / 2; 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); foundDemods->push_back(testDemod);
} }
} }

View File

@ -70,6 +70,8 @@ void DemodulatorPreThread::threadMain() {
std::vector<liquid_float_complex> in_buf_data; std::vector<liquid_float_complex> in_buf_data;
std::vector<liquid_float_complex> out_buf_data; std::vector<liquid_float_complex> out_buf_data;
liquid_float_complex carrySample; // Keep the stream count even to simplify some demod operations
bool carrySampleFlag = false;
terminated = false; terminated = false;
@ -197,7 +199,30 @@ void DemodulatorPreThread::threadMain() {
msresamp_crcf_execute(iqResampler, in_buf, bufSize, &resampledData[0], &numWritten); msresamp_crcf_execute(iqResampler, in_buf, bufSize, &resampledData[0], &numWritten);
resamp->setRefCount(1); 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->audioResampleRatio = audioResampleRatio;
resamp->audioResampler = audioResampler; resamp->audioResampler = audioResampler;

View File

@ -14,8 +14,8 @@ DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* iqInputQue
0), squelchEnabled(false) { 0), squelchEnabled(false) {
demodFM = freqdem_create(0.5); demodFM = freqdem_create(0.5);
demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_LSB, 1); demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1);
demodAM_LSB = 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 = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 1);
demodAM_DSB_CSP = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0); demodAM_DSB_CSP = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_DSB, 0);
demodAM = demodAM_DSB_CSP; demodAM = demodAM_DSB_CSP;
@ -64,7 +64,8 @@ void DemodulatorThread::threadMain() {
delete h; 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 firStereoR2C = firhilbf_create(5, 60.0f);
firhilbf firStereoC2R = 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 ssbShifterDown = nco_crcf_create(LIQUID_NCO);
nco_crcf_set_frequency(ssbShifterDown, (2.0 * M_PI) * 0.25); nco_crcf_set_frequency(ssbShifterDown, (2.0 * M_PI) * 0.25);
float ssbFt = 0.001f; // filter transition // half band interp / decimate used for side-band elimination
float ssbAs = 120.0f; // stop-band attenuation [dB] resamp2_crcf ssbInterp = resamp2_crcf_create(7, 0.0f, -120.0f);
resamp2_crcf ssbDecim = resamp2_crcf_create(7, 0.0f, -120.0f);
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;
// Automatic IQ gain // Automatic IQ gain
iqAutoGain = agc_crcf_create(); iqAutoGain = agc_crcf_create();
@ -103,10 +97,10 @@ void DemodulatorThread::threadMain() {
case DEMOD_TYPE_FM: case DEMOD_TYPE_FM:
break; break;
case DEMOD_TYPE_LSB: case DEMOD_TYPE_LSB:
demodAM = demodAM_USB; demodAM = demodAM_LSB;
break; break;
case DEMOD_TYPE_USB: case DEMOD_TYPE_USB:
demodAM = demodAM_LSB; demodAM = demodAM_USB;
break; break;
case DEMOD_TYPE_DSB: case DEMOD_TYPE_DSB:
demodAM = demodAM_DSB; demodAM = demodAM_DSB;
@ -181,42 +175,59 @@ void DemodulatorThread::threadMain() {
float p; float p;
switch (demodulatorType.load()) { switch (demodulatorType.load()) {
case DEMOD_TYPE_LSB: case DEMOD_TYPE_LSB:
for (int i = 0; i < bufSize; i++) { // Reject upper band for (int i = 0; i < bufSize / 2; i++) { // Reject upper band
nco_crcf_mix_up(ssbShifterUp, inp->data[i], &x); nco_crcf_mix_up(ssbShifterUp, inp->data[i * 2], &z[0]);
nco_crcf_step(ssbShifterUp); nco_crcf_step(ssbShifterUp);
firfilt_crcf_push(firSSB, x); nco_crcf_mix_up(ssbShifterUp, inp->data[i * 2 + 1], &z[1]);
firfilt_crcf_execute(firSSB, &x); nco_crcf_step(ssbShifterUp);
nco_crcf_mix_down(ssbShifterDown, x, &(inp->data[i])); 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_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; break;
case DEMOD_TYPE_USB: case DEMOD_TYPE_USB:
for (int i = 0; i < bufSize; i++) { // Reject lower band for (int i = 0; i < bufSize / 2; i++) { // Reject lower band
nco_crcf_mix_down(ssbShifterDown, inp->data[i], &x); nco_crcf_mix_down(ssbShifterDown, inp->data[i * 2], &z[0]);
nco_crcf_step(ssbShifterDown); nco_crcf_step(ssbShifterDown);
firfilt_crcf_push(firSSB, x); nco_crcf_mix_down(ssbShifterDown, inp->data[i * 2 + 1], &z[1]);
firfilt_crcf_execute(firSSB, &x); nco_crcf_step(ssbShifterDown);
nco_crcf_mix_up(ssbShifterUp, x, &(inp->data[i])); 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_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; break;
case DEMOD_TYPE_AM: case DEMOD_TYPE_AM:
case DEMOD_TYPE_DSB: case DEMOD_TYPE_DSB:
for (int i = 0; i < bufSize; i++) {
ampmodem_demodulate(demodAM, inp->data[i], &demodOutputData[i]);
}
break; break;
} }
amOutputCeilMA = amOutputCeilMA + (amOutputCeil - amOutputCeilMA) * 0.05;
amOutputCeilMAA = amOutputCeilMAA + (amOutputCeilMA - amOutputCeilMAA) * 0.05;
amOutputCeil = 0; amOutputCeil = 0;
for (int i = 0; i < bufSize; i++) { for (int i = 0; i < bufSize; i++) {
ampmodem_demodulate(demodAM, inp->data[i], &demodOutputData[i]);
if (demodOutputData[i] > amOutputCeil) { if (demodOutputData[i] > amOutputCeil) {
amOutputCeil = demodOutputData[i]; 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++) { for (int i = 0; i < bufSize; i++) {
demodOutputData[i] *= gain; demodOutputData[i] *= gain;
@ -316,7 +327,8 @@ void DemodulatorThread::threadMain() {
std::vector<float>::iterator data_i; std::vector<float>::iterator data_i;
ati->peak = 0; ati->peak = 0;
for (data_i = ati->data.begin(); data_i != ati->data.end(); data_i++) { 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; ati->peak = p;
} }
} }
@ -389,11 +401,11 @@ void DemodulatorThread::threadMain() {
freqdem_reset(demodFM); freqdem_reset(demodFM);
break; break;
case DEMOD_TYPE_LSB: case DEMOD_TYPE_LSB:
demodAM = demodAM_USB; demodAM = demodAM_LSB;
ampmodem_reset(demodAM); ampmodem_reset(demodAM);
break; break;
case DEMOD_TYPE_USB: case DEMOD_TYPE_USB:
demodAM = demodAM_LSB; demodAM = demodAM_USB;
ampmodem_reset(demodAM); ampmodem_reset(demodAM);
break; break;
case DEMOD_TYPE_DSB: case DEMOD_TYPE_DSB:

View File

@ -97,7 +97,7 @@ GLFont &PrimaryGLContext::getFont(GLFontSize esize) {
return fonts[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) { if (!demod) {
return; return;
} }
@ -122,10 +122,10 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 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 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 labelHeight = 20.0 / viewHeight;
float hPos = -1.0 + labelHeight; float hPos = -1.0 + labelHeight;
@ -134,48 +134,53 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float
glColor4f(0, 0, 0, 0.35); glColor4f(0, 0, 0, 0.35);
glBegin(GL_QUADS); glBegin(GL_QUADS);
glVertex3f(uxPos - ofs, hPos + labelHeight, 0.0); glVertex3f(uxPos - ofsLeft, hPos + labelHeight, 0.0);
glVertex3f(uxPos - ofs, -1.0, 0.0); glVertex3f(uxPos - ofsLeft, -1.0, 0.0);
glVertex3f(uxPos + ofs, -1.0, 0.0); glVertex3f(uxPos + ofsRight, -1.0, 0.0);
glVertex3f(uxPos + ofs, hPos + labelHeight, 0.0); glVertex3f(uxPos + ofsRight, hPos + labelHeight, 0.0);
glEnd(); glEnd();
glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glColor4f(r, g, b, 0.2); glColor4f(color.r, color.g, color.b, 0.2);
glBegin(GL_QUADS); glBegin(GL_QUADS);
glVertex3f(uxPos - ofs, 1.0, 0.0); glVertex3f(uxPos - ofsLeft, 1.0, 0.0);
glVertex3f(uxPos - ofs, -1.0, 0.0); glVertex3f(uxPos - ofsLeft, -1.0, 0.0);
glVertex3f(uxPos + ofs, -1.0, 0.0); glVertex3f(uxPos + ofsRight, -1.0, 0.0);
glVertex3f(uxPos + ofs, 1.0, 0.0); glVertex3f(uxPos + ofsRight, 1.0, 0.0);
glEnd(); glEnd();
if (ofs * 2.0 < 16.0 / viewWidth) { if (ofs * 2.0 < 16.0 / viewWidth) {
ofs = 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); glBegin(GL_QUADS);
glVertex3f(uxPos - ofs, hPos + labelHeight, 0.0); glVertex3f(uxPos - ofsLeft, hPos + labelHeight, 0.0);
glVertex3f(uxPos - ofs, -1.0, 0.0); glVertex3f(uxPos - ofsLeft, -1.0, 0.0);
glVertex3f(uxPos + ofs, -1.0, 0.0); glVertex3f(uxPos + ofsRight, -1.0, 0.0);
glVertex3f(uxPos + ofs, hPos + labelHeight, 0.0); glVertex3f(uxPos + ofsRight, hPos + labelHeight, 0.0);
glEnd(); glEnd();
} }
glColor4f(1.0, 1.0, 1.0, 0.8); 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); 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) { if (!demod) {
return; return;
} }
@ -193,30 +198,31 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, float r, float g, f
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE); 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); glBegin(GL_LINES);
glVertex3f((uxPos - 0.5) * 2.0, 1.0, 0.0); glVertex3f((uxPos - 0.5) * 2.0, 1.0, 0.0);
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 + ofsRight, 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 + ofs, 1.0, 0.0);
glVertex3f((uxPos - 0.5) * 2.0 + ofs, -1.0, 0.0);
glEnd(); glEnd();
glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glColor4f(r, g, b, 0.2); glColor4f(color.r, color.g, color.b, 0.2);
glBegin(GL_QUADS); glBegin(GL_QUADS);
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 - ofs, -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 + ofsRight, -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);
glEnd(); glEnd();
GLint vp[4]; GLint vp[4];
@ -252,10 +258,12 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, float r, float g, f
case DEMOD_TYPE_LSB: case DEMOD_TYPE_LSB:
demodStr = "LSB"; demodStr = "LSB";
demodAlign = GLFont::GLFONT_ALIGN_RIGHT; demodAlign = GLFont::GLFONT_ALIGN_RIGHT;
uxPos -= xOfs;
break; break;
case DEMOD_TYPE_USB: case DEMOD_TYPE_USB:
demodStr = "USB"; demodStr = "USB";
demodAlign = GLFont::GLFONT_ALIGN_LEFT; demodAlign = GLFont::GLFONT_ALIGN_LEFT;
uxPos += xOfs;
break; 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(); DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
long long bw = 0; long long bw = 0;
int last_type = wxGetApp().getDemodMgr().getLastDemodulatorType();
if (!demod) { if (!demod) {
bw = wxGetApp().getDemodMgr().getLastBandwidth(); bw = wxGetApp().getDemodMgr().getLastBandwidth();
} else { } else {
@ -288,9 +298,10 @@ void PrimaryGLContext::DrawFreqSelector(float uxPos, float r, float g, float b,
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glColor4f(r, g, b, 0.6); glColor4f(color.r, color.g, color.b, 0.6);
glBegin(GL_LINES); glBegin(GL_LINES);
glVertex3f((uxPos - 0.5) * 2.0, 1.0, 0.0); glVertex3f((uxPos - 0.5) * 2.0, 1.0, 0.0);
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; ofs = ((float) bw) / (float) srate;
} }
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);
glVertex3f((uxPos - 0.5) * 2.0 + ofs, -1.0, 0.0);
}
glEnd(); glEnd();
glDisable(GL_BLEND); 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) { void PrimaryGLContext::BeginDraw(float r, float g, float b) {
glClearColor(r,g,b, 1); glClearColor(r,g,b, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

View File

@ -9,6 +9,7 @@
#include "CubicSDRDefs.h" #include "CubicSDRDefs.h"
#include "GLFont.h" #include "GLFont.h"
#include "DemodulatorMgr.h" #include "DemodulatorMgr.h"
#include "ColorTheme.h"
class PrimaryGLContext: public wxGLContext { class PrimaryGLContext: public wxGLContext {
public: public:
@ -23,9 +24,10 @@ public:
void BeginDraw(float r, float g, float b); void BeginDraw(float r, float g, float b);
void EndDraw(); 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 DrawFreqSelector(float uxPos, RGBColor color, 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 DrawRangeSelector(float uxPos1, float uxPos2, RGBColor color);
void DrawDemodInfo(DemodulatorInstance *demod, float r = 1, float g = 1, float b = 1, long long center_freq = -1, long long srate = 0); 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); static GLFont &getFont(GLFontSize esize);

View File

@ -83,7 +83,7 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
std::vector<DemodulatorInstance *> &demods = wxGetApp().getDemodMgr().getDemodulators(); std::vector<DemodulatorInstance *> &demods = wxGetApp().getDemodMgr().getDemodulators();
for (int i = 0, iMax = demods.size(); i < iMax; i++) { 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(); glContext->EndDraw();

View File

@ -137,56 +137,49 @@ void WaterfallCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
int currentBandwidth = getBandwidth(); int currentBandwidth = getBandwidth();
long long currentCenterFreq = getCenterFrequency(); long long currentCenterFreq = getCenterFrequency();
float demodColor, selectorColor;
ColorTheme *currentTheme = ThemeMgr::mgr.currentTheme;
int last_type = wxGetApp().getDemodMgr().getLastDemodulatorType();
if (mouseTracker.mouseInView()) { if (mouseTracker.mouseInView()) {
if (nextDragState == WF_DRAG_RANGE) { if (nextDragState == WF_DRAG_RANGE) {
if (mouseTracker.mouseDown()) { float width = (1.0 / (float) ClientSize.x);
float width = mouseTracker.getOriginDeltaMouseX(); float rangeWidth = mouseTracker.getOriginDeltaMouseX();
float centerPos = mouseTracker.getOriginMouseX() + width / 2.0; float centerPos;
if (isNew) { if (mouseTracker.mouseDown()) {
glContext->DrawDemod(lastActiveDemodulator, ThemeMgr::mgr.currentTheme->waterfallHighlight.r, ThemeMgr::mgr.currentTheme->waterfallHighlight.g, ThemeMgr::mgr.currentTheme->waterfallHighlight.b, currentCenterFreq, currentBandwidth); if (rangeWidth) {
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, width = rangeWidth;
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);
} }
centerPos = mouseTracker.getOriginMouseX() + width / 2.0;
} else { } else {
if (isNew) { centerPos = mouseTracker.getMouseX();
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, isNew?currentTheme->waterfallHighlight:currentTheme->waterfallDestroy, currentCenterFreq, currentBandwidth);
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); 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 { } else {
if (lastActiveDemodulator) {
glContext->DrawDemod(lastActiveDemodulator, ((isNew && activeDemodulator == NULL) || (activeDemodulator != NULL))?currentTheme->waterfallHighlight:currentTheme->waterfallDestroy, currentCenterFreq, currentBandwidth);
}
if (activeDemodulator == NULL) { if (activeDemodulator == NULL) {
if (lastActiveDemodulator) { glContext->DrawFreqSelector(mouseTracker.getMouseX(), ((isNew && lastActiveDemodulator) || (!lastActiveDemodulator) )?currentTheme->waterfallNew:currentTheme->waterfallHover, 0, currentCenterFreq, currentBandwidth);
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);
}
} else { } else {
if (lastActiveDemodulator) { glContext->DrawDemod(activeDemodulator, currentTheme->waterfallHover, currentCenterFreq, currentBandwidth);
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);
} }
} }
} else { } else {
if (activeDemodulator) { 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) { 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]) { if (activeDemodulator == demods[i] || lastActiveDemodulator == demods[i]) {
continue; 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(); glContext->EndDraw();
@ -811,7 +804,25 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
} }
} else if (dragState == WF_DRAG_RANGE) { } else if (dragState == WF_DRAG_RANGE) {
float width = mouseTracker.getOriginDeltaMouseX(); 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 input_center_freq = getCenterFrequency();
long long freq = input_center_freq - (long long) (0.5 * (float) getBandwidth()) + (long long) ((float) pos * (float) getBandwidth()); long long freq = input_center_freq - (long long) (0.5 * (float) getBandwidth()) + (long long) ((float) pos * (float) getBandwidth());