Merge with upstream

pull/2/head
Stelios Bounanos 2008-02-14 20:20:24 +00:00
commit 3248b76856
14 zmienionych plików z 272 dodań i 110 usunięć

Wyświetl plik

@ -1,5 +1,9 @@
Change Log:
2.10 1) Added history (ctrl-Left-click in waterfall). Available after tracking
has started. This does not start a new signal acquisition.
2) Psk and ViewPsk use shared signal detection class
2.09 1) Modified src/Makefile.am for FreeBSD name space clash
2) Added psk multi-channel viewer with regex search capability
3) Rewrote audio capture/playback/generate routines to use the

Wyświetl plik

@ -4,7 +4,7 @@
AC_COPYRIGHT([Copyright (C) 2007 Stelios Bounanos, M0GLD (m0gld AT enotty DOT net)])
AC_PREREQ(2.61)
AC_INIT([fldigi], [2.09], [w1hkj AT w1hkj DOT com])
AC_INIT([fldigi], [2.10A], [w1hkj AT w1hkj DOT com])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([-Wall foreign std-options 1.9.6])
AM_MAINTAINER_MODE

Wyświetl plik

@ -154,6 +154,7 @@ fldigi_SOURCES += \
include/viewpsk.h \
include/pskcoeff.h \
include/pskvaricode.h \
include/pskeval.h \
include/ptt.h \
include/qrunner.h \
include/qrzcall.h \
@ -217,6 +218,7 @@ fldigi_SOURCES += \
psk/pskcoeff.cxx \
psk/pskvaricode.cxx \
psk/viewpsk.cxx \
psk/pskeval.cxx \
qrunner/fqueue.h \
qrunner/qrunner.cxx \
rigcontrol/FreqControl.cxx \

Wyświetl plik

@ -965,8 +965,8 @@ Fl_Menu_Item menu_[] = {
{" ", 0, 0, 0, FL_MENU_INACTIVE, FL_NORMAL_LABEL, 0, 14, 0},
{"Rig", 0, (Fl_Callback*)cb_mnuRig, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{" ", 0, 0, 0, FL_MENU_INACTIVE, FL_NORMAL_LABEL, 0, 14, 0},
{"Viewer", 0, (Fl_Callback*)cb_mnuViewer, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{"Viewer", 0, (Fl_Callback*)cb_mnuViewer, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
{" ", 0, 0, 0, FL_MENU_INACTIVE, FL_NORMAL_LABEL, 0, 14, 0},
{"Help", 0, 0, 0, FL_SUBMENU, FL_NORMAL_LABEL, 0, 14, 0},

Wyświetl plik

@ -89,7 +89,7 @@ public:
double get_squelch() { return squelch; }
void set_sqlchOnOff(bool val) {squelchon = val;}
bool get_sqlchOnOff() { return squelchon;}
void set_afcOnOff(bool val) {afcon = val;}
void set_afcOnOff(int val) {afcon = val;}
bool get_afcOnOff() { return afcon;}
// void set_mode(trx_mode);

Wyświetl plik

@ -37,7 +37,7 @@
#define PipeLen (64)
#define SNTHRESHOLD 2.0
#define AFCDECAY 8
#define AFCDECAYSLOW 8
//=====================================================================
class psk : public modem {
@ -53,6 +53,7 @@ private:
C_FIR_filter *fir1;
C_FIR_filter *fir2;
// C_FIR_filter *fir3;
double *fir1c;
double *fir2c;
@ -69,6 +70,7 @@ private:
int dcd;
int dcdbits;
complex quality;
void rx_symbol(complex symbol);
void rx_bit(int bit);
void rx_qpsk(int bits);
@ -78,6 +80,8 @@ private:
double I11, I12, I21, I22, I31, I32;
double snratio, s2n, imdratio, imd;
double E1, E2, E3;
double twopi;
// complex thirdorder;
// tx variables & functions
double *tx_shape;
@ -91,6 +95,7 @@ private:
void findsignal();
void phaseafc();
void afc();
void coreafc();
public:
psk(trx_mode mode);

Wyświetl plik

@ -0,0 +1,51 @@
// ----------------------------------------------------------------------------
// pskeval.cxx -- psk signal evaluator
//
// Copyright (C) 2008
// Dave Freese, W1HKJ
//
// This file is part of fldigi. Adapted from code contained in gmfsk source code
// distribution.
//
// fldigi is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// fldigi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with fldigi; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// ----------------------------------------------------------------------------
#ifndef _PSKEVAL_H
#define _PSKEVAL_H
#include "complex.h"
#include "trx.h"
#include "filters.h"
#include "fldigi-config.h"
#include "waterfall.h"
#define FLOWER 200
#define FUPPER 4000
class pskeval {
private:
double sigpwr[FFT_LEN];
double sigavg;
double bw;
public:
pskeval();
~pskeval();
void clear();
void setbw(double w) { bw = w;}
void sigdensity();
double sigpeak(int &f, int f1, int f2);
};
#endif

Wyświetl plik

@ -53,4 +53,6 @@ extern modem *active_modem;
extern cSound *scard;
extern bool bHistory;
#endif

Wyświetl plik

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------------
// psk.h -- psk modem
// viewpsk.h -- psk modem
//
// Copyright (C) 2006
// Copyright (C) 2008
// Dave Freese, W1HKJ
//
// This file is part of fldigi. Adapted from code contained in gmfsk source code

Wyświetl plik

@ -30,11 +30,13 @@
#include <stdlib.h>
#include <stdio.h>
#include <iomanip>
#include "psk.h"
#include "waterfall.h"
#include "configuration.h"
#include "viewpsk.h"
#include "pskeval.h"
extern waterfall *wf;
@ -47,6 +49,7 @@ extern waterfall *wf;
// Change the following for DCD low pass filter adjustment
#define SQLCOEFF 0.01
#define SQLDECAY 100
//=====================================================================
@ -56,6 +59,7 @@ extern waterfall *wf;
char pskmsg[80];
viewpsk *pskviewer = (viewpsk *)0;
pskeval *evalpsk = (pskeval *)0;
void psk::tx_init(cSound *sc)
{
@ -86,6 +90,8 @@ void psk::restart()
{
if (!pskviewer) pskviewer = new viewpsk(mode);
else pskviewer->restart(mode);
if (!evalpsk) evalpsk = new pskeval;
evalpsk->setbw(bandwidth);
}
void psk::init()
@ -107,6 +113,8 @@ psk::~psk()
psk::psk(trx_mode pskmode) : modem()
{
mode = pskmode;
twopi = 2.0 * M_PI;
switch (mode) {
case MODE_BPSK31:
@ -172,6 +180,7 @@ psk::psk(trx_mode pskmode) : modem()
wsincfilt(fir1c, 1.0 / symbollen, true); // creates fir1c matched sin(x)/x filter w blackman
wsincfilt(fir2c, 1.0 / 16.0, true); // creates fir2c matched sin(x)/x filter w blackman
// wsincfilt(fir1c, 1.0 / symbollen, false); // creates fir1c matched sin(x)/x filter w hamming
// wsincfilt(fir2c, 1.0 / 16.0, false); // creates fir2c matched sin(x)/x filter w hamming
// wsincfilt(fir2c, 1.0 / 22.0, false); // 1/22 with Hamming window
@ -185,6 +194,7 @@ psk::psk(trx_mode pskmode) : modem()
fir2 = new C_FIR_filter();
fir2->init(FIRLEN, 1, fir2c, fir2c);
if (_qpsk) {
enc = new encoder(K, POLY1, POLY2);
dec = new viterbi(K, POLY1, POLY2);
@ -330,31 +340,40 @@ void psk::findsignal()
}
} else {
// normal signal search
searchBW = progdefaults.SearchRange;
ftest = wf->peakFreq((int)(frequency), searchBW);
sigpwr = wf->powerDensity(ftest, bandwidth);
noise = wf->powerDensity(ftest + 2 * bandwidth / 2, bandwidth / 2) +
wf->powerDensity(ftest - 2 * bandwidth / 2, bandwidth / 2) + 1e-20;
if (sigpwr/noise > SNTHRESHOLD) { // larger than the detection threshold)
frequency = ftest;
set_freq(frequency);
freqerr = 0.0;
}
int ftest;
int f1 = (int)(frequency - progdefaults.SearchRange/2);
int f2 = (int)(frequency + progdefaults.SearchRange/2);
if (evalpsk->sigpeak(ftest, f1, f2) > SNTHRESHOLD ){//SNTHRESHOLD) {
frequency = ftest;
set_freq(frequency);
freqerr = 0.0;
}
// searchBW = progdefaults.SearchRange;
// ftest = wf->peakFreq((int)(frequency), searchBW);
// sigpwr = wf->powerDensity(ftest, bandwidth);
// noise = wf->powerDensity(ftest + 2 * bandwidth / 2, bandwidth / 2) +
// wf->powerDensity(ftest - 2 * bandwidth / 2, bandwidth / 2) + 1e-20;
// if (sigpwr/noise > SNTHRESHOLD) { // larger than the detection threshold)
// frequency = ftest;
// set_freq(frequency);
// freqerr = 0.0;
// }
}
}
}
void psk::phaseafc()
{
double error;
error = (phase - bits * M_PI / 2);
if (error < M_PI / 2)
error += 2 * M_PI;
if (error > M_PI / 2)
error -= 2 * M_PI;
error *= ((samplerate / (symbollen * 2 * M_PI)/16));
error = (phase - bits * M_PI / 2.0);
if (error < -M_PI/2.0)
error += twopi;
if (error > M_PI/2.0)
error -= twopi;
error *= ((samplerate / twopi) / (16.0 * symbollen));
if (fabs(error) < bandwidth) {
freqerr = decayavg( freqerr, error, AFCDECAY);
freqerr = decayavg( freqerr, error, AFCDECAYSLOW);
frequency -= freqerr;
set_freq (frequency);
}
@ -378,7 +397,7 @@ void psk::rx_symbol(complex symbol)
prevsymbol = symbol;
if (phase < 0)
phase += 2 * M_PI;
phase += twopi;
if (_qpsk) {
bits = ((int) (phase / M_PI_2 + 0.5)) & 3;
n = 4;
@ -389,9 +408,9 @@ void psk::rx_symbol(complex symbol)
// simple low pass filter for quality of signal
// quality.re = 0.02 * cos(n * phase) + 0.98 * quality.re;
// quality.im = 0.02 * sin(n * phase) + 0.98 * quality.im;
quality.re = SQLCOEFF * cos(n * phase) + (1.0 - SQLCOEFF) * quality.re;
quality.im = SQLCOEFF * sin(n * phase) + (1.0 - SQLCOEFF) * quality.im;
quality.re = decayavg(quality.re, cos(n*phase), SQLDECAY);
quality.im = decayavg(quality.im, cos(n*phase), SQLDECAY);
metric = 100.0 * quality.norm();
dcdshreg = (dcdshreg << 2) | bits;
@ -460,11 +479,15 @@ char bitstatus[100];
int psk::rx_process(const double *buf, int len)
{
double delta;
complex z;
complex z, z2;//, z3;
if (pskviewer) pskviewer->rx_process(buf, len);
delta = 2.0 * M_PI * frequency / samplerate;
if (pskviewer && !bHistory) pskviewer->rx_process(buf, len);
if (evalpsk) evalpsk->sigdensity();
if (afcon == 2)
sigsearch = 0;
delta = twopi * frequency / samplerate;
signalquality();
@ -474,27 +497,30 @@ int psk::rx_process(const double *buf, int len)
buf++;
phaseacc += delta;
if (phaseacc > M_PI)
phaseacc -= 2.0 * M_PI;
phaseacc -= twopi;
// Filter and downsample
// by 16 (psk31, qpsk31)
// by 8 (psk63, qpsk63)
// by 4 (psk125, qpsk125)
// by 2 (psk250, qpsk250)
// first filter
if (fir1->run( z, z )) { // fir1 returns true every Nth sample
// final filter
fir2->run( z, z ); // fir3 returns value on every sample
fir2->run( z, z2 ); // fir2 returns value on every sample
// fir3->run( z, z3);
// coreafc(z3);
int idx = (int) bitclk;
double sum = 0.0;
double ampsum = 0.0;
syncbuf[idx] = 0.8 * syncbuf[idx] + 0.2 * z.mag();
syncbuf[idx] = 0.8 * syncbuf[idx] + 0.2 * z2.mag();
for (int i = 0; i < 8; i++) {
sum += (syncbuf[i] - syncbuf[i+8]);
ampsum += (syncbuf[i] + syncbuf[i+8]);
}
// added correction as per PocketDigi
// vastly improved performance with synchronous interference !!
sum = (ampsum == 0 ? 0 : sum / ampsum);
bitclk -= sum / 5.0;
@ -503,7 +529,7 @@ int psk::rx_process(const double *buf, int len)
if (bitclk < 0) bitclk += 16.0;
if (bitclk >= 16.0) {
bitclk -= 16.0;
rx_symbol(z);
rx_symbol(z2);
update_syncscope();
afc();
}

Wyświetl plik

@ -0,0 +1,89 @@
// ----------------------------------------------------------------------------
// pskeval.cxx -- psk signal evaluator
//
// Copyright (C) 2008
// Dave Freese, W1HKJ
//
// This file is part of fldigi. Adapted from code contained in gmfsk source code
// distribution.
//
// fldigi is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// fldigi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with fldigi; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// ----------------------------------------------------------------------------
#include "pskeval.h"
//=============================================================================
//========================== psk signal evaluation ============================
//=============================================================================
double alpha = 0.125;
pskeval::pskeval() {
bw = 31.25;
clear();
}
pskeval::~pskeval() {
}
//static int evalcount = 1;
void pskeval::sigdensity() {
double sig = 0.0;
double val;
int ihbw = (int)(bw / 2 + 0.5) + 1;
int ibw = 2 * ihbw;
int fstart = FLOWER + ibw;
double *vals = new double[ibw + 1];
for (int i = 0; i < ibw + 1; i++) vals[i] = 0.0;
int j = -1;
sigavg = 0.0;
for (int i = FLOWER; i < IMAGE_WIDTH; i++) {
j++;
if (j == ibw + 1) j = 0;
val = wf->Pwr(i);
if (i >= fstart) {
sigpwr[i - ihbw - 1] = (1-alpha)*sigpwr[i - ihbw - 1] + alpha * sig;
// sigpwr[i - ihbw - 1] = sig;
sig -= vals[j];
}
vals[j] = val;
sig += val;
sigavg += val;
}
sigavg /= (FFT_LEN - FLOWER);
if (sigavg == 0) sigavg = 1e-20;
// if (evalcount++ < 100) {
// for (int i = FLOWER; i < IMAGE_WIDTH; i++)
// std::cout << i << "," << sigpwr[i] / sigavg << std::endl;
// std::cout.flush();
// }
}
double pskeval::sigpeak(int &f, int f1, int f2)
{
double peak = 0;
f = (f1 + f2) / 2;
for (int i = f1; i <= f2; i++)
if (sigpwr[i] > peak) {
peak = sigpwr[i];
f = i;
}
return peak / sigavg / bw;
}
void pskeval::clear() {
for (int i = 0; i < FFT_LEN; i++) sigpwr[i] = 0.0;
}

Wyświetl plik

@ -34,6 +34,7 @@
#include <stdio.h>
#include "viewpsk.h"
#include "pskeval.h"
#include "pskcoeff.h"
#include "pskvaricode.h"
#include "waterfall.h"
@ -42,6 +43,7 @@
#include "qrunner.h"
extern waterfall *wf;
extern pskeval *evalpsk;
//=====================================================================
// Change the following for DCD low pass filter adjustment
@ -144,22 +146,20 @@ void viewpsk::restart(trx_mode pskmode)
init();
}
int sigcnt = 0;
//=============================================================================
//========================== viewpsk signal evaluation ========================
//=============================================================================
void viewpsk::sigdensity() {
sigcnt++;
double sig = 0.0;
double val;
int hbw = (int)(bandwidth / 2);
int twohbw = 2 * hbw;
int flower = progdefaults.VIEWERstart - 50; //nomfreq[0] - 50;
int fupper = flower + 100 * progdefaults.VIEWERchannels + 100; //nomfreq[MAXCHANNELS-1] + 50;
int flower = progdefaults.VIEWERstart - 50;
int fupper = flower + 100 * progdefaults.VIEWERchannels + 100;
double *vals = new double[twohbw + 1];
int j = -1;
sigavg = 0.0;
// sigmin = 1e6;
sigmin = 1e6;
for (int i = flower - hbw; i < fupper + hbw; i++) {
j++;
if (j == twohbw + 1) j = 0;
@ -171,14 +171,9 @@ void viewpsk::sigdensity() {
vals[j] = val;
sig += val;
sigavg += val;
// if (sig && sig < sigmin) sigmin = sig;
if (sig > 0 && sig < sigmin) sigmin = sig;
}
sigavg /= (fupper - flower - 100);
//if (sigcnt == 32)
// for (int i = flower; i <= fupper; i++)
// std::cout << i << ", " << sigpwr[i] / sigavg << std::endl;
}
double viewpsk::sigpeak(int &f, int f1, int f2)
@ -205,7 +200,7 @@ void viewpsk::rx_bit(int ch, int bit)
if ((shreg[ch] & 3) == 0) {
c = psk_varicode_decode(shreg[ch] >> 2);
shreg[ch] = 0;
// if (c != -1) {
if (c == '\n') c = ' ';
if (c >= ' ' && c <= 'z') {
REQ(&viewaddchr, ch, (int)frequency[ch], c);
timeout[ch] = now + progdefaults.VIEWERtimeout;
@ -215,36 +210,21 @@ void viewpsk::rx_bit(int ch, int bit)
void viewpsk::findsignal(int ch)
{
// double ftest, sigpwr, noise;
if (waitcount[ch] > 0) {
waitcount[ch]--;
return;
}
// ftest = wf->peakFreq((int)(frequency[ch]), VSEARCHWIDTH + (int)(bandwidth / 2));
// sigpwr = wf->powerDensity(ftest, bandwidth);
// noise = wf->powerDensity(ftest + 2 * bandwidth, bandwidth / 2) +
// wf->powerDensity(ftest - 2 * bandwidth, bandwidth / 2) + 1e-20;
// if (sigpwr/noise > VSNTHRESHOLD) { // larger than the search threshold
// if (ftest - nomfreq[ch] > VSEARCHWIDTH) ftest = nomfreq[ch] + VSEARCHWIDTH;
// if (ftest - nomfreq[ch] < -VSEARCHWIDTH) ftest = nomfreq[ch] - VSEARCHWIDTH;
// frequency[ch] = ftest;
// } else { // less than the detection threshold
// frequency[ch] = nomfreq[ch];
// sigsearch[ch] = VSIGSEARCH;
// }
int ftest;
int f1 = (int)(nomfreq[ch] - VSEARCHWIDTH);
int f2 = (int)(nomfreq[ch] + VSEARCHWIDTH);
if (sigpeak(ftest, f1, f2) > VSNTHRESHOLD) {
frequency[ch] = ftest;
sigsearch[ch] = 0;
}
else
frequency[ch] = nomfreq[ch];
freqerr[ch] = 0.0;
// }
int ftest;
int f1 = (int)(nomfreq[ch] - VSEARCHWIDTH);
int f2 = (int)(nomfreq[ch] + VSEARCHWIDTH);
if (evalpsk->sigpeak(ftest, f1, f2) > VSNTHRESHOLD) {
frequency[ch] = ftest;
sigsearch[ch] = 0;
}
else
frequency[ch] = nomfreq[ch];
freqerr[ch] = 0.0;
}
void viewpsk::afc(int ch)
@ -322,7 +302,7 @@ int viewpsk::rx_process(const double *buf, int len)
complex z[MAXCHANNELS];
now = time(NULL);
sigdensity();
// sigdensity();
while (len-- > 0) {
// process all CHANNELS (25)
@ -369,34 +349,10 @@ int viewpsk::rx_process(const double *buf, int len)
REQ( &viewclearchannel, channel);
timeout[channel] = -1;
}
// if (sigpwr[(int)(frequency[channel])] / sigmin < VSNTHRESHOLD)
if (sigpwr[(int)(frequency[channel])] / sigavg < VSNTHRESHOLD)
sigsearch[channel] = 1;
if (sigsearch[channel])
findsignal(channel);
/* if (sigsearch[channel])
findsignal(channel);
else {
if (waitcount[channel] > 0) {
--waitcount[channel];
if (waitcount[channel] == 0) {
// sigsearch[channel] = VSIGSEARCH;
sigsearch[channel] = 1;
}
}
else {
// double E1 = wf->powerDensity(frequency[channel], bandwidth);
// double E2 = wf->powerDensity(frequency[channel] - 2 * bandwidth, bandwidth/2) +
// wf->powerDensity(frequency[channel] + 2 * bandwidth, bandwidth/2);
// if ( E1/ E2 <= VSNTHRESHOLD) {
if (sigpwr[(int)(frequency[channel])] / sigavg < VSNTHRESHOLD) {
waitcount[channel] = VWAITCOUNT;
sigsearch[channel] = 0;
}
}
}
*/
}
return 0;
}

Wyświetl plik

@ -73,6 +73,11 @@ short int *sidata;
// is used asynchronously by the GUI thread.
mbuffer<double, SCBLOCKSIZE * 2, 2> _trx_scdbl;
#define HISTSIZE 1024 * SCBLOCKSIZE
double histbuff[HISTSIZE];
size_t numinbuff = 0;
bool bHistory = false;
static int dummy = 0;
static bool trxrunning = false;
#include "tune.cxx"
@ -117,9 +122,25 @@ void trx_trx_receive_loop()
if (numread == -1 || (trx_state != STATE_RX))
break;
if (numread > 0) {
REQ(&waterfall::sig_data, wf, _trx_scdbl.c_array(), numread);
active_modem->rx_process(_trx_scdbl, numread);
_trx_scdbl.next(); // change buffers
if (bHistory) {
active_modem->set_afcOnOff(0);
active_modem->rx_process( histbuff, numinbuff );
active_modem->set_afcOnOff(1);
bHistory = false;
}
active_modem->rx_process(_trx_scdbl, numread);
if (numinbuff + numread > HISTSIZE) {
memcpy( &histbuff[0], &histbuff[numread], (numinbuff - numread)*sizeof(double));
numinbuff -= numread;
}
for (int n = 0; n < numread; n++)
histbuff[numinbuff++] = _trx_scdbl[n];
REQ(&waterfall::sig_data, wf, _trx_scdbl.c_array(), numread);
_trx_scdbl.next(); // change buffers
}
}
if (!scard->full_duplex())

Wyświetl plik

@ -630,9 +630,11 @@ void WFdisp::update_waterfall() {
p4 = p3;
for (int col = 0; col < disp_width; col++) {
if (step == 4)
sig = MAX( MAX ( MAX ( *p2, *(p2+1) ), *(p2+2) ), *(p2+3) );
// sig = MAX( MAX ( MAX ( *p2, *(p2+1) ), *(p2+2) ), *(p2+3) );
sig = (*p2+ *(p2+1)+ *(p2+2)+ *(p2+3))/4;
else if (step == 2)
sig = MAX( *p2, *(p2 + 1) );
// sig = MAX( *p2, *(p2 + 1) );
sig = (*p2 + *(p2 + 1))/2;
else
sig = *p2;
*p4 = mag2RGBI[ sig ];
@ -1405,12 +1407,16 @@ int WFdisp::handle(int event)
}
// fall through
case FL_LEFT_MOUSE:
newcarrier = cursorFreq(xpos);
active_modem->set_freq(newcarrier);
if (!(Fl::event_state() & FL_SHIFT))
active_modem->set_sigsearch(SIGSEARCH);
redrawCursor();
restoreFocus();
if ((Fl::event_state() & FL_CTRL))
bHistory = true;
else {
newcarrier = cursorFreq(xpos);
active_modem->set_freq(newcarrier);
if (!(Fl::event_state() & FL_SHIFT))
active_modem->set_sigsearch(SIGSEARCH);
redrawCursor();
restoreFocus();
}
break;
case FL_MIDDLE_MOUSE:
if (event == FL_DRAG)